Repository: glotzerlab/signac-flow

Issue:
Error when running jobs using -f on command line
### Description

When I use `python project.py run -f ...` on the command line, flow errors internally.

### To reproduce

```python
import signac
from flow import FlowProject

from pathlib import Path

project = signac.get_project(Path(__file__).parent / "SignacProject")

job_sps = [{'a': 1, 'b': 2},
           {'a': 1, 'b': 3}]

for job_sp in job_sps:
    job = project.open_job(job_sp)
    job.init()


class SignacProject(FlowProject):
    pass


@SignacProject.operation
def print_statepoint(job):
    print(job.sp)


if __name__ == "__main__":
    SignacProject.get_project(project.path).main()
```

Try to run the only job on the command line with

```bash
python script.py run -f b 2
```

### Error output

```bash
$ python script.py run -f b 2
Using environment configuration: StandardEnvironment
Interpreted filter arguments as '{"b": 2}'.
Traceback (most recent call last):
  File "/Users/tomwalt/scripts/signac/flow-2.0-bug/script.py", line 26, in <module>
    SignacProject.get_project(project.path).main()
  File "/Users/tomwalt/miniconda3/envs/py310/lib/python3.10/site-packages/flow/project.py", line 5132, in main
    args.func(args)
  File "/Users/tomwalt/miniconda3/envs/py310/lib/python3.10/site-packages/flow/project.py", line 4820, in _main_run
    aggregates = self._select_jobs_from_args(args)
  File "/Users/tomwalt/miniconda3/envs/py310/lib/python3.10/site-packages/flow/project.py", line 4908, in _select_jobs_from_args
    return _JobAggregateCursor(self, filter_, doc_filter)
TypeError: _JobAggregateCursor.__init__() takes from 2 to 3 positional arguments but 4 were given
```

### System configuration

Please complete the following information:

 - Operating System [e.g. macOS]: macOS, linux
 - Version of Python [e.g. 3.7]: 3.10.10
 - Version of signac [e.g. 1.0]: 2.0.0
 - Version of signac-flow: 0.25.0



Discussion:
codecov[bot]: ## [Codecov](https://codecov.io/gh/glotzerlab/signac-flow/pull/738?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab) Report
> Merging [#738](https://codecov.io/gh/glotzerlab/signac-flow/pull/738?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab) (ad26207) into [main](https://codecov.io/gh/glotzerlab/signac-flow/commit/4590e4258942512d24b281d34a0205e1e5bf3c69?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab) (4590e42) will **decrease** coverage by `0.14%`.
> The diff coverage is `0.00%`.

```diff
@@            Coverage Diff             @@
##             main     #738      +/-   ##
==========================================
- Coverage   68.77%   68.64%   -0.14%     
==========================================
  Files          42       42              
  Lines        4196     4194       -2     
  Branches     1032      958      -74     
==========================================
- Hits         2886     2879       -7     
- Misses       1099     1104       +5     
  Partials      211      211              
```


| [Impacted Files](https://codecov.io/gh/glotzerlab/signac-flow/pull/738?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab) | Coverage Δ | |
|---|---|---|
| [flow/project.py](https://codecov.io/gh/glotzerlab/signac-flow/pull/738?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab#diff-Zmxvdy9wcm9qZWN0LnB5) | `82.46% <0.00%> (-0.35%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=glotzerlab)

bdice: I opened a PR to fix signac's changelog: https://github.com/glotzerlab/signac/pull/916
cbkerr: @bdice I added a test and confirmed that it fails without the change introduced by this PR

Patch:
diff --git a/changelog.txt b/changelog.txt
index a002f4d..1657aef 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -8,6 +8,19 @@ The numbers in brackets denote the related GitHub issue and/or pull request.
 Version 0.25
 ============
 
+[0.25.1] -- 2023-XX-XX
+----------------------
+
+Fixed
++++++
+
+- Fix filter argument (#737, #738).
+
+Removed
++++++++
+
+- ``--doc-filter`` argument (#738).
+
 [0.25.0] -- 2023-03-30
 ----------------------
 
diff --git a/flow/project.py b/flow/project.py
index 8fdd92f..8bd2970 100644
--- a/flow/project.py
+++ b/flow/project.py
@@ -4223,12 +4223,6 @@ class FlowProject(signac.Project, metaclass=_FlowProjectClass):
             nargs="+",
             help="Only select jobs that match the given state point filter.",
         )
-        parser.add_argument(
-            "--doc-filter",
-            type=str,
-            nargs="+",
-            help="Only select jobs that match the given document filter.",
-        )
 
     @classmethod
     def _add_operation_selection_arg_group(cls, parser):
@@ -4757,7 +4751,6 @@ class FlowProject(signac.Project, metaclass=_FlowProjectClass):
                 "debug",
                 "job_id",
                 "filter",
-                "doc_filter",
             ]
         }
         if args.pop("full"):
@@ -4876,14 +4869,10 @@ class FlowProject(signac.Project, metaclass=_FlowProjectClass):
             operation_function(*aggregate)
 
     def _select_jobs_from_args(self, args):
-        """Select jobs with the given command line arguments ('-j/-f/--doc-filter/--job-id')."""
-        if (
-            not args.func == self._main_exec
-            and args.job_id
-            and (args.filter or args.doc_filter)
-        ):
+        """Select jobs with the given command line arguments ('-j/-f/--job-id')."""
+        if not args.func == self._main_exec and args.job_id and (args.filter):
             raise ValueError(
-                "Cannot provide both -j/--job-id and -f/--filter or --doc-filter in combination."
+                "Cannot provide both -j/--job-id and -f/--filter in combination."
             )
 
         if args.job_id:
@@ -4900,12 +4889,11 @@ class FlowProject(signac.Project, metaclass=_FlowProjectClass):
         elif args.func == self._main_exec:
             # exec command does not support filters, so we must exit early.
             return _AggregateStoresCursor(self)
-        elif args.filter or args.doc_filter:
-            # filter or doc_filter provided. Filters can only be used to select
+        elif args.filter:
+            # filter, including doc_filter provided. Filters can only be used to select
             # single jobs and not aggregates of multiple jobs.
             filter_ = parse_filter_arg(args.filter)
-            doc_filter = parse_filter_arg(args.doc_filter)
-            return _JobAggregateCursor(self, filter_, doc_filter)
+            return _JobAggregateCursor(self, filter_)
         else:
             # Use all aggregates
             return _AggregateStoresCursor(self)


Test patch:
diff --git a/tests/test_project.py b/tests/test_project.py
index a8b9940..7d06273 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -1307,6 +1307,18 @@ class TestProjectMainInterface(TestProjectBase):
             else:
                 assert not job.isfile("world.txt")
 
+    def test_main_run_filter(self):
+        assert len(self.project)
+        for job in self.project:
+            assert not job.isfile("world.txt")
+        self.call_subcmd("run -o op1 -f b 2")
+        even_jobs = [job for job in self.project if job.sp.b == 2]
+        for job in self.project:
+            if job in even_jobs:
+                assert job.isfile("world.txt")
+            else:
+                assert not job.isfile("world.txt")
+
     def test_main_run_invalid_op(self):
         assert len(self.project)
         run_output = self.call_subcmd(