diff --git a/src/bids_validator/context.py b/src/bids_validator/context.py index 7b940a1..2427a59 100644 --- a/src/bids_validator/context.py +++ b/src/bids_validator/context.py @@ -219,8 +219,8 @@ def walk_back( yield file_group elif len(file_group) == 1: yield file_group[0] - else: - raise ValidationError('Multiple matching files.') + elif file_group: + raise ValidationError(f'Multiple matching files: {file_group}') def _walk_back( @@ -230,7 +230,7 @@ def _walk_back( target_suffix: str | None, target_entities: tuple[str, ...], ) -> Generator[list[FileTree, ...]]: - file_parts = FileParts.from_file(source.relative_path) + file_parts = FileParts.from_file(source) if target_suffix is None: target_suffix = file_parts.suffix @@ -238,11 +238,11 @@ def _walk_back( tree = source.parent while tree: matches = [] - for child in tree.children: + for child in tree.children.values(): if child.is_dir: continue - parts = FileParts.from_file(child.relative_path) - if parts.extension != target_extensions: + parts = FileParts.from_file(child) + if parts.extension not in target_extensions: continue if parts.suffix != target_suffix: continue @@ -270,7 +270,7 @@ class FileParts: extension: str | None @classmethod - def from_file(cls, file: FileTree, schema: Namespace) -> t.Self: + def from_file(cls, file: FileTree, schema: Namespace | None = None) -> t.Self: """Parse file parts from FileTree object.""" stem, _, extension = file.name.partition('.') @@ -280,7 +280,7 @@ def from_file(cls, file: FileTree, schema: Namespace) -> t.Self: extension = f'{extension}/' datatype = None - if file.parent: + if file.parent and schema: if any(file.parent.name == dtype.value for dtype in schema.objects.datatypes.values()): datatype = file.parent.name diff --git a/tests/test_context.py b/tests/test_context.py index 0cc6c45..234f393 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -1,37 +1,35 @@ +import pytest + from bids_validator import context from bids_validator.types.files import FileTree -import pytest -def test_load(examples, schema): - tree = FileTree.read_from_filesystem(examples / 'synthetic') - ds = context.Dataset(tree, schema) +@pytest.fixture +def synthetic_dataset(examples): + return FileTree.read_from_filesystem(examples / 'synthetic') + + +def test_load(synthetic_dataset, schema): + ds = context.Dataset(synthetic_dataset, schema) assert ds.dataset_description.Name.startswith('Synthetic dataset') assert ds.subjects.participant_id == [f'sub-{i:02d}' for i in range(1, 6)] assert sorted(ds.subjects.sub_dirs) == [f'sub-{i:02d}' for i in range(1, 6)] - assert sorted(ds.datatypes) == ["anat", "beh", "func"] - assert sorted(ds.modalities) == ["beh", "mri"] - - -@pytest.mark.parametrize( - "depth, expected", - [ - (2, {"anat", "beh", "func"}), - (1, set()) - ]) -def test_find_datatypes(examples, schema, depth, expected): - tree = FileTree.read_from_filesystem(examples / 'synthetic') + assert sorted(ds.datatypes) == ['anat', 'beh', 'func'] + assert sorted(ds.modalities) == ['beh', 'mri'] + + +@pytest.mark.parametrize(('depth', 'expected'), [(2, {'anat', 'beh', 'func'}), (1, set())]) +def test_find_datatypes(synthetic_dataset, schema, depth, expected): datatypes = schema.objects.datatypes - result = context.find_datatypes(tree, datatypes, max_depth=depth) + result = context.find_datatypes(synthetic_dataset, datatypes, max_depth=depth) assert result == expected -def test_fileparts(examples, schema): - tree = FileTree.read_from_filesystem(examples / 'synthetic') - T1w = tree / 'sub-01' / 'ses-01' / 'anat' / 'sub-01_ses-01_T1w.nii' +def test_fileparts(synthetic_dataset, schema): + T1w = synthetic_dataset / 'sub-01' / 'ses-01' / 'anat' / 'sub-01_ses-01_T1w.nii' parts = context.FileParts.from_file(T1w, schema) assert parts == context.FileParts( path='/sub-01/ses-01/anat/sub-01_ses-01_T1w.nii', @@ -41,3 +39,16 @@ def test_fileparts(examples, schema): suffix='T1w', extension='.nii', ) + + +def test_walkback(synthetic_dataset, schema): + bold = ( + synthetic_dataset + / 'sub-01' + / 'ses-01' + / 'func' + / 'sub-01_ses-01_task-nback_run-01_bold.nii' + ) + sidecars = list(context.walk_back(bold, inherit=True)) + assert len(sidecars) == 1 + assert sidecars[0] is synthetic_dataset / 'task-nback_bold.json'