A schema-driven, pydantic-typed, in-process BIDS validator.
Project description
bidsval
Validate BIDS datasets in pure Python.
bidsval reads the official BIDS schema and checks datasets against the rules it
contains. It runs in-process with no external runtime, returns typed (pydantic)
results, and validates a whole dataset, a single subject, a single file, or a
single expression. Every published BIDS schema version ships inside the package,
so it works offline and you choose the version with one argument.
Because the schema drives everything, bidsval covers all of BIDS - anatomical,
functional, diffusion, fieldmaps, perfusion, EEG, MEG, iEEG, behavioural, PET,
microscopy, motion, NIRS, MRS - not a fixed set of modalities. Point it at a
newer schema and the newer rules apply with no code change.
Verified against the reference Deno
bids-validatoracross the fullbids-examplescorpus and real MRI/EEG/MEG/PET datasets, at a matched schema, with zero false positives. It covers filename and path legality, file integrity, sidecar field presence and value types, associated files, tabular columns (types, order, uniqueness), the inheritance principle, and dataset-level checks. The remaining gaps are HED and symlink validation; see the comparison and "Roadmap".
Install
pip install bidsval
That is all you need: the bundled BIDS schemas and the content readers
(nibabel, pandas, mne) come with it, so it works offline. Python 3.10 to 3.14.
For development, from a clone:
git clone https://github.com/karellopez/bidsval
cd bidsval
pip install -e ".[dev]" # editable install, plus the test and lint tooling
Validate a dataset
From Python:
import bidsval
report = bidsval.validate("/path/to/dataset")
report.is_valid # False if there are any errors
report.counts # {'error': 3, 'warning': 27, 'ignore': 0}
for verdict in report.files:
for issue in verdict.issues:
print(issue.severity.value, issue.code, verdict.path, issue.message)
# Narrower granularity:
bidsval.validate_subject("/path/to/dataset", "sub-01")
bidsval.validate_file("/path/to/dataset", "sub-01/anat/sub-01_T1w.nii.gz")
From the command line:
# Text summary to the terminal (exits non-zero on errors, so it drops into CI):
bidsval validate /path/to/dataset
# Validate one subject; also check NIfTI headers:
bidsval validate /path/to/dataset --subject sub-01 --headers
# Pick the output type (independent of where it goes):
bidsval validate /path/to/dataset --output-type json # JSON to stdout
bidsval validate /path/to/dataset --output-type sarif # SARIF to stdout (CI / IDE code scanning)
# Write report files: --out-dir holds report.<ext> for each selected type:
bidsval validate /path/to/dataset --output-type html --out-dir reports/ # reports/report.html
bidsval validate /path/to/dataset --output-type all --out-dir reports/ # report.txt/.json/.sarif/.html
# Show only the severities you care about (does not change pass/fail):
bidsval validate /path/to/dataset --show error # errors only
Flags: --schema <version|url|path>, --subject sub-01, --headers
(also check NIfTI headers, needs nibabel), --output-type text|json|sarif|html|all
(default text; one type prints to stdout, several need --out-dir),
--out-dir DIR (write report.<ext> per type), --show error,warning,ignore,all
(filter displayed findings; default error,warning).
Choose a schema version
Every published BIDS schema is bundled, and any other version or a URL is fetched and cached. One argument selects the schema; everything downstream is unchanged:
bidsval.validate("/data", schema="1.10.0") # a bundled version
bidsval.validate("/data", schema="latest") # the development tip (fetched)
bidsval.validate("/data", schema="https://.../schema.json") # any URL (fetched + cached)
bidsval.validate("/data", schema="/path/to/schema.json") # a local dereferenced schema.json
bidsval.validate("/data", schema="/path/to/src/schema") # a YAML schema source directory
bidsval.available_versions() # bundled: ['1.8.0', ... '1.11.1']
bidsval validate /data --schema 1.9.0
bidsval validate /data --schema latest
bidsval validate /data --schema https://bids-specification.readthedocs.io/en/v1.10.0/schema.json
bidsval schema --schema 1.10.0 # show the versions a selector resolves to
Evaluate a single expression
The expression engine is usable on its own - handy for understanding a rule or checking one condition:
from bidsval import evaluate_string
evaluate_string("suffix == 'T1w'", {"suffix": "T1w"}) # True
evaluate_string("nifti_header.dim[0] == 3", {"nifti_header": {"dim": [4]}}) # False
bidsval eval "suffix == 'T1w'" --context '{"suffix": "T1w"}'
How it works
- The schema is the engine. The BIDS schema expresses validation logic as
expressions: selectors that decide when a rule applies (
suffix == 'T1w') and checks that must hold (nifti_header.dim[0] == 3).bidsvalreads the schema's vocabulary (datatypes, entities, suffixes, extensions) and rules, builds a context for each file, and evaluates the rules against it. No BIDS terms are hardcoded. - Parsing comes from
bidsschematools;bidsvaladds the evaluator that walks the syntax tree (noeval/exec), the file/context layers, and the rule loop. - A finding is reported only when a rule produces a determinate failure. When the context cannot determine a rule (for example a check that needs a content layer not yet built), the rule is skipped rather than guessed, so the validator does not emit false errors.
- Results are pydantic models, ready to serialise to JSON or bind to a GUI.
Layout
| Module | Responsibility |
|---|---|
bidsval.schema |
Resolve a selector to one schema object; read BIDS vocabulary from it. The only version-aware code. |
bidsval.files |
Index a dataset's files (FileTree). |
bidsval.context |
Build the per-file context: entities, datatype, inheritance-merged sidecar, associated files, loaded content. |
bidsval.expr |
Evaluate BIDS schema expressions against a context. |
bidsval.rules |
Apply the schema's checks, sidecar fields (presence + value type), and tabular-column rules; plus bespoke checks. |
bidsval.validate |
validate / validate_subject / validate_file. |
bidsval.render |
Render a report as text / JSON / SARIF / HTML. |
bidsval.issues / bidsval.report |
Typed findings and results. |
bidsval.cli |
The bidsval command. |
Done: the schema engine and the file/context/rule layers; dataset/subject/file
validation; filename and path legality (with .bidsignore); file-integrity checks;
sidecar field presence and full value-type checks; the associations layer
(events, bval/bvec, channels, ASL, coordsystem, atlas, ...); tabular checks (types,
order, uniqueness, additional columns); inheritance checks; dataset-level checks;
CITATION.cff; derivatives recursion; bundled + URL + latest schema selection;
text / JSON / SARIF / HTML output.
Roadmap
Filename/path legality, file integrity, the cross-file and tabular checks (including full value-type checking and type redefinition), inheritance checks, CITATION.cff, derivatives recursion, and the coordsystems/atlas-description aggregates are all in (see comparison vs the Deno reference validator for full coverage). Remaining:
- Deferred reference checks: HED (needs a HED validator dependency) and symlink checks (the annex-symlink tension). Only the gzip/ome/tiff content-header aggregates are still unbuilt.
- The ahead-of-market features: requirement-level completeness per subject, reasoned waivers, explain mode, and one-click fixes (provenance and fix hints are already on every finding).
Documentation
The docs live in docs/ on GitHub:
- usage - install, the CLI, the Python API.
- CLI reference - every command and option, with examples and exit codes.
- schema selection - the single
--schemaselector. - output formats -
--output-type,--out-dir,--show. - how it works - the complete technical reference: design, dependencies, every layer, flowcharts, and a glossary.
- comparison vs the Deno reference validator - coverage, results, and the no-false-positives evidence.
Develop
pytest # unit suite, incl. the schema expression oracle
BIDSVAL_REAL_DATA=1 pytest tests/test_real_data.py # real-data validation (if datasets present)
ruff check src tests
License
MIT. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bidsval-0.0.2.tar.gz.
File metadata
- Download URL: bidsval-0.0.2.tar.gz
- Upload date:
- Size: 681.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72b454699e19992236cc05c3d3d0a699975d8478a9b4e575e7f72ae39ee2aef7
|
|
| MD5 |
f02ef1fe434b2b3b803374b4ffde54ce
|
|
| BLAKE2b-256 |
77d83f699ef7b680ac1f039e635f74a14521c1b5ddb3f2e3efe7bc76aff0d30d
|
File details
Details for the file bidsval-0.0.2-py3-none-any.whl.
File metadata
- Download URL: bidsval-0.0.2-py3-none-any.whl
- Upload date:
- Size: 681.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddbefa08b7bb272ad9bbc2383c455d6c78f67e67c8f815d97890c4cea9629256
|
|
| MD5 |
cbe9456565d693ea98fff86461ab922d
|
|
| BLAKE2b-256 |
89268384c9fd90bd94c1e1e0350b77fe4046dbca0b81d3d96ab88036e3bfb70f
|