Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: Match only within relative path when indexer is validating #859

Merged
merged 8 commits into from
Jul 22, 2022
22 changes: 14 additions & 8 deletions bids/layout/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,22 @@ def _extract_entities(bidsfile, entities):
return match_vals


def _check_path_matches_patterns(path, patterns):
def _check_path_matches_patterns(path, patterns, root=None):
"""Check if the path matches at least one of the provided patterns. """
if not patterns:
return False

path = path.absolute()
if root is not None:
path = Path("/") / path.relative_to(root)

# Path now can be downcast to str
path = str(path)
for patt in patterns:
if isinstance(patt, Path):
if path == patt:
if isinstance(patt, (str, Path)):
if str(patt) in path:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@effigies I hope I did not misinterpreted these two lines.

Here is the string matching pattern:

  1. Shouldn't we allow strings, not just Paths?
  2. Shouldn't we just check the presence of the substring, rather than the exact match?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, the changes were much more involved - probably this doesn't have much relevance now.

return True
elif patt.search(str(path)):
elif patt.search(path):
return True
return False

Expand Down Expand Up @@ -115,17 +121,17 @@ def session(self):
return self._layout.connection_manager.session

def _validate_dir(self, d, default=None):
if _check_path_matches_patterns(d, self._include_patterns):
if _check_path_matches_patterns(d, self._include_patterns, root=self._layout._root):
return True
if _check_path_matches_patterns(d, self._exclude_patterns):
if _check_path_matches_patterns(d, self._exclude_patterns, root=self._layout._root):
return False
return default

def _validate_file(self, f, default=None):
# Inclusion takes priority over exclusion
if _check_path_matches_patterns(f, self._include_patterns):
if _check_path_matches_patterns(f, self._include_patterns, root=self._layout._root):
return True
if _check_path_matches_patterns(f, self._exclude_patterns):
if _check_path_matches_patterns(f, self._exclude_patterns, root=self._layout._root):
return False

# If inclusion/exclusion is inherited from a parent directory, that
Expand Down
32 changes: 31 additions & 1 deletion bids/layout/tests/test_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from bids.layout import BIDSLayout, Query
from bids.layout.models import Config
from bids.layout.index import BIDSLayoutIndexer
from bids.layout.index import BIDSLayoutIndexer, _check_path_matches_patterns
from bids.layout.utils import PaddedInt
from bids.tests import get_test_data_path
from bids.utils import natural_sort
Expand Down Expand Up @@ -835,3 +835,33 @@ def test_padded_run_roundtrip(layout_ds005):
assert ents["run"] == 1
newpath = layout_ds005.build_path(ents, absolute_paths=False)
assert newpath == "sub-01/func/sub-01_task-mixedgamblestask_run-01_bold.nii.gz"

@pytest.mark.parametrize(
"fname", [
"sub-01/anat/sub-01_T1w.nii.gz",
".datalad",
"code",
"sub-01/.datalad",
],
)
def test_indexer_patterns(fname):
root = Path("/home/user/.cache/data/")
path = root / fname

assert _check_path_matches_patterns(
path,
["code"],
root=None,
) is (fname == "code")

assert _check_path_matches_patterns(
path,
[re.compile(r"/\.")],
root=None,
) is True

assert _check_path_matches_patterns(
path,
[re.compile(r"/\.")],
root=root,
) is (".datalad" in fname)