Skip to content

Commit

Permalink
Update documentation with new filter syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
pvandyken committed Jul 13, 2024
1 parent 8c1ac55 commit 2d4da35
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 12 deletions.
1 change: 1 addition & 0 deletions snakebids/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"CliConfig",
"ComponentEdit",
"FilterParse",
"FilterParseError",
"InvalidBidsError",
"Pybidsdb",
"SnakemakeBidsApp",
Expand Down
2 changes: 2 additions & 0 deletions snakebids/plugins/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ from .cli_config import (
from .component_edit import (
ComponentEdit,
FilterParse,
FilterParseError,
)
from .pybidsdb import (
Pybidsdb,
Expand All @@ -29,6 +30,7 @@ __all__ = [
"CliConfig",
"ComponentEdit",
"FilterParse",
"FilterParseError",
"InvalidBidsError",
"Pybidsdb",
"SnakemakeBidsApp",
Expand Down
29 changes: 24 additions & 5 deletions snakebids/plugins/component_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from snakebids import bidsapp
from snakebids.plugins.base import PluginBase
from snakebids.types import OptionalFilter
from snakebids.utils.utils import text_fold


class FilterParseError(Exception):
Expand Down Expand Up @@ -111,6 +112,16 @@ class ComponentEdit(PluginBase):
arguments are read and used to update the original component specification within
config.
Filters are specified on the CLI using ``ENTITY[:METHOD][=VALUE]``, as follows:
1. ``ENTITY=VALUE`` selects paths based on an exact value match.
2. ``ENTITY:match=REGEX`` and ``ENTITY:search=REGEX`` selects paths using regex
with :func:`re.match` and :func:`re.search` respectively. This syntax can be used
to select multiple values (e.g. ``'session:match=01|02'``).
3. ``ENTITY:required`` selects all paths with the entity, regardless of value.
4. ``ENTITY:none`` selects all paths without the entity.
5. ``ENTITY:any`` removes filters for the entity.
CLI arguments created by this plugin cannot be overriden.
Parameters
Expand Down Expand Up @@ -139,9 +150,17 @@ def add_cli_arguments(
# create filter parsers, one for each input_type
filter_opts = parser.add_argument_group(
"BIDS FILTERS",
"Filters to customize PyBIDS get() as key=value pairs, or as "
"key:{REQUIRED|OPTIONAL|NONE} (case-insensitive), to enforce the presence "
"or absence of values for that key.",
text_fold(
"""
Update filters for input components. Each filter can be specified as a
ENTITY=VALUE pair to select an value directly. To use regex filtering,
ENTITY:match=REGEX or ENTITY:search=REGEX can be used for re.match() or
re.search() respectively. Regex can also be used to select multiple
values, e.g. 'session:match=01|02'. ENTITY:required and ENTITY:none can
be used to require or prohibit presence of an entity in selected paths,
respectively. ENTITY:optional can be used to remove a filter.
"""
),
)

for input_type in pybids_inputs:
Expand All @@ -155,7 +174,7 @@ def add_cli_arguments(
nargs="+",
action=FilterParse,
dest=f"{self.PREFIX}.filter.{input_type}",
metavar="ENTITY=VALUE",
metavar="ENTITY[:METHOD][=VALUE]",
help=f"(default: {' '.join(arglist_default)})",
)

Expand All @@ -164,7 +183,7 @@ def add_cli_arguments(
# create wildcards parsers, one for each input_type
wildcards_opts = parser.add_argument_group(
"INPUT WILDCARDS",
"File path entities to use as wildcards in snakemake",
"Provide entities to be used as wildcards.",
)

for input_type in pybids_inputs:
Expand Down
10 changes: 3 additions & 7 deletions snakebids/tests/test_plugins/test_component_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,7 @@ def test_filter_with_invalid_spec(

with pytest.raises(
FilterParseError,
match=re.compile(
rf"':{re.escape(flag.lower())}' is not a valid filter method"
),
match=re.compile(r"is not a valid filter method"),
):
p.parse_args(argv)

Expand All @@ -207,7 +205,7 @@ def test_filter_with_missing_value_errors(

with pytest.raises(
FilterParseError,
match=re.compile(rf"':{re.escape(flag.lower())}' requires a value"),
match=re.compile(rf"':{flag}' requires a value"),
):
p.parse_args(argv)

Expand All @@ -230,9 +228,7 @@ def test_boolean_filter_with_value_errors(

with pytest.raises(
FilterParseError,
match=re.compile(
rf"'entity:{re.escape(flag.lower())}' should not be given a value"
),
match=re.compile(rf"'entity:{flag}' should not be given a value"),
):
p.parse_args(argv)

Expand Down

0 comments on commit 2d4da35

Please sign in to comment.