From 46906b88e4d372dc13dcb3224c43deb54eb272d2 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Wed, 18 Jun 2025 14:54:24 -0400 Subject: [PATCH 1/8] feat(schema): Add meta.templates --- src/metaschema.json | 3 + src/schema/README.md | 21 +- src/schema/meta/templates.yaml | 108 ++++ src/schema/rules/files/deriv/imaging.yaml | 354 +++++-------- .../rules/files/deriv/preprocessed_data.yaml | 496 ++++++++---------- src/schema/rules/files/raw/anat.yaml | 30 +- src/schema/rules/files/raw/beh.yaml | 3 +- src/schema/rules/files/raw/channels.yaml | 12 +- src/schema/rules/files/raw/dwi.yaml | 6 +- src/schema/rules/files/raw/eeg.yaml | 3 +- src/schema/rules/files/raw/events.yaml | 6 +- src/schema/rules/files/raw/fmap.yaml | 21 +- src/schema/rules/files/raw/func.yaml | 6 +- src/schema/rules/files/raw/ieeg.yaml | 3 +- src/schema/rules/files/raw/meg.yaml | 15 +- src/schema/rules/files/raw/micr.yaml | 3 +- src/schema/rules/files/raw/motion.yaml | 3 +- src/schema/rules/files/raw/nirs.yaml | 3 +- src/schema/rules/files/raw/perf.yaml | 9 +- src/schema/rules/files/raw/pet.yaml | 6 +- src/schema/rules/files/raw/photo.yaml | 3 +- src/schema/rules/files/raw/task.yaml | 9 +- .../schemacode/src/bidsschematools/schema.py | 26 +- 23 files changed, 544 insertions(+), 605 deletions(-) create mode 100644 src/schema/meta/templates.yaml diff --git a/src/metaschema.json b/src/metaschema.json index e5d4c7b400..49d0f8cab7 100644 --- a/src/metaschema.json +++ b/src/metaschema.json @@ -71,6 +71,9 @@ "additionalProperties": false } }, + "templates": { + "type": "object" + }, "versions": { "type": "array", "items": { diff --git a/src/schema/README.md b/src/schema/README.md index 3505ea1b04..4d53a38c74 100644 --- a/src/schema/README.md +++ b/src/schema/README.md @@ -167,21 +167,23 @@ references (the cases in which they are used will be presented later): (which are in turn references to individual values), and the references inside `GeneticLevel.anyOf` indicate that there may be a single such value or a list of values. -1. In [`rules.files.deriv.preprocessed_data`][preprocessed_data]: +1. In [`rules.files.deriv.imaging`](./rules/files/deriv/imaging.yaml): ```YAML - anat_nonparametric_common: - $ref: rules.files.raw.anat.nonparametric + anat_parametric_volumetric: + $ref: rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.parametric.entities ``` Here, the derivative datatype rule starts by copying the raw datatype rule `rules.files.raw.anat.nonparametric`. It then *overrides* the `entities` portion of that rule with a new object. - To *extend* the original `entities`, it again begins - by referencing `rules.files.raw.anat.nonparametric.entities`, - and adding the new entities `space` and `description`. + To *extend* the original `entities`, it composes + `meta.templates.deriv.volumetric.entities` + and `rules.files.raw.anat.nonparametric.entities`. + When multiple references are aggregated, the first reference takes + precedence. ### Expressions @@ -1071,5 +1073,4 @@ ensuring consistency across the entire schema directory. Validation of the schem incorporated into the CI, so any changes that are inconsistent will be flagged before inclusion. -[preprocessed_data]: https://github.com/bids-standard/bids-specification/tree/master/src/schema/rules/files/deriv/preprocessed_data.yaml [tabular files]: https://bids-specification.readthedocs.io/en/stable/common-principles.html#tabular-files diff --git a/src/schema/meta/templates.yaml b/src/schema/meta/templates.yaml new file mode 100644 index 0000000000..781d21faaf --- /dev/null +++ b/src/schema/meta/templates.yaml @@ -0,0 +1,108 @@ +--- +# This section is unstructured, for inclusion in rules by reference + +# Entities that apply to most raw files +# Include thus: +# +# filerule: +# entities: +# $ref: meta.templates.raw.base.entities +# task: optional +# ... +# datatypes: +# ... +raw: + base: + entities: + subject: required + session: optional + +# Entities that apply to most derivative files +# Include thus: +# +# filerule: +# entities: +# $ref: meta.templates.deriv.base.entities +# task: optional +# ... +# datatypes: +# ... +deriv: + base: + selectors: + - dataset.dataset_description.DatasetType == 'derivative' + entities: + subject: optional + session: optional + description: optional + + spatial: + $ref: meta.templates.deriv.base + entities: + $ref: meta.templates.deriv.base.entities + space: optional + + # Imaging derivatives + volumetric: + $ref: meta.templates.deriv.spatial + extensions: + - .nii.gz + - .nii + - .json + entities: + $ref: meta.templates.deriv.spatial.entities + resolution: optional + + surface: + $ref: meta.templates.deriv.spatial + entities: + $ref: meta.templates.deriv.spatial.entities + hemisphere: optional + density: optional + + mask: + $ref: meta.templates.deriv.volumetric + suffixes: + - mask + entities: + $ref: meta.templates.deriv.volumetric.entities + label: optional + + dseg: + $ref: meta.templates.deriv.volumetric + extensions: + - .nii.gz + - .nii + - .tsv + - .json + suffixes: + - dseg + entities: + $ref: meta.templates.deriv.volumetric.entities + segmentation: optional + + probseg: + $ref: meta.templates.deriv.volumetric + extensions: + - .nii.gz + - .nii + - .json + suffixes: + - probseg + entities: + $ref: meta.templates.deriv.volumetric.entities + segmentation: optional + label: optional + + dseg_surface: + $ref: meta.templates.deriv.surface + extensions: + - .label.gii + - .dlabel.nii + - .tsv + - .json + suffixes: + - dseg + entities: + $ref: meta.templates.deriv.surface.entities + segmentation: optional diff --git a/src/schema/rules/files/deriv/imaging.yaml b/src/schema/rules/files/deriv/imaging.yaml index 819654b4e5..2d50202c96 100644 --- a/src/schema/rules/files/deriv/imaging.yaml +++ b/src/schema/rules/files/deriv/imaging.yaml @@ -1,280 +1,180 @@ --- anat_parametric_volumetric: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.parametric.entities - space: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.parametric.entities anat_nonparametric_volumetric: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.nonparametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.nonparametric.entities -dwi_volumetric: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.dwi +dwi_dwi_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.dwi.dwi entities: - $ref: rules.files.raw.dwi.dwi.entities - space: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.dwi.dwi.entities + +dwi_sbref_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.dwi.sbref + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.dwi.sbref.entities dwi_scannerderivatives: - $ref: rules.files.raw.dwi.ScannerDerivatives + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.dwi.ScannerDerivatives entities: - $ref: rules.files.raw.dwi.ScannerDerivatives.entities - space: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.dwi.ScannerDerivatives.entities func_volumetric: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.func + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.func.func + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.func.func.entities + +func_phase_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.func.phase entities: - $ref: rules.files.raw.func.func.entities - space: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.func.phase.entities anat_parametric_mask: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric - suffixes: - - mask + $ref: + - meta.templates.deriv.mask + - rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.parametric.entities - space: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.mask.entities + - rules.files.raw.anat.parametric.entities anat_nonparametric_mask: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric - suffixes: - - mask + $ref: + - meta.templates.deriv.mask + - rules.files.raw.anat.nonparametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.mask.entities + - rules.files.raw.anat.nonparametric.entities dwi_mask: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.dwi - suffixes: - - mask - extensions: - - .nii.gz - - .nii - - .json + $ref: + - meta.templates.deriv.mask + - rules.files.raw.dwi.dwi entities: - $ref: rules.files.raw.dwi.dwi.entities - space: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.mask.entities + - rules.files.raw.dwi.dwi.entities func_mask: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.func - suffixes: - - mask + $ref: + - meta.templates.deriv.mask + - rules.files.raw.func.func entities: - $ref: rules.files.raw.func.func.entities - space: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.mask.entities + - rules.files.raw.func.func.entities anat_parametric_discrete_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric - suffixes: - - dseg + $ref: + - meta.templates.deriv.dseg + - rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.parametric.entities - space: optional - segmentation: optional - resolution: optional - description: optional - extensions: - - .nii.gz - - .nii - - .json - - .tsv + $ref: + - meta.templates.deriv.dseg.entities + - rules.files.raw.anat.parametric.entities anat_nonparametric_discrete_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric - suffixes: - - dseg + $ref: + - meta.templates.deriv.dseg + - rules.files.raw.anat.nonparametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - segmentation: optional - resolution: optional - description: optional - extensions: - - .nii.gz - - .nii - - .json - - .tsv + $ref: + - meta.templates.deriv.dseg.entities + - rules.files.raw.anat.nonparametric.entities func_discrete_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.func - suffixes: - - dseg + $ref: + - meta.templates.deriv.dseg + - rules.files.raw.func.func entities: - $ref: rules.files.raw.func.func.entities - space: optional - segmentation: optional - resolution: optional - description: optional - extensions: - - .nii.gz - - .nii - - .json - - .tsv + $ref: + - meta.templates.deriv.dseg.entities + - rules.files.raw.func.func.entities dwi_discrete_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.dwi - suffixes: - - dseg + $ref: + - meta.templates.deriv.dseg + - rules.files.raw.dwi.dwi entities: - $ref: rules.files.raw.dwi.dwi.entities - space: optional - resolution: optional - description: optional - extensions: - - .nii.gz - - .nii - - .json - - .tsv + $ref: + - meta.templates.deriv.dseg.entities + - rules.files.raw.dwi.dwi.entities anat_parametric_probabilistic_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric - suffixes: - - probseg + $ref: + - meta.templates.deriv.probseg + - rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.parametric.entities - space: optional - segmentation: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.probseg.entities + - rules.files.raw.anat.parametric.entities anat_nonparametric_probabilistic_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric - suffixes: - - probseg + $ref: + - meta.templates.deriv.probseg + - rules.files.raw.anat.nonparametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - segmentation: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.probseg.entities + - rules.files.raw.anat.nonparametric.entities func_probabilistic_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.func - suffixes: - - probseg + $ref: + - meta.templates.deriv.probseg + - rules.files.raw.func.func entities: - $ref: rules.files.raw.func.func.entities - space: optional - segmentation: optional - resolution: optional - label: optional - description: optional + $ref: + - meta.templates.deriv.probseg.entities + - rules.files.raw.func.func.entities dwi_probabilistic_segmentation: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.dwi - suffixes: - - probseg + $ref: + - meta.templates.deriv.probseg + - rules.files.raw.dwi.dwi entities: - $ref: rules.files.raw.dwi.dwi.entities - space: optional - segmentation: optional - resolution: optional - label: optional - description: optional - extensions: - - .nii.gz - - .nii - - .json + $ref: + - meta.templates.deriv.probseg.entities + - rules.files.raw.dwi.dwi.entities anat_parametric_discrete_surface: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric - suffixes: - - dseg - extensions: - - .label.gii - - .dlabel.nii - - .json - - .tsv - entities: - $ref: rules.files.raw.anat.parametric.entities - hemisphere: optional - space: optional - segmentation: optional - resolution: optional - density: optional - description: optional - -anat_nonparametric_discrete_surface: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric - suffixes: - - dseg - extensions: - - .label.gii - - .dlabel.nii - - .json - - .tsv + $ref: + - meta.templates.deriv.dseg_surface + - rules.files.raw.anat.parametric entities: - $ref: rules.files.raw.anat.nonparametric.entities - hemisphere: optional - space: optional - segmentation: optional - resolution: optional - density: optional - description: optional + $ref: + - meta.templates.deriv.dseg_surface.entities + - rules.files.raw.anat.parametric.entities diff --git a/src/schema/rules/files/deriv/preprocessed_data.yaml b/src/schema/rules/files/deriv/preprocessed_data.yaml index 48ca1bccc6..d359be44fd 100644 --- a/src/schema/rules/files/deriv/preprocessed_data.yaml +++ b/src/schema/rules/files/deriv/preprocessed_data.yaml @@ -1,378 +1,338 @@ +# This document implements the common derivatives specification, +# generally adding space and description entities to most raw data. +# +# Imaging files are omitted when it is redundant with the rules in +# imaging.yaml --- -anat_nonparametric_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.nonparametric - entities: - $ref: rules.files.raw.anat.nonparametric.entities - space: optional - description: optional - -anat_parametric_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.parametric - entities: - $ref: rules.files.raw.anat.parametric.entities - space: optional - description: optional - anat_defacemask_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.defacemask + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.defacemask entities: - $ref: rules.files.raw.anat.defacemask.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.defacemask.entities anat_megre_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.megre + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.megre entities: - $ref: rules.files.raw.anat.megre.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.megre.entities anat_mese_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.mese + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.mese entities: - $ref: rules.files.raw.anat.mese.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.mese.entities anat_multiflip_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.multiflip + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.multiflip entities: - $ref: rules.files.raw.anat.multiflip.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.multiflip.entities anat_multiinversion_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.multiinversion + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.multiinversion entities: - $ref: rules.files.raw.anat.multiinversion.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.multiinversion.entities anat_mp2rage_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.mp2rage + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.mp2rage entities: - $ref: rules.files.raw.anat.mp2rage.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.mp2rage.entities anat_vfamt_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.vfamt + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.vfamt entities: - $ref: rules.files.raw.anat.vfamt.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.vfamt.entities anat_mtr_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.anat.mtr + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.anat.mtr entities: - $ref: rules.files.raw.anat.mtr.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.anat.mtr.entities beh_noncontinuous_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.beh.noncontinuous + $ref: + - meta.templates.deriv.base + - rules.files.raw.beh.noncontinuous entities: - $ref: rules.files.raw.beh.noncontinuous.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.beh.noncontinuous.entities channels_channels_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.channels + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.channels entities: - $ref: rules.files.raw.channels.channels.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.channels.entities channels_channels__meg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.channels__meg + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.channels__meg entities: - $ref: rules.files.raw.channels.channels__meg.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.channels__meg.entities channels_channels__motion_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.channels__motion + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.channels__motion entities: - $ref: rules.files.raw.channels.channels__motion.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.channels__motion.entities channels_coordsystem_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.coordsystem + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.coordsystem entities: - $ref: rules.files.raw.channels.coordsystem.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.coordsystem.entities channels_coordsystem__eeg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.coordsystem__eeg + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.coordsystem__eeg entities: - $ref: rules.files.raw.channels.coordsystem__eeg.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.coordsystem__eeg.entities channels_electrodes_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.electrodes + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.electrodes entities: - $ref: rules.files.raw.channels.electrodes.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.electrodes.entities channels_electrodes__meg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.electrodes__meg - entities: - $ref: rules.files.raw.channels.electrodes__meg.entities - description: optional - -channels_electrodes_optodes_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.channels.optodes + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.electrodes__meg entities: - $ref: rules.files.raw.channels.optodes.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.electrodes__meg.entities -dwi_dwi_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.dwi +channels_optodes_common: + $ref: + - meta.templates.deriv.base + - rules.files.raw.channels.optodes entities: - $ref: rules.files.raw.dwi.dwi.entities - space: optional - description: optional - -dwi_sbref_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.dwi.sbref - entities: - $ref: rules.files.raw.dwi.sbref.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.channels.optodes.entities eeg_eeg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.eeg.eeg + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.eeg.eeg entities: - $ref: rules.files.raw.eeg.eeg.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.eeg.eeg.entities fmap_fieldmaps_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.fieldmaps + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.fieldmaps entities: - $ref: rules.files.raw.fmap.fieldmaps.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.fieldmaps.entities fmap_pepolar_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.pepolar + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.pepolar entities: - $ref: rules.files.raw.fmap.pepolar.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.pepolar.entities fmap_pepolar_m0scan: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.pepolar_m0scan + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.pepolar_m0scan entities: - $ref: rules.files.raw.fmap.pepolar.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.pepolar.entities fmap_TB1DAM_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.TB1DAM + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.TB1DAM entities: - $ref: rules.files.raw.fmap.TB1DAM.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.TB1DAM.entities fmap_TB1EPI_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.TB1EPI + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.TB1EPI entities: - $ref: rules.files.raw.fmap.TB1EPI.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.TB1EPI.entities fmap_RFFieldMaps_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.RFFieldMaps + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.RFFieldMaps entities: - $ref: rules.files.raw.fmap.RFFieldMaps.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.RFFieldMaps.entities fmap_TB1SRGE_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.TB1SRGE + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.TB1SRGE entities: - $ref: rules.files.raw.fmap.TB1SRGE.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.TB1SRGE.entities fmap_parametric_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.fmap.parametric - entities: - $ref: rules.files.raw.fmap.parametric.entities - space: optional - description: optional - -func_func_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.func - entities: - $ref: rules.files.raw.func.func.entities - space: optional - description: optional - -func_phase_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.func.phase + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.fmap.parametric entities: - $ref: rules.files.raw.func.phase.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.fmap.parametric.entities ieeg_ieeg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.ieeg.ieeg + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.ieeg.ieeg entities: - $ref: rules.files.raw.ieeg.ieeg.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.ieeg.ieeg.entities meg_meg_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.meg.meg + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.meg.meg entities: - $ref: rules.files.raw.meg.meg.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.meg.meg.entities meg_calibration_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.meg.calibration + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.meg.calibration entities: - $ref: rules.files.raw.meg.calibration.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.meg.calibration.entities meg_crosstalk_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.meg.crosstalk + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.meg.crosstalk entities: - $ref: rules.files.raw.meg.crosstalk.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.meg.crosstalk.entities meg_headshape_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.meg.headshape + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.meg.headshape entities: - $ref: rules.files.raw.meg.headshape.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.meg.headshape.entities meg_markers_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.meg.markers + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.meg.markers entities: - $ref: rules.files.raw.meg.markers.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.meg.markers.entities micr_microscopy_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.micr.microscopy + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.micr.microscopy entities: - $ref: rules.files.raw.micr.microscopy.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.micr.microscopy.entities perf_asl_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.perf.asl + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.perf.asl entities: - $ref: rules.files.raw.perf.asl.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.perf.asl.entities pet_pet_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.pet.pet + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.pet.pet entities: - $ref: rules.files.raw.pet.pet.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.pet.pet.entities pet_blood_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.pet.blood + $ref: + - meta.templates.deriv.spatial + - rules.files.raw.pet.blood entities: - $ref: rules.files.raw.pet.blood.entities - space: optional - description: optional + $ref: + - meta.templates.deriv.spatial.entities + - rules.files.raw.pet.blood.entities task_events_common: - selectors: - - dataset.dataset_description.DatasetType == 'derivative' - $ref: rules.files.raw.events.events + $ref: + - meta.templates.deriv.base + - rules.files.raw.events.events entities: - $ref: rules.files.raw.events.events.entities - description: optional + $ref: + - meta.templates.deriv.base.entities + - rules.files.raw.events.events.entities diff --git a/src/schema/rules/files/raw/anat.yaml b/src/schema/rules/files/raw/anat.yaml index d1b83f17d9..78e3749715 100644 --- a/src/schema/rules/files/raw/anat.yaml +++ b/src/schema/rules/files/raw/anat.yaml @@ -20,8 +20,7 @@ nonparametric: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -56,8 +55,7 @@ parametric: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -75,8 +73,7 @@ defacemask: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -95,8 +92,7 @@ megre: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -116,8 +112,7 @@ mese: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -138,8 +133,7 @@ multiflip: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -160,8 +154,7 @@ multiinversion: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -181,8 +174,7 @@ mp2rage: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -205,8 +197,7 @@ vfamt: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional @@ -228,8 +219,7 @@ mtr: datatypes: - anat entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional ceagent: optional diff --git a/src/schema/rules/files/raw/beh.yaml b/src/schema/rules/files/raw/beh.yaml index 6193015295..d22a81c33d 100644 --- a/src/schema/rules/files/raw/beh.yaml +++ b/src/schema/rules/files/raw/beh.yaml @@ -9,8 +9,7 @@ noncontinuous: datatypes: - beh entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional diff --git a/src/schema/rules/files/raw/channels.yaml b/src/schema/rules/files/raw/channels.yaml index 6a4358c689..da362d9a7c 100644 --- a/src/schema/rules/files/raw/channels.yaml +++ b/src/schema/rules/files/raw/channels.yaml @@ -10,8 +10,7 @@ channels: - ieeg - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional @@ -43,8 +42,7 @@ coordsystem: - meg - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional @@ -68,8 +66,7 @@ electrodes: - eeg - ieeg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional run: optional @@ -93,6 +90,5 @@ optodes: datatypes: - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional diff --git a/src/schema/rules/files/raw/dwi.yaml b/src/schema/rules/files/raw/dwi.yaml index 91319046dc..4a5f158720 100644 --- a/src/schema/rules/files/raw/dwi.yaml +++ b/src/schema/rules/files/raw/dwi.yaml @@ -11,8 +11,7 @@ dwi: datatypes: - dwi entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional reconstruction: optional direction: optional @@ -30,8 +29,7 @@ sbref: datatypes: - dwi entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional reconstruction: optional direction: optional diff --git a/src/schema/rules/files/raw/eeg.yaml b/src/schema/rules/files/raw/eeg.yaml index 676d66dc1b..47b40ce69d 100644 --- a/src/schema/rules/files/raw/eeg.yaml +++ b/src/schema/rules/files/raw/eeg.yaml @@ -14,8 +14,7 @@ eeg: datatypes: - eeg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional diff --git a/src/schema/rules/files/raw/events.yaml b/src/schema/rules/files/raw/events.yaml index 7800b946df..8fa9f9106f 100644 --- a/src/schema/rules/files/raw/events.yaml +++ b/src/schema/rules/files/raw/events.yaml @@ -12,8 +12,7 @@ events: - meg - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional @@ -45,8 +44,7 @@ events__pet: - pet entities: # Most events allow acquisition, PET doesn't - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required tracer: optional reconstruction: optional diff --git a/src/schema/rules/files/raw/fmap.yaml b/src/schema/rules/files/raw/fmap.yaml index 79d5944feb..2aea616bab 100644 --- a/src/schema/rules/files/raw/fmap.yaml +++ b/src/schema/rules/files/raw/fmap.yaml @@ -15,8 +15,7 @@ fieldmaps: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional run: optional chunk: optional @@ -52,8 +51,7 @@ pepolar_m0scan: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional direction: required @@ -71,8 +69,7 @@ TB1DAM: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional reconstruction: optional @@ -92,8 +89,7 @@ TB1EPI: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional reconstruction: optional @@ -117,8 +113,7 @@ RFFieldMaps: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional reconstruction: optional @@ -139,8 +134,7 @@ TB1SRGE: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional reconstruction: optional @@ -162,8 +156,7 @@ parametric: datatypes: - fmap entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional ceagent: optional reconstruction: optional diff --git a/src/schema/rules/files/raw/func.yaml b/src/schema/rules/files/raw/func.yaml index 61a614bead..41b7919b50 100644 --- a/src/schema/rules/files/raw/func.yaml +++ b/src/schema/rules/files/raw/func.yaml @@ -11,8 +11,7 @@ func: datatypes: - func entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional ceagent: optional @@ -41,8 +40,7 @@ phase: datatypes: - func entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional ceagent: optional diff --git a/src/schema/rules/files/raw/ieeg.yaml b/src/schema/rules/files/raw/ieeg.yaml index 587f9bcbb8..6bd2ba2a79 100644 --- a/src/schema/rules/files/raw/ieeg.yaml +++ b/src/schema/rules/files/raw/ieeg.yaml @@ -15,8 +15,7 @@ ieeg: datatypes: - ieeg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional diff --git a/src/schema/rules/files/raw/meg.yaml b/src/schema/rules/files/raw/meg.yaml index a25ed56646..ef9a97f1fd 100644 --- a/src/schema/rules/files/raw/meg.yaml +++ b/src/schema/rules/files/raw/meg.yaml @@ -19,8 +19,7 @@ meg: datatypes: - meg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional @@ -35,8 +34,7 @@ calibration: datatypes: - meg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: level: required enum: @@ -50,8 +48,7 @@ crosstalk: datatypes: - meg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: level: required enum: @@ -66,8 +63,7 @@ headshape: datatypes: - meg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional markers: @@ -79,8 +75,7 @@ markers: datatypes: - meg entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional acquisition: optional space: optional diff --git a/src/schema/rules/files/raw/micr.yaml b/src/schema/rules/files/raw/micr.yaml index b256033ce9..c978ee2fcd 100644 --- a/src/schema/rules/files/raw/micr.yaml +++ b/src/schema/rules/files/raw/micr.yaml @@ -29,8 +29,7 @@ microscopy: datatypes: - micr entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities sample: required acquisition: optional stain: optional diff --git a/src/schema/rules/files/raw/motion.yaml b/src/schema/rules/files/raw/motion.yaml index 5ac18a4e92..267d052b20 100644 --- a/src/schema/rules/files/raw/motion.yaml +++ b/src/schema/rules/files/raw/motion.yaml @@ -8,8 +8,7 @@ motion: datatypes: - motion entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required tracksys: required acquisition: optional diff --git a/src/schema/rules/files/raw/nirs.yaml b/src/schema/rules/files/raw/nirs.yaml index 8dfc41e861..c5c2d8b8b0 100644 --- a/src/schema/rules/files/raw/nirs.yaml +++ b/src/schema/rules/files/raw/nirs.yaml @@ -8,8 +8,7 @@ nirs: datatypes: - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional diff --git a/src/schema/rules/files/raw/perf.yaml b/src/schema/rules/files/raw/perf.yaml index c725bef442..f5eb62f823 100644 --- a/src/schema/rules/files/raw/perf.yaml +++ b/src/schema/rules/files/raw/perf.yaml @@ -10,8 +10,7 @@ asl: datatypes: - perf entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional reconstruction: optional direction: optional @@ -27,8 +26,7 @@ aslcontext: datatypes: - perf entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional reconstruction: optional direction: optional @@ -44,8 +42,7 @@ asllabeling: datatypes: - perf entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional reconstruction: optional run: optional diff --git a/src/schema/rules/files/raw/pet.yaml b/src/schema/rules/files/raw/pet.yaml index a94cb9addd..50d393761c 100644 --- a/src/schema/rules/files/raw/pet.yaml +++ b/src/schema/rules/files/raw/pet.yaml @@ -9,8 +9,7 @@ pet: datatypes: - pet entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional tracer: optional reconstruction: optional @@ -25,8 +24,7 @@ blood: datatypes: - pet entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: optional tracer: optional reconstruction: optional diff --git a/src/schema/rules/files/raw/photo.yaml b/src/schema/rules/files/raw/photo.yaml index f5969e2d0c..65706b02d8 100644 --- a/src/schema/rules/files/raw/photo.yaml +++ b/src/schema/rules/files/raw/photo.yaml @@ -12,8 +12,7 @@ photo: - meg - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional photo__micr: diff --git a/src/schema/rules/files/raw/task.yaml b/src/schema/rules/files/raw/task.yaml index 8a207a7384..5d86564bf0 100644 --- a/src/schema/rules/files/raw/task.yaml +++ b/src/schema/rules/files/raw/task.yaml @@ -12,8 +12,7 @@ timeseries: - ieeg - nirs entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required acquisition: optional run: optional @@ -30,8 +29,7 @@ timeseries__mri_no_task: - dwi - perf entities: - subject: required - session: optional + $ref: meta.templates.raw.base.entities acquisition: optional run: optional reconstruction: optional @@ -86,8 +84,7 @@ timeseries__pet: - pet entities: # Most timeseries allow acquisition, PET doesn't - subject: required - session: optional + $ref: meta.templates.raw.base.entities task: required tracer: optional reconstruction: optional diff --git a/tools/schemacode/src/bidsschematools/schema.py b/tools/schemacode/src/bidsschematools/schema.py index ca36e2668b..1f53c08f0d 100644 --- a/tools/schemacode/src/bidsschematools/schema.py +++ b/tools/schemacode/src/bidsschematools/schema.py @@ -5,6 +5,7 @@ import json import os import re +from collections import ChainMap from collections.abc import Iterable, Mapping from copy import deepcopy from functools import cache, lru_cache @@ -94,13 +95,26 @@ def _dereference(namespace, base_schema): # A dependency graph could be constructed, but would likely be slower # to build than to duplicate a couple dereferences for struct in _find(namespace, lambda obj: "$ref" in obj): - target = base_schema.get(struct["$ref"]) - if target is None: - raise ValueError(f"Reference {struct['$ref']} not found in schema.") - if isinstance(target, Mapping): + refs = struct["$ref"] + if isinstance(refs, str): + refs = [refs] + targets = [] + for ref in refs: + target = base_schema.get(ref) + if target is None: + raise ValueError(f"Reference {ref} not found in schema.") + targets.append(target) + if all(isinstance(target, Mapping) for target in targets): struct.pop("$ref") - _dereference(target, base_schema) - struct.update({**target, **struct}) + + combined_target = dict(ChainMap(*targets)) + _dereference(combined_target, base_schema) + struct.update({**combined_target, **struct}) + + # Use `key: null` to delete fields + for key, value in list(struct.items()): + if value is None: + del struct[key] @cache From 745a573a738b725ebc2c4397095a78be783b9587 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Wed, 18 Jun 2025 16:25:59 -0400 Subject: [PATCH 2/8] fix(test): Replace removed schema location --- .../src/bidsschematools/tests/test_schema.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/schemacode/src/bidsschematools/tests/test_schema.py b/tools/schemacode/src/bidsschematools/tests/test_schema.py index 3ee2430fe4..0663cec898 100644 --- a/tools/schemacode/src/bidsschematools/tests/test_schema.py +++ b/tools/schemacode/src/bidsschematools/tests/test_schema.py @@ -412,18 +412,18 @@ def test_valid_schema_with_check_jsonschema(tmp_path, regex_variant): def test_add_legal_field(): """Test that adding a legal field does not raise an error.""" namespace = schema.load_schema() - namespace["rules"]["files"]["deriv"]["preprocessed_data"]["anat_nonparametric_common"][ - "entities" - ]["density"] = "optional" + namespace["rules"]["files"]["deriv"]["imaging"]["anat_nonparametric_volumetric"]["entities"][ + "density" + ] = "optional" schema.validate_schema(namespace) def test_invalid_value(): """Test that an invalid value raises an error.""" namespace = schema.load_schema() - namespace["rules"]["files"]["deriv"]["preprocessed_data"]["anat_nonparametric_common"][ - "entities" - ]["density"] = "invalid" + namespace["rules"]["files"]["deriv"]["imaging"]["anat_nonparametric_volumetric"]["entities"][ + "density" + ] = "invalid" with pytest.raises(ValidationError) as e: schema.validate_schema(namespace) print(e.value) From 2a8cdd7e61f62a71b2c6f8d69d5514bb00a9a46d Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Thu, 19 Jun 2025 06:55:39 -0400 Subject: [PATCH 3/8] feat(schema): Move more imaging data into imaging.yaml --- src/schema/rules/files/deriv/imaging.yaml | 169 ++++++++++++++++++ .../rules/files/deriv/preprocessed_data.yaml | 165 +---------------- 2 files changed, 170 insertions(+), 164 deletions(-) diff --git a/src/schema/rules/files/deriv/imaging.yaml b/src/schema/rules/files/deriv/imaging.yaml index 2d50202c96..18662ad6e3 100644 --- a/src/schema/rules/files/deriv/imaging.yaml +++ b/src/schema/rules/files/deriv/imaging.yaml @@ -1,4 +1,9 @@ +# This document implements general imaging derivatives. +# +# The _volumetric rules cover supersets of files that would be covered by the +# common derivatives spec, namely, the space and description entities. --- +# Preprocessed and/or resampled volumes anat_parametric_volumetric: $ref: - meta.templates.deriv.volumetric @@ -17,6 +22,78 @@ anat_nonparametric_volumetric: - meta.templates.deriv.volumetric.entities - rules.files.raw.anat.nonparametric.entities +anat_defacemask_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.defacemask + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.defacemask.entities + +anat_mese_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.mese + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.mese.entities + +anat_megre_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.megre + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.megre.entities + +anat_multiflip_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.multiflip + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.multiflip.entities + +anat_multiinversion_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.multiinversion + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.multiinversion.entities + +anat_mp2rage_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.mp2rage + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.mp2rage.entities + +anat_vfamt_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.vfamt + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.vfamt.entities + +anat_mtr_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.anat.mtr + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.anat.mtr.entities + dwi_dwi_volumetric: $ref: - meta.templates.deriv.volumetric @@ -62,6 +139,97 @@ func_phase_volumetric: - meta.templates.deriv.volumetric.entities - rules.files.raw.func.phase.entities +fmap_fieldmaps_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.fieldmaps + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.fieldmaps.entities + +fmap_pepolar_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.pepolar + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.pepolar.entities + +fmap_pepolar_m0scan: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.pepolar_m0scan + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.pepolar.entities + +fmap_TB1DAM_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.TB1DAM + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.TB1DAM.entities + +fmap_TB1EPI_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.TB1EPI + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.TB1EPI.entities + +fmap_RFFieldMaps_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.RFFieldMaps + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.RFFieldMaps.entities + +fmap_TB1SRGE_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.TB1SRGE + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.TB1SRGE.entities + +fmap_parametric_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.fmap.parametric + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.fmap.parametric.entities + +perf_asl_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.perf.asl + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.perf.asl.entities + +pet_pet_volumetric: + $ref: + - meta.templates.deriv.volumetric + - rules.files.raw.pet.pet + entities: + $ref: + - meta.templates.deriv.volumetric.entities + - rules.files.raw.pet.pet.entities + +# Masks anat_parametric_mask: $ref: - meta.templates.deriv.mask @@ -98,6 +266,7 @@ func_mask: - meta.templates.deriv.mask.entities - rules.files.raw.func.func.entities +# Discrete and probabilistic segmentations anat_parametric_discrete_segmentation: $ref: - meta.templates.deriv.dseg diff --git a/src/schema/rules/files/deriv/preprocessed_data.yaml b/src/schema/rules/files/deriv/preprocessed_data.yaml index d359be44fd..0a1029b348 100644 --- a/src/schema/rules/files/deriv/preprocessed_data.yaml +++ b/src/schema/rules/files/deriv/preprocessed_data.yaml @@ -1,81 +1,8 @@ # This document implements the common derivatives specification, # generally adding space and description entities to most raw data. # -# Imaging files are omitted when it is redundant with the rules in -# imaging.yaml +# Imaging files are generally omitted, due to redundancy with imaging.yaml --- -anat_defacemask_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.defacemask - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.defacemask.entities - -anat_megre_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.megre - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.megre.entities - -anat_mese_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.mese - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.mese.entities - -anat_multiflip_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.multiflip - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.multiflip.entities - -anat_multiinversion_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.multiinversion - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.multiinversion.entities - -anat_mp2rage_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.mp2rage - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.mp2rage.entities - -anat_vfamt_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.vfamt - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.vfamt.entities - -anat_mtr_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.anat.mtr - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.anat.mtr.entities - beh_noncontinuous_common: $ref: - meta.templates.deriv.base @@ -166,78 +93,6 @@ eeg_eeg_common: - meta.templates.deriv.spatial.entities - rules.files.raw.eeg.eeg.entities -fmap_fieldmaps_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.fieldmaps - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.fieldmaps.entities - -fmap_pepolar_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.pepolar - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.pepolar.entities - -fmap_pepolar_m0scan: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.pepolar_m0scan - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.pepolar.entities - -fmap_TB1DAM_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.TB1DAM - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.TB1DAM.entities - -fmap_TB1EPI_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.TB1EPI - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.TB1EPI.entities - -fmap_RFFieldMaps_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.RFFieldMaps - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.RFFieldMaps.entities - -fmap_TB1SRGE_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.TB1SRGE - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.TB1SRGE.entities - -fmap_parametric_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.fmap.parametric - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.fmap.parametric.entities - ieeg_ieeg_common: $ref: - meta.templates.deriv.spatial @@ -301,24 +156,6 @@ micr_microscopy_common: - meta.templates.deriv.spatial.entities - rules.files.raw.micr.microscopy.entities -perf_asl_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.perf.asl - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.perf.asl.entities - -pet_pet_common: - $ref: - - meta.templates.deriv.spatial - - rules.files.raw.pet.pet - entities: - $ref: - - meta.templates.deriv.spatial.entities - - rules.files.raw.pet.pet.entities - pet_blood_common: $ref: - meta.templates.deriv.spatial From 0f699c47e1829275c3203a1ded65cdd43aba1fd1 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Thu, 19 Jun 2025 06:59:13 -0400 Subject: [PATCH 4/8] feat(schema): Remove redundant anatomical derivative rules --- src/schema/rules/files/deriv/imaging.yaml | 44 ++++++----------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/src/schema/rules/files/deriv/imaging.yaml b/src/schema/rules/files/deriv/imaging.yaml index 18662ad6e3..d2ce8a451d 100644 --- a/src/schema/rules/files/deriv/imaging.yaml +++ b/src/schema/rules/files/deriv/imaging.yaml @@ -230,20 +230,13 @@ pet_pet_volumetric: - rules.files.raw.pet.pet.entities # Masks -anat_parametric_mask: - $ref: - - meta.templates.deriv.mask - - rules.files.raw.anat.parametric - entities: - $ref: - - meta.templates.deriv.mask.entities - - rules.files.raw.anat.parametric.entities - -anat_nonparametric_mask: +anat_mask: $ref: - meta.templates.deriv.mask - rules.files.raw.anat.nonparametric entities: + # The nonparametric entities are a superset of parametric entities, + # so no need to duplicate. $ref: - meta.templates.deriv.mask.entities - rules.files.raw.anat.nonparametric.entities @@ -267,20 +260,12 @@ func_mask: - rules.files.raw.func.func.entities # Discrete and probabilistic segmentations -anat_parametric_discrete_segmentation: - $ref: - - meta.templates.deriv.dseg - - rules.files.raw.anat.parametric - entities: - $ref: - - meta.templates.deriv.dseg.entities - - rules.files.raw.anat.parametric.entities - -anat_nonparametric_discrete_segmentation: +anat_discrete_segmentation: $ref: - meta.templates.deriv.dseg - rules.files.raw.anat.nonparametric entities: + # ibid $ref: - meta.templates.deriv.dseg.entities - rules.files.raw.anat.nonparametric.entities @@ -303,20 +288,12 @@ dwi_discrete_segmentation: - meta.templates.deriv.dseg.entities - rules.files.raw.dwi.dwi.entities -anat_parametric_probabilistic_segmentation: - $ref: - - meta.templates.deriv.probseg - - rules.files.raw.anat.parametric - entities: - $ref: - - meta.templates.deriv.probseg.entities - - rules.files.raw.anat.parametric.entities - -anat_nonparametric_probabilistic_segmentation: +anat_probabilistic_segmentation: $ref: - meta.templates.deriv.probseg - rules.files.raw.anat.nonparametric entities: + # ibid $ref: - meta.templates.deriv.probseg.entities - rules.files.raw.anat.nonparametric.entities @@ -339,11 +316,12 @@ dwi_probabilistic_segmentation: - meta.templates.deriv.probseg.entities - rules.files.raw.dwi.dwi.entities -anat_parametric_discrete_surface: +anat_discrete_surface: $ref: - meta.templates.deriv.dseg_surface - - rules.files.raw.anat.parametric + - rules.files.raw.anat.nonparametric entities: + # ibid $ref: - meta.templates.deriv.dseg_surface.entities - - rules.files.raw.anat.parametric.entities + - rules.files.raw.anat.nonparametric.entities From ae3747fb47e6d5ec1548feb372ecb66ec42ce848 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Thu, 19 Jun 2025 14:37:07 -0400 Subject: [PATCH 5/8] feat(schema): Expand use of raw templates --- src/schema/meta/templates.yaml | 24 ++++++++ src/schema/rules/files/raw/anat.yaml | 70 ++++-------------------- src/schema/rules/files/raw/beh.yaml | 6 +- src/schema/rules/files/raw/channels.yaml | 10 +--- src/schema/rules/files/raw/dwi.yaml | 31 ++++------- src/schema/rules/files/raw/eeg.yaml | 6 +- src/schema/rules/files/raw/events.yaml | 13 ++--- src/schema/rules/files/raw/fmap.yaml | 59 +++----------------- src/schema/rules/files/raw/func.yaml | 30 ++-------- src/schema/rules/files/raw/ieeg.yaml | 6 +- src/schema/rules/files/raw/meg.yaml | 5 +- src/schema/rules/files/raw/micr.yaml | 4 +- src/schema/rules/files/raw/motion.yaml | 5 +- src/schema/rules/files/raw/mrs.yaml | 5 +- src/schema/rules/files/raw/nirs.yaml | 6 +- src/schema/rules/files/raw/perf.yaml | 22 +++----- src/schema/rules/files/raw/task.yaml | 24 +++----- 17 files changed, 88 insertions(+), 238 deletions(-) diff --git a/src/schema/meta/templates.yaml b/src/schema/meta/templates.yaml index 781d21faaf..7cc07a3756 100644 --- a/src/schema/meta/templates.yaml +++ b/src/schema/meta/templates.yaml @@ -17,6 +17,30 @@ raw: subject: required session: optional + recording: + entities: + $ref: meta.templates.raw.base.entities + acquisition: optional + run: optional + + task: + entities: + $ref: meta.templates.raw.recording.entities + task: required + + mri: + entities: + $ref: meta.templates.raw.recording.entities + ceagent: optional + reconstruction: optional + chunk: optional + + epi: + entities: + $ref: meta.templates.raw.mri.entities + direction: optional + part: optional + # Entities that apply to most derivative files # Include thus: # diff --git a/src/schema/rules/files/raw/anat.yaml b/src/schema/rules/files/raw/anat.yaml index 78e3749715..ba751c0253 100644 --- a/src/schema/rules/files/raw/anat.yaml +++ b/src/schema/rules/files/raw/anat.yaml @@ -20,15 +20,10 @@ nonparametric: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional echo: optional part: optional - chunk: optional parametric: suffixes: @@ -55,13 +50,8 @@ parametric: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional - chunk: optional defacemask: suffixes: @@ -73,14 +63,9 @@ defacemask: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional modality: optional - chunk: optional megre: suffixes: @@ -92,15 +77,10 @@ megre: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional echo: required part: optional - chunk: optional mese: suffixes: @@ -112,16 +92,11 @@ mese: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional direction: optional - run: optional echo: required part: optional - chunk: optional multiflip: suffixes: @@ -133,16 +108,11 @@ multiflip: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional echo: optional flip: required part: optional - chunk: optional multiinversion: suffixes: @@ -154,15 +124,10 @@ multiinversion: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional inversion: required part: optional - chunk: optional mp2rage: suffixes: @@ -174,17 +139,12 @@ mp2rage: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional echo: optional flip: optional inversion: required part: optional - chunk: optional vfamt: suffixes: @@ -197,17 +157,12 @@ vfamt: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional echo: optional flip: required mtransfer: required part: optional - chunk: optional mtr: suffixes: @@ -219,12 +174,7 @@ mtr: datatypes: - anat entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.mri.entities task: optional - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional mtransfer: required part: optional - chunk: optional diff --git a/src/schema/rules/files/raw/beh.yaml b/src/schema/rules/files/raw/beh.yaml index d22a81c33d..df6f9dac06 100644 --- a/src/schema/rules/files/raw/beh.yaml +++ b/src/schema/rules/files/raw/beh.yaml @@ -1,6 +1,7 @@ --- # Non-continuous data noncontinuous: + $ref: meta.templates.raw.task suffixes: - beh extensions: @@ -8,8 +9,3 @@ noncontinuous: - .json datatypes: - beh - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional diff --git a/src/schema/rules/files/raw/channels.yaml b/src/schema/rules/files/raw/channels.yaml index da362d9a7c..4f2c9e774b 100644 --- a/src/schema/rules/files/raw/channels.yaml +++ b/src/schema/rules/files/raw/channels.yaml @@ -1,5 +1,6 @@ --- channels: + $ref: meta.templates.raw.task suffixes: - channels extensions: @@ -9,11 +10,6 @@ channels: - eeg - ieeg - nirs - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional # MEG has an additional entity available channels__meg: @@ -66,10 +62,8 @@ electrodes: - eeg - ieeg entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.recording.entities task: optional - acquisition: optional - run: optional space: optional # MEG has an additional entity available diff --git a/src/schema/rules/files/raw/dwi.yaml b/src/schema/rules/files/raw/dwi.yaml index 4a5f158720..cc211150a0 100644 --- a/src/schema/rules/files/raw/dwi.yaml +++ b/src/schema/rules/files/raw/dwi.yaml @@ -11,13 +11,10 @@ dwi: datatypes: - dwi entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - reconstruction: optional - direction: optional - run: optional - part: optional - chunk: optional + $ref: meta.templates.raw.epi.entities + # Historically BIDS has not permitted ceagent for DWI + # This could be relaxed without backwards incompatibility + ceagent: null sbref: suffixes: @@ -29,13 +26,8 @@ sbref: datatypes: - dwi entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - reconstruction: optional - direction: optional - run: optional - part: optional - chunk: optional + $ref: meta.templates.raw.epi.entities + ceagent: null # Common scanner-generated derivatives need raw names ScannerDerivatives: @@ -53,10 +45,7 @@ ScannerDerivatives: datatypes: - dwi entities: - subject: required - session: optional - acquisition: optional - reconstruction: optional - direction: optional - run: optional - chunk: optional + $ref: meta.templates.raw.epi.entities + # part is also not defined for derivative maps + ceagent: null + part: null diff --git a/src/schema/rules/files/raw/eeg.yaml b/src/schema/rules/files/raw/eeg.yaml index 47b40ce69d..0fa2e21feb 100644 --- a/src/schema/rules/files/raw/eeg.yaml +++ b/src/schema/rules/files/raw/eeg.yaml @@ -1,5 +1,6 @@ --- eeg: + $ref: meta.templates.raw.task suffixes: - eeg extensions: @@ -13,8 +14,3 @@ eeg: - .bdf datatypes: - eeg - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional diff --git a/src/schema/rules/files/raw/events.yaml b/src/schema/rules/files/raw/events.yaml index 8fa9f9106f..a1600a53e9 100644 --- a/src/schema/rules/files/raw/events.yaml +++ b/src/schema/rules/files/raw/events.yaml @@ -1,5 +1,6 @@ --- events: + $ref: meta.templates.raw.task suffixes: - events extensions: @@ -11,11 +12,6 @@ events: - ieeg - meg - nirs - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional # Specializations # In these rules, we use $ref to retrieve most of an object, and then override @@ -43,12 +39,11 @@ events__pet: datatypes: - pet entities: - # Most events allow acquisition, PET doesn't - $ref: meta.templates.raw.base.entities - task: required + $ref: meta.templates.raw.task.entities tracer: optional reconstruction: optional - run: optional + # Most events allow acquisition, PET doesn't + acquisition: null events__mrs: $ref: rules.files.raw.events.events diff --git a/src/schema/rules/files/raw/fmap.yaml b/src/schema/rules/files/raw/fmap.yaml index 2aea616bab..7d04c547a4 100644 --- a/src/schema/rules/files/raw/fmap.yaml +++ b/src/schema/rules/files/raw/fmap.yaml @@ -15,12 +15,11 @@ fieldmaps: datatypes: - fmap entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - run: optional + $ref: meta.templates.raw.recording.entities chunk: optional pepolar: + $ref: meta.templates.raw.epi suffixes: - epi extensions: @@ -31,17 +30,9 @@ pepolar: - .bvec datatypes: - fmap - entities: - subject: required - session: optional - acquisition: optional - ceagent: optional - direction: required - run: optional - part: optional - chunk: optional pepolar_m0scan: + $ref: meta.templates.raw.epi suffixes: - m0scan extensions: @@ -50,14 +41,6 @@ pepolar_m0scan: - .json datatypes: - fmap - entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - direction: required - run: optional - part: optional - chunk: optional TB1DAM: suffixes: @@ -69,15 +52,10 @@ TB1DAM: datatypes: - fmap entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.mri.entities flip: required inversion: optional part: optional - chunk: optional TB1EPI: suffixes: @@ -89,16 +67,11 @@ TB1EPI: datatypes: - fmap entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.mri.entities echo: required flip: required inversion: optional part: optional - chunk: optional RFFieldMaps: suffixes: @@ -113,16 +86,11 @@ RFFieldMaps: datatypes: - fmap entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.mri.entities echo: optional flip: optional inversion: optional part: optional - chunk: optional TB1SRGE: suffixes: @@ -134,18 +102,14 @@ TB1SRGE: datatypes: - fmap entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.mri.entities echo: optional flip: required inversion: required part: optional - chunk: optional parametric: + $ref: meta.templates.raw.mri suffixes: - TB1map - RB1map @@ -155,10 +119,3 @@ parametric: - .json datatypes: - fmap - entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - ceagent: optional - reconstruction: optional - run: optional - chunk: optional diff --git a/src/schema/rules/files/raw/func.yaml b/src/schema/rules/files/raw/func.yaml index 41b7919b50..4072d04437 100644 --- a/src/schema/rules/files/raw/func.yaml +++ b/src/schema/rules/files/raw/func.yaml @@ -11,16 +11,10 @@ func: datatypes: - func entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - ceagent: optional - reconstruction: optional - direction: optional - run: optional + $ref: + - meta.templates.raw.epi.entities + - meta.templates.raw.task.entities echo: optional - part: optional - chunk: optional norf: $ref: rules.files.raw.func.func @@ -31,21 +25,9 @@ norf: modality: optional phase: + $ref: rules.files.raw.func.func suffixes: - phase # deprecated - extensions: - - .nii.gz - - .nii - - .json - datatypes: - - func entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - ceagent: optional - reconstruction: optional - direction: optional - run: optional - echo: optional - chunk: optional + $ref: rules.files.raw.func.func.entities + part: null diff --git a/src/schema/rules/files/raw/ieeg.yaml b/src/schema/rules/files/raw/ieeg.yaml index 6bd2ba2a79..9197aa9676 100644 --- a/src/schema/rules/files/raw/ieeg.yaml +++ b/src/schema/rules/files/raw/ieeg.yaml @@ -1,5 +1,6 @@ --- ieeg: + $ref: meta.templates.raw.task suffixes: - ieeg extensions: @@ -14,8 +15,3 @@ ieeg: - .nwb datatypes: - ieeg - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional diff --git a/src/schema/rules/files/raw/meg.yaml b/src/schema/rules/files/raw/meg.yaml index ef9a97f1fd..48de894cdd 100644 --- a/src/schema/rules/files/raw/meg.yaml +++ b/src/schema/rules/files/raw/meg.yaml @@ -19,10 +19,7 @@ meg: datatypes: - meg entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional + $ref: meta.templates.raw.task.entities processing: optional split: optional diff --git a/src/schema/rules/files/raw/micr.yaml b/src/schema/rules/files/raw/micr.yaml index c978ee2fcd..ba88843472 100644 --- a/src/schema/rules/files/raw/micr.yaml +++ b/src/schema/rules/files/raw/micr.yaml @@ -29,9 +29,7 @@ microscopy: datatypes: - micr entities: - $ref: meta.templates.raw.base.entities + $ref: meta.templates.raw.recording.entities sample: required - acquisition: optional stain: optional - run: optional chunk: optional diff --git a/src/schema/rules/files/raw/motion.yaml b/src/schema/rules/files/raw/motion.yaml index 267d052b20..818a979792 100644 --- a/src/schema/rules/files/raw/motion.yaml +++ b/src/schema/rules/files/raw/motion.yaml @@ -8,8 +8,5 @@ motion: datatypes: - motion entities: - $ref: meta.templates.raw.base.entities - task: required + $ref: meta.templates.raw.task.entities tracksys: required - acquisition: optional - run: optional diff --git a/src/schema/rules/files/raw/mrs.yaml b/src/schema/rules/files/raw/mrs.yaml index fe95f08f3a..9f8d941ef1 100644 --- a/src/schema/rules/files/raw/mrs.yaml +++ b/src/schema/rules/files/raw/mrs.yaml @@ -12,12 +12,9 @@ mrs: datatypes: - mrs entities: - subject: required - session: optional + $ref: meta.templates.raw.recording.entities task: optional - acquisition: optional reconstruction: optional - run: optional echo: optional inversion: optional nucleus: optional diff --git a/src/schema/rules/files/raw/nirs.yaml b/src/schema/rules/files/raw/nirs.yaml index c5c2d8b8b0..aafce13fa9 100644 --- a/src/schema/rules/files/raw/nirs.yaml +++ b/src/schema/rules/files/raw/nirs.yaml @@ -1,5 +1,6 @@ --- nirs: + $ref: meta.templates.raw.task suffixes: - nirs extensions: @@ -7,8 +8,3 @@ nirs: - .json datatypes: - nirs - entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional diff --git a/src/schema/rules/files/raw/perf.yaml b/src/schema/rules/files/raw/perf.yaml index f5eb62f823..330bdc087a 100644 --- a/src/schema/rules/files/raw/perf.yaml +++ b/src/schema/rules/files/raw/perf.yaml @@ -10,13 +10,10 @@ asl: datatypes: - perf entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - reconstruction: optional - direction: optional - run: optional + $ref: meta.templates.raw.epi.entities echo: optional - part: optional + ceagent: null + chunk: null aslcontext: suffixes: @@ -26,11 +23,10 @@ aslcontext: datatypes: - perf entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - reconstruction: optional - direction: optional - run: optional + $ref: meta.templates.raw.epi.entities + ceagent: null + part: null + chunk: null asllabeling: suffixes: @@ -42,10 +38,8 @@ asllabeling: datatypes: - perf entities: - $ref: meta.templates.raw.base.entities - acquisition: optional + $ref: meta.templates.raw.recording.entities reconstruction: optional - run: optional norf: $ref: rules.files.raw.perf.asl diff --git a/src/schema/rules/files/raw/task.yaml b/src/schema/rules/files/raw/task.yaml index 5d86564bf0..15fab309de 100644 --- a/src/schema/rules/files/raw/task.yaml +++ b/src/schema/rules/files/raw/task.yaml @@ -12,10 +12,7 @@ timeseries: - ieeg - nirs entities: - $ref: meta.templates.raw.base.entities - task: required - acquisition: optional - run: optional + $ref: meta.templates.raw.task.entities recording: optional timeseries__mri_no_task: @@ -29,9 +26,7 @@ timeseries__mri_no_task: - dwi - perf entities: - $ref: meta.templates.raw.base.entities - acquisition: optional - run: optional + $ref: meta.templates.raw.recording.entities reconstruction: optional direction: optional recording: optional @@ -44,12 +39,11 @@ timeseries__anat: datatypes: - anat entities: - $ref: rules.files.raw.task.timeseries.entities - ceagent: optional - reconstruction: optional + $ref: + - rules.files.raw.task.timeseries.entities + - meta.templates.raw.mri.entities echo: optional part: optional - chunk: optional modality: optional timeseries__func: @@ -83,10 +77,8 @@ timeseries__pet: datatypes: - pet entities: - # Most timeseries allow acquisition, PET doesn't - $ref: meta.templates.raw.base.entities - task: required + $ref: rules.files.raw.task.timeseries.entities tracer: optional reconstruction: optional - run: optional - recording: optional + # Most timeseries allow acquisition, PET doesn't + acquisition: null From 4b683006cf2b44eca2da7bd2adda450fdcce38b0 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Fri, 20 Jun 2025 07:05:13 -0400 Subject: [PATCH 6/8] rf: Dereference while looking up references --- .../schemacode/src/bidsschematools/schema.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/schemacode/src/bidsschematools/schema.py b/tools/schemacode/src/bidsschematools/schema.py index 1f53c08f0d..0208d51e00 100644 --- a/tools/schemacode/src/bidsschematools/schema.py +++ b/tools/schemacode/src/bidsschematools/schema.py @@ -91,25 +91,27 @@ def _find(obj, predicate): def _dereference(namespace, base_schema): # In-place, recursively dereference objects - # This allows a referenced object to itself contain a reference - # A dependency graph could be constructed, but would likely be slower - # to build than to duplicate a couple dereferences + # This allows for referencing objects that contain references, + # as well as objects that do not exist until a parent is dereferenced. for struct in _find(namespace, lambda obj: "$ref" in obj): refs = struct["$ref"] if isinstance(refs, str): refs = [refs] targets = [] for ref in refs: - target = base_schema.get(ref) - if target is None: - raise ValueError(f"Reference {ref} not found in schema.") + target = base_schema + for part in ref.split("."): + target = target.get(part) + if target is None: + raise ValueError(f"Reference {ref} not found in schema.") + if "$ref" in target: + _dereference(target, base_schema) targets.append(target) + if all(isinstance(target, Mapping) for target in targets): struct.pop("$ref") - combined_target = dict(ChainMap(*targets)) - _dereference(combined_target, base_schema) - struct.update({**combined_target, **struct}) + struct.update({**ChainMap(*targets), **struct}) # Use `key: null` to delete fields for key, value in list(struct.items()): From b2953a69b90c4be74813833546d424c6964f1f8c Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 26 Aug 2025 09:59:03 -0400 Subject: [PATCH 7/8] doc: Document null deletion --- src/schema/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/schema/README.md b/src/schema/README.md index 4d53a38c74..075151f476 100644 --- a/src/schema/README.md +++ b/src/schema/README.md @@ -185,6 +185,26 @@ references (the cases in which they are used will be presented later): When multiple references are aggregated, the first reference takes precedence. + Note also that `value: null` can be used to "delete" a key from a template. + For example, in `rules.files.raw.events`: + + ```YAML + events__pet: + $ref: rules.files.raw.events.events + datatypes: + - pet + entities: + $ref: meta.templates.raw.task.entities + tracer: optional + reconstruction: optional + # Most events allow acquisition, PET doesn't + acquisition: null + ``` + + This technique should be used judiciously, preferring semantic clarity to brevity. + Templates should be expected to grow as BIDS evolves, + and should thus be used only where those changes should propagate. + ### Expressions Rules definitions make use of a limited language of expressions that always evaluate to `true` or `false`. From b9d7037dad5e4b27578e87046119d04481479b45 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 26 Aug 2025 10:32:37 -0400 Subject: [PATCH 8/8] schema: Factor out common PET and MRS entities --- src/schema/meta/templates.yaml | 16 ++++++++++++++++ src/schema/rules/files/raw/events.yaml | 11 ++--------- src/schema/rules/files/raw/mrs.yaml | 6 +----- src/schema/rules/files/raw/pet.yaml | 12 ++---------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/schema/meta/templates.yaml b/src/schema/meta/templates.yaml index 7cc07a3756..f9db50d33d 100644 --- a/src/schema/meta/templates.yaml +++ b/src/schema/meta/templates.yaml @@ -41,6 +41,22 @@ raw: direction: optional part: optional + pet: + entities: + $ref: meta.templates.raw.base.entities + task: optional + tracer: optional + reconstruction: optional + run: optional + + mrs: + entities: + $ref: meta.templates.raw.recording.entities + task: optional + nucleus: optional + volume: optional + reconstruction: optional + # Entities that apply to most derivative files # Include thus: # diff --git a/src/schema/rules/files/raw/events.yaml b/src/schema/rules/files/raw/events.yaml index a1600a53e9..bbd1ff9b84 100644 --- a/src/schema/rules/files/raw/events.yaml +++ b/src/schema/rules/files/raw/events.yaml @@ -39,18 +39,11 @@ events__pet: datatypes: - pet entities: - $ref: meta.templates.raw.task.entities - tracer: optional - reconstruction: optional - # Most events allow acquisition, PET doesn't - acquisition: null + $ref: meta.templates.raw.pet.entities events__mrs: $ref: rules.files.raw.events.events datatypes: - mrs entities: - $ref: rules.files.raw.events.events.entities - reconstruction: optional - nucleus: optional - volume: optional + $ref: meta.templates.raw.mrs.entities diff --git a/src/schema/rules/files/raw/mrs.yaml b/src/schema/rules/files/raw/mrs.yaml index 9f8d941ef1..1190bebbf1 100644 --- a/src/schema/rules/files/raw/mrs.yaml +++ b/src/schema/rules/files/raw/mrs.yaml @@ -12,10 +12,6 @@ mrs: datatypes: - mrs entities: - $ref: meta.templates.raw.recording.entities - task: optional - reconstruction: optional + $ref: meta.templates.raw.mrs.entities echo: optional inversion: optional - nucleus: optional - volume: optional diff --git a/src/schema/rules/files/raw/pet.yaml b/src/schema/rules/files/raw/pet.yaml index 50d393761c..2f543efac1 100644 --- a/src/schema/rules/files/raw/pet.yaml +++ b/src/schema/rules/files/raw/pet.yaml @@ -9,11 +9,7 @@ pet: datatypes: - pet entities: - $ref: meta.templates.raw.base.entities - task: optional - tracer: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.pet.entities blood: suffixes: @@ -24,9 +20,5 @@ blood: datatypes: - pet entities: - $ref: meta.templates.raw.base.entities - task: optional - tracer: optional - reconstruction: optional - run: optional + $ref: meta.templates.raw.pet.entities recording: required