diff --git a/.gitignore b/.gitignore index a640d9edf..e57c413af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ historical/ -# # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -86,6 +85,9 @@ celerybeat-schedule venv/ ENV/ +# Pipenv +Pipfile + # Spyder project settings .spyderproject diff --git a/bids/layout/config/bids.json b/bids/layout/config/bids.json index 44f6b636f..fbd669802 100644 --- a/bids/layout/config/bids.json +++ b/bids/layout/config/bids.json @@ -12,6 +12,10 @@ "mandatory": false, "directory": "{subject}{session}" }, + { + "name": "sample", + "pattern": "[_/\\\\]+sample-([a-zA-Z0-9]+)" + }, { "name": "task", "pattern": "[_/\\\\]+task-([a-zA-Z0-9]+)" @@ -24,6 +28,14 @@ "name": "ceagent", "pattern": "[_/\\\\]+ce-([a-zA-Z0-9]+)" }, + { + "name": "staining", + "pattern": "[_/\\\\]+stain-([a-zA-Z0-9]+)" + }, + { + "name": "tracer", + "pattern": "[_/\\\\]+trc-([a-zA-Z0-9]+)" + }, { "name": "reconstruction", "pattern": "[_/\\\\]+rec-([a-zA-Z0-9]+)" @@ -73,6 +85,10 @@ "name": "space", "pattern": "[_/\\\\]+space-([a-zA-Z0-9]+)" }, + { + "name": "chunk", + "pattern": "[_/\\\\]+chunk-([0-9]+)" + }, { "name": "suffix", "pattern": "[._]*([a-zA-Z0-9]*?)\\.[^/\\\\]+$" @@ -87,7 +103,7 @@ }, { "name": "datatype", - "pattern": "[/\\\\]+(anat|beh|dwi|eeg|fmap|func|ieeg|meg|perf)[/\\\\]+" + "pattern": "[/\\\\]+(anat|beh|dwi|eeg|fmap|func|ieeg|meg|micr|perf|pet)[/\\\\]+" }, { "name": "extension", @@ -98,8 +114,8 @@ "default_path_patterns": [ "sub-{subject}[/ses-{session}]/{datatype|anat}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_part-{part}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", "sub-{subject}[/ses-{session}]/{datatype|anat}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_mod-{modality}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", - "sub-{subject}[/ses-{session}]/{datatype|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_part-{part}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", - "sub-{subject}[/ses-{session}]/{datatype|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_dir-{direction}][_run-{run}][_echo-{echo}][_part-{part}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|func}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_dir-{direction}][_run-{run}][_echo-{echo}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", "sub-{subject}[/ses-{session}]/{datatype|dwi}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_part-{part}]_{suffix}{extension<.bval|.bvec|.json|.nii.gz|.nii>|.nii.gz}", "sub-{subject}[/ses-{session}]/{datatype|fmap}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_dir-{direction}][_run-{run}]_{fmap}{extension<.nii|.nii.gz|.json>|.nii.gz}", "sub-{subject}[/ses-{session}]/{datatype|fmap}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}]_dir-{direction}[_run-{run}]_{fmap}{extension<.nii|.nii.gz|.json>|.nii.gz}", @@ -109,6 +125,23 @@ "sub-{subject}[/ses-{session}]/{datatype|meg}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_run-{run}][_proc-{proc}]_{suffix}{extension<.tsv|.json>|.tsv}", "sub-{subject}[/ses-{session}]/{datatype|meg}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}]_{suffix}{extension<.json>|.json}", "sub-{subject}[/ses-{session}]/{datatype|meg}/sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}]_{suffix}{extension<.jpg>|.jpg}", + "sub-{subject}[/ses-{session}]/{datatype|micr}/sub-{subject}[_ses-{session}]_sample-{sample}[_acq-{acquisition}][_stain-{stain}][_run-{run}][_chunk-{chunk}]_{suffix}{extension<.png|.tif|.ome.tif|.ome.btf|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|micr}/sub-{subject}[_ses-{session}]_sample-{sample}[_acq-{acquisition}]_{suffix|photo}{extension<.jpg|.png|.tif|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_echo-{echo}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_flip-{flip}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_inv-{inv}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_flip-{flip}]_inv-{inv}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_flip-{flip}_mt-{on|off}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_mt-{on|off}[_part-{}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|anat}|anat/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|pet}/sub-{subject}[_ses-{session}][_task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|pet}/sub-{subject}[_ses-{session}][_task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}]_recording-{recording}_{suffix}{extension<.tsv|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|pet}/sub-{subject}[_ses-{session}]_task-{task}[trc-{tracer}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.tsv|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|pet}/sub-{subject}[_ses-{session}][_task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}][_recording-{recording}]_{suffix}{extension<.tsv.gz|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|perf}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}]_{suffix}{extension<.nii|.nii.gz|.json>|.nii.gz}", + "sub-{subject}[/ses-{session}]/{datatype|perf}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}]_{suffix}{extension<.tsv|.json>}", + "sub-{subject}[/ses-{session}]/{datatype|perf}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.jpg>}", + "sub-{subject}[/ses-{session}]/{datatype|perf}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}][_recording{recording}]_{suffix}{extension<.tsv|.json>}", "[acq-{acquisition}_][ce-{ceagent}_][rec-{reconstruction}_]{suffix}{extension<.json>|.json}", "[acq-{acquisition}_][ce-{ceagent}_][rec-{reconstruction}_][mod-{modality}_]{suffix}{extension<.json>|.json}", "task-{task}[_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_{suffix}{extension<.json>|.json}", @@ -116,6 +149,21 @@ "[acq-{acquisition}_][dir-{direction}_][run-{run}_]{fmap}{extension<.json>|.json}", "[acq-{acquisition}_][ce-{ceagent}_]dir-{direction}[_run-{run}]_{fmap}{extension<.json>|.json}", "task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix}{extension<.json>|.json}", - "task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix}{extension<.json>}" + "task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix}{extension<.json>}", + "sample-{sample}[_acq-{acquisition}][_stain-{stain}][_run-{run}][_chunk-{chunk}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_echo-{echo}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_flip-{flip}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_inv-{inv}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_flip-{flip}]_inv-{inv}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_echo-{echo}]_flip-{flip}_mt-{on|off}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_mt-{on|off}[_part-{}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.json>|.json}", + "[task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.json>|.json}", + "[task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}]_recording-{recording}_{suffix}{extension<.json>|.json}", + "task-{task}[trc-{tracer}][_rec-{reconstruction}][_run-{run}]_{suffix}{extension<.json>|.json}", + "[task-{task}][trc-{tracer}][_rec-{reconstruction}][_run-{run}][_recording-{recording}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}]_{suffix}{extension<.json>|.json}", + "[acq-{acquisition}][_rec-{reconstruction}][_dir{direction}][_run-{run}][_recording{recording}]_{suffix}{extension<.json>|.json}" ] } diff --git a/bids/layout/tests/test_layout_on_examples.py b/bids/layout/tests/test_layout_on_examples.py new file mode 100644 index 000000000..aa217fb95 --- /dev/null +++ b/bids/layout/tests/test_layout_on_examples.py @@ -0,0 +1,87 @@ +""" Tests runs layout on bids examples and make sure all files are caught""" + +""" TODO +- add more 'vanilla' datasets +- missing files in micr? +""" + +from os.path import join + +import pytest + +from bids.layout import BIDSLayout + +# Values for the number of file got from a: +# +# find ds_name -type f | wc -l +# + +@pytest.mark.parametrize( + "dataset, nb_files", + [ + ("qmri_irt1", 15), + ("qmri_mese", 73), + ("qmri_mp2rage", 14), + ("qmri_mp2rageme", 28), + ("qmri_mtsat", 23), + ("qmri_sa2rage", 9), + ("qmri_vfa", 17), + ], +) +def test_layout_on_examples_with_derivatives(dataset, nb_files, bids_examples): + ds = join(bids_examples, dataset) + layout = BIDSLayout(ds, derivatives=True) + files = layout.get() + assert len(files) == nb_files + + +@pytest.mark.parametrize( + "dataset, nb_files", + [ + ("micr_SEM", 12), + ("micr_SPIM", 22), + ("asl001", 8), + ("asl002", 10), + ("asl003", 10), + ("asl004", 12), + ("asl005", 10), + ("pet001", 12), + ("pet002", 20), + ("pet003", 9), + ("pet004", 10), + ("pet005", 14), + ("qmri_megre", 18), + ("qmri_tb1tfl", 6), + ], +) +def test_layout_on_examples_no_derivatives(dataset, nb_files, bids_examples): + ds = join(bids_examples, dataset) + layout = BIDSLayout(ds) + files = layout.get() + assert len(files) == nb_files + + +@pytest.mark.parametrize( + "dataset, nb_files", + [ + pytest.param( + "qmri_qsm", + 8, + marks=pytest.mark.xfail(strict=True, + reason="https://github.com/bids-standard/bids-examples/issues/311" + ), + ), + pytest.param( + "qmri_mpm", + 125, + marks=pytest.mark.xfail(strict=True, + reason="https://github.com/bids-standard/bids-examples/issues/310" + ), + ), + ], +) +def test_layout_on_examples_invalid_ds_description(dataset, nb_files, bids_examples): + ds = join(bids_examples, dataset) + layout = BIDSLayout(ds, derivatives=True) + files = layout.get() + assert len(files) == nb_files