Skip to content

Commit cd62b38

Browse files
authored
Merge pull request #1123 from effigies/fix/ignore-dotfiles
fix: Ensure dotfiles are always filtered
2 parents 76b34b8 + 5e163a5 commit cd62b38

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

src/bids/layout/tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from os.path import join
2+
import shutil
23

34
import pytest
45

@@ -101,3 +102,10 @@ def layout_synthetic(tests_dir, request, db_dir):
101102
def layout_synthetic_nodb(tests_dir, request, db_dir):
102103
path = tests_dir / 'data' / 'synthetic'
103104
return BIDSLayout(path, derivatives=True)
105+
106+
107+
@pytest.fixture
108+
def temporary_dataset(tmp_path, tests_dir):
109+
path = tests_dir / 'data' / 'ds005'
110+
shutil.copytree(path, tmp_path / 'ds005')
111+
return tmp_path / 'ds005'

src/bids/layout/tests/test_layout.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,3 +1170,38 @@ def test_symlinks_in_path(tests_dir, tmp_path):
11701170
os.symlink(src_sub, link_sub)
11711171

11721172
assert "Subjects: 1 | Sessions: 2 | Runs: 2" in str(BIDSLayout(tmp_path / "7t_trt"))
1173+
1174+
1175+
def test_ignore_dotfiles(temporary_dataset):
1176+
arbitrary_dotfile = temporary_dataset / '.dotfile'
1177+
ds_store = temporary_dataset / 'sub-01' / '.DS_Store'
1178+
osx_companion_file = temporary_dataset / '._task-mixedgamblestask_bold.json'
1179+
1180+
arbitrary_dotfile.touch()
1181+
ds_store.touch()
1182+
osx_companion_file.touch()
1183+
1184+
# Default behavior
1185+
layout = BIDSLayout(temporary_dataset, validate=False)
1186+
assert str(temporary_dataset / 'dataset_description.json') in layout.files
1187+
assert str(arbitrary_dotfile) not in layout.files
1188+
assert str(ds_store) not in layout.files
1189+
assert str(osx_companion_file) not in layout.files
1190+
1191+
# Explicit ignores do not disable dotfile filtering
1192+
indexer = BIDSLayoutIndexer(ignore=['some_ignore'])
1193+
layout = BIDSLayout(temporary_dataset, validate=False, indexer=indexer)
1194+
assert str(temporary_dataset / 'dataset_description.json') in layout.files
1195+
assert str(arbitrary_dotfile) not in layout.files
1196+
assert str(ds_store) not in layout.files
1197+
assert str(osx_companion_file) not in layout.files
1198+
1199+
1200+
def test_empty_directory(temporary_dataset):
1201+
anat = temporary_dataset / 'sub-01' / 'anat'
1202+
shutil.rmtree(anat)
1203+
anat.mkdir()
1204+
1205+
layout = BIDSLayout(temporary_dataset)
1206+
1207+
assert layout.get(subject='01', datatype='anat') == []

src/bids/layout/validation.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232

3333
DEFAULT_LOCATIONS_TO_IGNORE = {
3434
re.compile(r"^/(code|models|sourcedata|stimuli)"),
35-
re.compile(r'/\.'),
3635
}
3736

37+
ALWAYS_IGNORE = (
38+
re.compile(r'/\.'), # dotfiles should never be indexed
39+
)
40+
3841
def absolute_path_deprecation_warning():
3942
warnings.warn("The absolute_paths argument will be removed from PyBIDS "
4043
"in 0.14. You can easily access the relative path of "
@@ -156,9 +159,11 @@ def _sort_patterns(patterns, root):
156159

157160
def validate_indexing_args(ignore, force_index, root):
158161
if ignore is None:
159-
ignore = list(
160-
DEFAULT_LOCATIONS_TO_IGNORE - set(force_index or [])
161-
)
162+
ignore = DEFAULT_LOCATIONS_TO_IGNORE - set(force_index or [])
163+
164+
ignore = list(ignore)
165+
166+
ignore.extend(ALWAYS_IGNORE)
162167

163168
# root has already been validated to be a directory
164169
ignore = _sort_patterns(ignore, root)

0 commit comments

Comments
 (0)