Repository: bids-standard/pybids
Pull request #799 (2021-11-30 18:21:13)

FIX: Accept paths/strings for layout configuration files
Replaces #791.


Patch:
diff --git a/bids/layout/layout.py b/bids/layout/layout.py
index 1088cf2d..fcae1791 100644
--- a/bids/layout/layout.py
+++ b/bids/layout/layout.py
@@ -54,7 +54,7 @@ class BIDSLayout(object):
         directories).
     derivatives : bool or str or list, optional
         Specifies whether and/or which
-        derivatives to index. If True, all pipelines found in the
+        derivatives to to index. If True, all pipelines found in the
         derivatives/ subdirectory will be indexed. If a str or list, gives
         the paths to one or more derivatives directories to index. If False
         or None, the derivatives/ directory is ignored during indexing, and
diff --git a/bids/layout/models.py b/bids/layout/models.py
index 2508ef2a..bf0ca674 100644
--- a/bids/layout/models.py
+++ b/bids/layout/models.py
@@ -59,6 +59,9 @@ class LayoutInfo(Base):
         if 'root' in kwargs:
             kwargs['root'] = str(Path(kwargs['root']).absolute())
 
+        if isinstance(kwargs.get('config'), os.PathLike):
+            kwargs['config'] = str(Path(kwargs['config']).absolute())
+
         # Get abspaths
         if kwargs.get('derivatives') not in (None, True, False):
             kwargs['derivatives'] = [
@@ -141,7 +144,7 @@ class Config(Base):
         A Config instance.
         """
 
-        if isinstance(config, str):
+        if isinstance(config, (str, Path)):
             config_paths = get_option('config_paths')
             if config in config_paths:
                 config = config_paths[config]


Test patch:
diff --git a/bids/layout/tests/test_layout.py b/bids/layout/tests/test_layout.py
index f00828db..be4ee4ec 100644
--- a/bids/layout/tests/test_layout.py
+++ b/bids/layout/tests/test_layout.py
@@ -48,6 +48,17 @@ def test_index_metadata(index_metadata, query, result, mock_config):
     assert metadata.get('RepetitionTime') == result
 
 
+
+@pytest.mark.parametrize('config_type', [str, Path])
+def test_config_filename(config_type):
+    data_path = Path(get_test_data_path())
+    # Use custom config that replaces session with oligarchy
+    config_path = data_path.parent / 'bids_specs_with_oligarchy.json'
+    layout = BIDSLayout(data_path / "7t_trt", config=config_type(config_path))
+    # Validate that we are using the desired configuration
+    assert 'oligarchy' in layout.get_entities()
+
+
 def test_layout_repr(layout_7t_trt):
     assert "Subjects: 10 | Sessions: 20 | Runs: 20" in str(layout_7t_trt)
 
diff --git a/bids/tests/bids_specs_with_oligarchy.json b/bids/tests/bids_specs_with_oligarchy.json
new file mode 100644
index 00000000..e2cb8a6c
--- /dev/null
+++ b/bids/tests/bids_specs_with_oligarchy.json
@@ -0,0 +1,104 @@
+{
+    "name": "bids",
+    "entities": [
+        {
+            "name": "subject",
+            "pattern": "[/\\\\]+sub-([a-zA-Z0-9]+)",
+            "directory": "{subject}"
+        },
+        {
+            "name": "oligarchy",
+            "pattern": "[_/\\\\]+ses-([a-zA-Z0-9]+)",
+            "mandatory": false,
+            "directory": "{subject}{oligarchy}"
+        },
+        {
+            "name": "task",
+            "pattern": "[_/\\\\]+task-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "acquisition",
+            "pattern": "[_/\\\\]+acq-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "ceagent",
+            "pattern": "[_/\\\\]+ce-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "reconstruction",
+            "pattern": "[_/\\\\]+rec-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "direction",
+            "pattern": "[_/\\\\]+dir-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "run",
+            "pattern": "[_/\\\\]+run-0*(\\d+)",
+            "dtype": "int"
+        },
+        {
+            "name": "proc",
+            "pattern": "[_/\\\\]+proc-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "modality",
+            "pattern": "[_/\\\\]+mod-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "echo",
+            "pattern": "[_/\\\\]+echo-([0-9]+)"
+        },
+        {
+            "name": "recording",
+            "pattern": "[_/\\\\]+recording-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "space",
+            "pattern": "[_/\\\\]+space-([a-zA-Z0-9]+)"
+        },
+        {
+            "name": "suffix",
+            "pattern": "[._]*([a-zA-Z0-9]*?)\\.[^/\\\\]+$"
+        },
+        {
+            "name": "scans",
+            "pattern": "(.*\\_scans.tsv)$"
+        },
+        {
+            "name": "fmap",
+            "pattern": "(phasediff|magnitude[1-2]|phase[1-2]|fieldmap|epi)\\.nii"
+        },
+        {
+            "name": "datatype",
+            "pattern": "[/\\\\]+(func|anat|fmap|dwi|meg|eeg)[/\\\\]+"
+        },
+        {
+            "name": "extension",
+            "pattern": "[._]*[a-zA-Z0-9]*?(\\.[^/\\\\]+)$"
+        }
+    ],
+
+    "default_path_patterns": [
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<anat>|anat}/sub-{subject}[_ses-{oligarchy}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}]_{suffix<T1w|T2w|T1rho|T1map|T2map|T2star|FLAIR|FLASH|PDmap|PD|PDT2|inplaneT[12]|angio|MTS>}{extension<.nii|.nii.gz|.json>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<anat>|anat}/sub-{subject}[_ses-{oligarchy}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_mod-{modality}]_{suffix<defacemask>}{extension<.nii|.nii.gz|.json>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<func>|func}/sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_{suffix<bold|cbv|phase|sbref>}{extension<.nii|.nii.gz|.json>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<dwi>|dwi}/sub-{subject}[_ses-{oligarchy}][_acq-{acquisition}]_{suffix<dwi>}{extension<.bval|.bvec|.json|.nii.gz|.nii>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<fmap>|fmap}/sub-{subject}[_ses-{oligarchy}][_acq-{acquisition}][_dir-{direction}][_run-{run}]_{fmap<phasediff|magnitude[12]|phase[12]|fieldmap>}{extension<.nii|.nii.gz|.json>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<fmap>|fmap}/sub-{subject}[_ses-{oligarchy}][_acq-{acquisition}][_ce-{ceagent}]_dir-{direction}[_run-{run}]_{fmap<epi>}{extension<.nii|.nii.gz|.json>|.nii.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/[{datatype<func|meg|beh>|func}/]sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<events>}{extension<.tsv|.json>|.tsv}",
+        "sub-{subject}[/ses-{oligarchy}]/[{datatype<func|beh>|func}/]sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<physio|stim>}{extension<.tsv.gz|.json>|.tsv.gz}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<meg>|meg}/sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}][_run-{run}][_proc-{proc}]_{suffix<meg>}{extension}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<meg>|meg}/sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}][_run-{run}][_proc-{proc}]_{suffix<channels>}{extension<.tsv|.json>|.tsv}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<meg>|meg}/sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}]_{suffix<coordsystem>}{extension<.json>|.json}",
+        "sub-{subject}[/ses-{oligarchy}]/{datatype<meg>|meg}/sub-{subject}[_ses-{oligarchy}]_task-{task}[_acq-{acquisition}]_{suffix<photo>}{extension<.jpg>|.jpg}",
+        "[acq-{acquisition}_][ce-{ceagent}_][rec-{reconstruction}_]{suffix<T1w|T2w|T1rho|T1map|T2map|T2star|FLAIR|FLASH|PDmap|PD|PDT2|inplaneT[12]|angio|MTS>}{extension<.json>|.json}",
+        "[acq-{acquisition}_][ce-{ceagent}_][rec-{reconstruction}_][mod-{modality}_]{suffix<defacemask>}{extension<.json>|.json}",
+        "task-{task}[_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_{suffix<bold|cbv|phase|sbref>}{extension<.json>|.json}",
+        "[acq-{acquisition}_]{suffix<dwi>}{extension<.json>|.json}",
+        "[acq-{acquisition}_][dir-{direction}_][run-{run}_]{fmap<phasediff|magnitude[1-2]|phase[1-2]|fieldmap>}{extension<.json>|.json}",
+        "[acq-{acquisition}_][ce-{ceagent}_]dir-{direction}[_run-{run}]_{fmap<epi>}{extension<.json>|.json}",
+        "task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<events>}{extension<.json>|.json}",
+        "task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<physio|stim>}{extension<.json>}"
+    ]
+}