bidsval 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bidsval-0.0.1/LICENSE +21 -0
- bidsval-0.0.1/PKG-INFO +217 -0
- bidsval-0.0.1/README.md +184 -0
- bidsval-0.0.1/pyproject.toml +87 -0
- bidsval-0.0.1/setup.cfg +4 -0
- bidsval-0.0.1/src/bidsval/__init__.py +45 -0
- bidsval-0.0.1/src/bidsval/cli.py +404 -0
- bidsval-0.0.1/src/bidsval/context/__init__.py +18 -0
- bidsval-0.0.1/src/bidsval/context/associations.py +219 -0
- bidsval-0.0.1/src/bidsval/context/builder.py +167 -0
- bidsval-0.0.1/src/bidsval/context/entities.py +38 -0
- bidsval-0.0.1/src/bidsval/context/inheritance.py +171 -0
- bidsval-0.0.1/src/bidsval/context/loaders.py +129 -0
- bidsval-0.0.1/src/bidsval/expr/__init__.py +20 -0
- bidsval-0.0.1/src/bidsval/expr/evaluator.py +342 -0
- bidsval-0.0.1/src/bidsval/expr/functions.py +351 -0
- bidsval-0.0.1/src/bidsval/files/__init__.py +14 -0
- bidsval-0.0.1/src/bidsval/files/bidsignore.py +75 -0
- bidsval-0.0.1/src/bidsval/files/tree.py +146 -0
- bidsval-0.0.1/src/bidsval/issues.py +128 -0
- bidsval-0.0.1/src/bidsval/render/__init__.py +25 -0
- bidsval-0.0.1/src/bidsval/render/html.py +100 -0
- bidsval-0.0.1/src/bidsval/render/json.py +56 -0
- bidsval-0.0.1/src/bidsval/render/sarif.py +72 -0
- bidsval-0.0.1/src/bidsval/render/text.py +41 -0
- bidsval-0.0.1/src/bidsval/report.py +103 -0
- bidsval-0.0.1/src/bidsval/rules/__init__.py +13 -0
- bidsval-0.0.1/src/bidsval/rules/bespoke.py +63 -0
- bidsval-0.0.1/src/bidsval/rules/citation.py +65 -0
- bidsval-0.0.1/src/bidsval/rules/column_types.py +181 -0
- bidsval-0.0.1/src/bidsval/rules/dataset_checks.py +143 -0
- bidsval-0.0.1/src/bidsval/rules/engine.py +356 -0
- bidsval-0.0.1/src/bidsval/rules/filenames.py +498 -0
- bidsval-0.0.1/src/bidsval/rules/guidance.py +120 -0
- bidsval-0.0.1/src/bidsval/rules/integrity.py +191 -0
- bidsval-0.0.1/src/bidsval/rules/tables.py +298 -0
- bidsval-0.0.1/src/bidsval/rules/values.py +102 -0
- bidsval-0.0.1/src/bidsval/schema/__init__.py +31 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.10.0.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.10.1.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.11.0.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.11.1.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.8.0.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/bundled/1.9.0.json +1 -0
- bidsval-0.0.1/src/bidsval/schema/cache.py +67 -0
- bidsval-0.0.1/src/bidsval/schema/introspect.py +142 -0
- bidsval-0.0.1/src/bidsval/schema/resolve.py +132 -0
- bidsval-0.0.1/src/bidsval/validate.py +228 -0
- bidsval-0.0.1/src/bidsval.egg-info/PKG-INFO +217 -0
- bidsval-0.0.1/src/bidsval.egg-info/SOURCES.txt +69 -0
- bidsval-0.0.1/src/bidsval.egg-info/dependency_links.txt +1 -0
- bidsval-0.0.1/src/bidsval.egg-info/entry_points.txt +2 -0
- bidsval-0.0.1/src/bidsval.egg-info/requires.txt +10 -0
- bidsval-0.0.1/src/bidsval.egg-info/top_level.txt +1 -0
- bidsval-0.0.1/tests/test_cli.py +127 -0
- bidsval-0.0.1/tests/test_dataset_checks.py +130 -0
- bidsval-0.0.1/tests/test_engine_units.py +84 -0
- bidsval-0.0.1/tests/test_expressions.py +84 -0
- bidsval-0.0.1/tests/test_filenames.py +85 -0
- bidsval-0.0.1/tests/test_functions.py +130 -0
- bidsval-0.0.1/tests/test_inheritance_and_tabular.py +95 -0
- bidsval-0.0.1/tests/test_integrity_and_guidance.py +124 -0
- bidsval-0.0.1/tests/test_layers.py +123 -0
- bidsval-0.0.1/tests/test_models.py +84 -0
- bidsval-0.0.1/tests/test_real_data.py +51 -0
- bidsval-0.0.1/tests/test_recursive.py +56 -0
- bidsval-0.0.1/tests/test_render.py +76 -0
- bidsval-0.0.1/tests/test_robustness.py +133 -0
- bidsval-0.0.1/tests/test_schema_resolve.py +61 -0
- bidsval-0.0.1/tests/test_validate.py +154 -0
- bidsval-0.0.1/tests/test_value_types.py +92 -0
bidsval-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bidsval contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bidsval-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bidsval
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A schema-driven, pydantic-typed, in-process BIDS validator.
|
|
5
|
+
Author: bidsval contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/karellopez/bidsval
|
|
8
|
+
Project-URL: Repository, https://github.com/karellopez/bidsval
|
|
9
|
+
Project-URL: Issues, https://github.com/karellopez/bidsval/issues
|
|
10
|
+
Keywords: BIDS,validation,neuroimaging,schema,pydantic
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: <3.15,>=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: bidsschematools<=1.2.2,>=1.0
|
|
24
|
+
Requires-Dist: pydantic<=2.13.4,>=2
|
|
25
|
+
Requires-Dist: nibabel<=5.4.2,>=5.0
|
|
26
|
+
Requires-Dist: pandas<3.0,>=2.0
|
|
27
|
+
Requires-Dist: mne<=1.12.1,>=1.6
|
|
28
|
+
Requires-Dist: pyyaml<=6.0.3,>=5.4
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# bidsval
|
|
35
|
+
|
|
36
|
+
Validate [BIDS](https://bids.neuroimaging.io) datasets in pure Python.
|
|
37
|
+
|
|
38
|
+
`bidsval` reads the official BIDS schema and checks datasets against the rules it
|
|
39
|
+
contains. It runs in-process with no external runtime, returns typed (pydantic)
|
|
40
|
+
results, and validates a whole dataset, a single subject, a single file, or a
|
|
41
|
+
single expression. Every published BIDS schema version ships inside the package,
|
|
42
|
+
so it works offline and you choose the version with one argument.
|
|
43
|
+
|
|
44
|
+
Because the schema drives everything, `bidsval` covers all of BIDS - anatomical,
|
|
45
|
+
functional, diffusion, fieldmaps, perfusion, EEG, MEG, iEEG, behavioural, PET,
|
|
46
|
+
microscopy, motion, NIRS, MRS - not a fixed set of modalities. Point it at a
|
|
47
|
+
newer schema and the newer rules apply with no code change.
|
|
48
|
+
|
|
49
|
+
> Working and tested against real MRI, EEG, MEG, and PET datasets and the
|
|
50
|
+
> official `bids-examples` corpus, with zero false positives versus the reference
|
|
51
|
+
> validator. It checks file structure, sidecar fields (presence and value type),
|
|
52
|
+
> associated files (events, bval/bvec, channels, ASL, ...), and tabular columns.
|
|
53
|
+
> Full coverage parity with the reference is still in progress; see "Roadmap".
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
pip install -e . # bidsval and all required readers (nibabel, pandas, mne)
|
|
59
|
+
pip install -e ".[dev]" # also the test and lint tooling
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Validate a dataset
|
|
63
|
+
|
|
64
|
+
From Python:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import bidsval
|
|
68
|
+
|
|
69
|
+
report = bidsval.validate("/path/to/dataset")
|
|
70
|
+
report.is_valid # False if there are any errors
|
|
71
|
+
report.counts # {'error': 3, 'warning': 27, 'ignore': 0}
|
|
72
|
+
for verdict in report.files:
|
|
73
|
+
for issue in verdict.issues:
|
|
74
|
+
print(issue.severity.value, issue.code, verdict.path, issue.message)
|
|
75
|
+
|
|
76
|
+
# Narrower granularity:
|
|
77
|
+
bidsval.validate_subject("/path/to/dataset", "sub-01")
|
|
78
|
+
bidsval.validate_file("/path/to/dataset", "sub-01/anat/sub-01_T1w.nii.gz")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
From the command line:
|
|
82
|
+
|
|
83
|
+
```shell
|
|
84
|
+
# Text summary to the terminal (exits non-zero on errors, so it drops into CI):
|
|
85
|
+
bidsval validate /path/to/dataset
|
|
86
|
+
|
|
87
|
+
# Validate one subject; also check NIfTI headers:
|
|
88
|
+
bidsval validate /path/to/dataset --subject sub-01 --headers
|
|
89
|
+
|
|
90
|
+
# Pick the output type (independent of where it goes):
|
|
91
|
+
bidsval validate /path/to/dataset --output-type json # JSON to stdout
|
|
92
|
+
bidsval validate /path/to/dataset --output-type sarif # SARIF to stdout (CI / IDE code scanning)
|
|
93
|
+
|
|
94
|
+
# Write report files: --out-dir holds report.<ext> for each selected type:
|
|
95
|
+
bidsval validate /path/to/dataset --output-type html --out-dir reports/ # reports/report.html
|
|
96
|
+
bidsval validate /path/to/dataset --output-type all --out-dir reports/ # report.txt/.json/.sarif/.html
|
|
97
|
+
|
|
98
|
+
# Show only the severities you care about (does not change pass/fail):
|
|
99
|
+
bidsval validate /path/to/dataset --show error # errors only
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Flags: `--schema <version|url|path>`, `--subject sub-01`, `--headers`
|
|
103
|
+
(also check NIfTI headers, needs nibabel), `--output-type text|json|sarif|html|all`
|
|
104
|
+
(default `text`; one type prints to stdout, several need `--out-dir`),
|
|
105
|
+
`--out-dir DIR` (write `report.<ext>` per type), `--show error,warning,ignore,all`
|
|
106
|
+
(filter displayed findings; default `error,warning`).
|
|
107
|
+
|
|
108
|
+
## Choose a schema version
|
|
109
|
+
|
|
110
|
+
Every published BIDS schema is bundled, and any other version or a URL is fetched
|
|
111
|
+
and cached. One argument selects the schema; everything downstream is unchanged:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
bidsval.validate("/data", schema="1.10.0") # a bundled version
|
|
115
|
+
bidsval.validate("/data", schema="latest") # the development tip (fetched)
|
|
116
|
+
bidsval.validate("/data", schema="https://.../schema.json") # any URL (fetched + cached)
|
|
117
|
+
bidsval.validate("/data", schema="/path/to/schema.json") # a local dereferenced schema.json
|
|
118
|
+
bidsval.validate("/data", schema="/path/to/src/schema") # a YAML schema source directory
|
|
119
|
+
bidsval.available_versions() # bundled: ['1.8.0', ... '1.11.1']
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```shell
|
|
123
|
+
bidsval validate /data --schema 1.9.0
|
|
124
|
+
bidsval validate /data --schema latest
|
|
125
|
+
bidsval validate /data --schema https://bids-specification.readthedocs.io/en/v1.10.0/schema.json
|
|
126
|
+
bidsval schema --schema 1.10.0 # show the versions a selector resolves to
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Evaluate a single expression
|
|
130
|
+
|
|
131
|
+
The expression engine is usable on its own - handy for understanding a rule or
|
|
132
|
+
checking one condition:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from bidsval import evaluate_string
|
|
136
|
+
|
|
137
|
+
evaluate_string("suffix == 'T1w'", {"suffix": "T1w"}) # True
|
|
138
|
+
evaluate_string("nifti_header.dim[0] == 3", {"nifti_header": {"dim": [4]}}) # False
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```shell
|
|
142
|
+
bidsval eval "suffix == 'T1w'" --context '{"suffix": "T1w"}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## How it works
|
|
146
|
+
|
|
147
|
+
- The schema is the engine. The BIDS schema expresses validation logic as
|
|
148
|
+
expressions: selectors that decide when a rule applies (`suffix == 'T1w'`) and
|
|
149
|
+
checks that must hold (`nifti_header.dim[0] == 3`). `bidsval` reads the schema's
|
|
150
|
+
vocabulary (datatypes, entities, suffixes, extensions) and rules, builds a
|
|
151
|
+
context for each file, and evaluates the rules against it. No BIDS terms are
|
|
152
|
+
hardcoded.
|
|
153
|
+
- Parsing comes from `bidsschematools`; `bidsval` adds the evaluator that walks
|
|
154
|
+
the syntax tree (no `eval`/`exec`), the file/context layers, and the rule loop.
|
|
155
|
+
- A finding is reported only when a rule produces a determinate failure. When the
|
|
156
|
+
context cannot determine a rule (for example a check that needs a content layer
|
|
157
|
+
not yet built), the rule is skipped rather than guessed, so the validator does
|
|
158
|
+
not emit false errors.
|
|
159
|
+
- Results are pydantic models, ready to serialise to JSON or bind to a GUI.
|
|
160
|
+
|
|
161
|
+
## Layout
|
|
162
|
+
|
|
163
|
+
| Module | Responsibility |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `bidsval.schema` | Resolve a selector to one schema object; read BIDS vocabulary from it. The only version-aware code. |
|
|
166
|
+
| `bidsval.files` | Index a dataset's files (`FileTree`). |
|
|
167
|
+
| `bidsval.context` | Build the per-file context: entities, datatype, inheritance-merged sidecar, associated files, loaded content. |
|
|
168
|
+
| `bidsval.expr` | Evaluate BIDS schema expressions against a context. |
|
|
169
|
+
| `bidsval.rules` | Apply the schema's checks, sidecar fields (presence + value type), and tabular-column rules; plus bespoke checks. |
|
|
170
|
+
| `bidsval.validate` | `validate` / `validate_subject` / `validate_file`. |
|
|
171
|
+
| `bidsval.render` | Render a report as text / JSON / SARIF / HTML. |
|
|
172
|
+
| `bidsval.issues` / `bidsval.report` | Typed findings and results. |
|
|
173
|
+
| `bidsval.cli` | The `bidsval` command. |
|
|
174
|
+
|
|
175
|
+
Done: schema engine; file/context/rule layers; dataset/subject/file validation;
|
|
176
|
+
JSON sidecar field presence and value-type checks; the associations layer
|
|
177
|
+
(events, bval/bvec, channels, ASL, coordsystem, ...); tabular-column checks;
|
|
178
|
+
empty-file / unreadable-NIfTI checks; bundled + URL + `latest` schema selection;
|
|
179
|
+
text / JSON / SARIF / HTML outputs.
|
|
180
|
+
|
|
181
|
+
## Roadmap
|
|
182
|
+
|
|
183
|
+
Filename/path legality, file integrity, the cross-file and tabular checks (including
|
|
184
|
+
full value-type checking and type redefinition), inheritance checks, CITATION.cff,
|
|
185
|
+
derivatives recursion, and the coordsystems/atlas-description aggregates are all in
|
|
186
|
+
(see [comparison vs the Deno reference validator](docs/comparison-vs-deno.md) for full
|
|
187
|
+
coverage). Remaining:
|
|
188
|
+
|
|
189
|
+
1. Deferred reference checks: HED (needs a HED validator dependency) and symlink checks
|
|
190
|
+
(the annex-symlink tension). Only the gzip/ome/tiff content-header aggregates are
|
|
191
|
+
still unbuilt.
|
|
192
|
+
2. The ahead-of-market features: requirement-level completeness per subject, reasoned
|
|
193
|
+
waivers, explain mode, and one-click fixes (provenance and fix hints are already on
|
|
194
|
+
every finding).
|
|
195
|
+
|
|
196
|
+
## Documentation
|
|
197
|
+
|
|
198
|
+
See [`docs/`](docs/index.md):
|
|
199
|
+
|
|
200
|
+
- [usage](docs/usage.md) - install, the CLI, the Python API.
|
|
201
|
+
- [CLI reference](docs/cli-reference.md) - every command and option, with examples and exit codes.
|
|
202
|
+
- [schema selection](docs/schema-selection.md) - the single `--schema` selector.
|
|
203
|
+
- [output formats](docs/output-formats.md) - `--output-type`, `--out-dir`, `--show`.
|
|
204
|
+
- [how it works](docs/internals.md) - the complete technical reference: design, dependencies, every layer, flowcharts, and a glossary.
|
|
205
|
+
- [comparison vs the Deno reference validator](docs/comparison-vs-deno.md) - coverage, results, and the no-false-positives evidence.
|
|
206
|
+
|
|
207
|
+
## Develop
|
|
208
|
+
|
|
209
|
+
```shell
|
|
210
|
+
pytest # unit suite, incl. the schema expression oracle
|
|
211
|
+
BIDSVAL_REAL_DATA=1 pytest tests/test_real_data.py # real-data validation (if datasets present)
|
|
212
|
+
ruff check src tests
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT. See [LICENSE](LICENSE).
|
bidsval-0.0.1/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# bidsval
|
|
2
|
+
|
|
3
|
+
Validate [BIDS](https://bids.neuroimaging.io) datasets in pure Python.
|
|
4
|
+
|
|
5
|
+
`bidsval` reads the official BIDS schema and checks datasets against the rules it
|
|
6
|
+
contains. It runs in-process with no external runtime, returns typed (pydantic)
|
|
7
|
+
results, and validates a whole dataset, a single subject, a single file, or a
|
|
8
|
+
single expression. Every published BIDS schema version ships inside the package,
|
|
9
|
+
so it works offline and you choose the version with one argument.
|
|
10
|
+
|
|
11
|
+
Because the schema drives everything, `bidsval` covers all of BIDS - anatomical,
|
|
12
|
+
functional, diffusion, fieldmaps, perfusion, EEG, MEG, iEEG, behavioural, PET,
|
|
13
|
+
microscopy, motion, NIRS, MRS - not a fixed set of modalities. Point it at a
|
|
14
|
+
newer schema and the newer rules apply with no code change.
|
|
15
|
+
|
|
16
|
+
> Working and tested against real MRI, EEG, MEG, and PET datasets and the
|
|
17
|
+
> official `bids-examples` corpus, with zero false positives versus the reference
|
|
18
|
+
> validator. It checks file structure, sidecar fields (presence and value type),
|
|
19
|
+
> associated files (events, bval/bvec, channels, ASL, ...), and tabular columns.
|
|
20
|
+
> Full coverage parity with the reference is still in progress; see "Roadmap".
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```shell
|
|
25
|
+
pip install -e . # bidsval and all required readers (nibabel, pandas, mne)
|
|
26
|
+
pip install -e ".[dev]" # also the test and lint tooling
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Validate a dataset
|
|
30
|
+
|
|
31
|
+
From Python:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import bidsval
|
|
35
|
+
|
|
36
|
+
report = bidsval.validate("/path/to/dataset")
|
|
37
|
+
report.is_valid # False if there are any errors
|
|
38
|
+
report.counts # {'error': 3, 'warning': 27, 'ignore': 0}
|
|
39
|
+
for verdict in report.files:
|
|
40
|
+
for issue in verdict.issues:
|
|
41
|
+
print(issue.severity.value, issue.code, verdict.path, issue.message)
|
|
42
|
+
|
|
43
|
+
# Narrower granularity:
|
|
44
|
+
bidsval.validate_subject("/path/to/dataset", "sub-01")
|
|
45
|
+
bidsval.validate_file("/path/to/dataset", "sub-01/anat/sub-01_T1w.nii.gz")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
From the command line:
|
|
49
|
+
|
|
50
|
+
```shell
|
|
51
|
+
# Text summary to the terminal (exits non-zero on errors, so it drops into CI):
|
|
52
|
+
bidsval validate /path/to/dataset
|
|
53
|
+
|
|
54
|
+
# Validate one subject; also check NIfTI headers:
|
|
55
|
+
bidsval validate /path/to/dataset --subject sub-01 --headers
|
|
56
|
+
|
|
57
|
+
# Pick the output type (independent of where it goes):
|
|
58
|
+
bidsval validate /path/to/dataset --output-type json # JSON to stdout
|
|
59
|
+
bidsval validate /path/to/dataset --output-type sarif # SARIF to stdout (CI / IDE code scanning)
|
|
60
|
+
|
|
61
|
+
# Write report files: --out-dir holds report.<ext> for each selected type:
|
|
62
|
+
bidsval validate /path/to/dataset --output-type html --out-dir reports/ # reports/report.html
|
|
63
|
+
bidsval validate /path/to/dataset --output-type all --out-dir reports/ # report.txt/.json/.sarif/.html
|
|
64
|
+
|
|
65
|
+
# Show only the severities you care about (does not change pass/fail):
|
|
66
|
+
bidsval validate /path/to/dataset --show error # errors only
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Flags: `--schema <version|url|path>`, `--subject sub-01`, `--headers`
|
|
70
|
+
(also check NIfTI headers, needs nibabel), `--output-type text|json|sarif|html|all`
|
|
71
|
+
(default `text`; one type prints to stdout, several need `--out-dir`),
|
|
72
|
+
`--out-dir DIR` (write `report.<ext>` per type), `--show error,warning,ignore,all`
|
|
73
|
+
(filter displayed findings; default `error,warning`).
|
|
74
|
+
|
|
75
|
+
## Choose a schema version
|
|
76
|
+
|
|
77
|
+
Every published BIDS schema is bundled, and any other version or a URL is fetched
|
|
78
|
+
and cached. One argument selects the schema; everything downstream is unchanged:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
bidsval.validate("/data", schema="1.10.0") # a bundled version
|
|
82
|
+
bidsval.validate("/data", schema="latest") # the development tip (fetched)
|
|
83
|
+
bidsval.validate("/data", schema="https://.../schema.json") # any URL (fetched + cached)
|
|
84
|
+
bidsval.validate("/data", schema="/path/to/schema.json") # a local dereferenced schema.json
|
|
85
|
+
bidsval.validate("/data", schema="/path/to/src/schema") # a YAML schema source directory
|
|
86
|
+
bidsval.available_versions() # bundled: ['1.8.0', ... '1.11.1']
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```shell
|
|
90
|
+
bidsval validate /data --schema 1.9.0
|
|
91
|
+
bidsval validate /data --schema latest
|
|
92
|
+
bidsval validate /data --schema https://bids-specification.readthedocs.io/en/v1.10.0/schema.json
|
|
93
|
+
bidsval schema --schema 1.10.0 # show the versions a selector resolves to
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Evaluate a single expression
|
|
97
|
+
|
|
98
|
+
The expression engine is usable on its own - handy for understanding a rule or
|
|
99
|
+
checking one condition:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from bidsval import evaluate_string
|
|
103
|
+
|
|
104
|
+
evaluate_string("suffix == 'T1w'", {"suffix": "T1w"}) # True
|
|
105
|
+
evaluate_string("nifti_header.dim[0] == 3", {"nifti_header": {"dim": [4]}}) # False
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```shell
|
|
109
|
+
bidsval eval "suffix == 'T1w'" --context '{"suffix": "T1w"}'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## How it works
|
|
113
|
+
|
|
114
|
+
- The schema is the engine. The BIDS schema expresses validation logic as
|
|
115
|
+
expressions: selectors that decide when a rule applies (`suffix == 'T1w'`) and
|
|
116
|
+
checks that must hold (`nifti_header.dim[0] == 3`). `bidsval` reads the schema's
|
|
117
|
+
vocabulary (datatypes, entities, suffixes, extensions) and rules, builds a
|
|
118
|
+
context for each file, and evaluates the rules against it. No BIDS terms are
|
|
119
|
+
hardcoded.
|
|
120
|
+
- Parsing comes from `bidsschematools`; `bidsval` adds the evaluator that walks
|
|
121
|
+
the syntax tree (no `eval`/`exec`), the file/context layers, and the rule loop.
|
|
122
|
+
- A finding is reported only when a rule produces a determinate failure. When the
|
|
123
|
+
context cannot determine a rule (for example a check that needs a content layer
|
|
124
|
+
not yet built), the rule is skipped rather than guessed, so the validator does
|
|
125
|
+
not emit false errors.
|
|
126
|
+
- Results are pydantic models, ready to serialise to JSON or bind to a GUI.
|
|
127
|
+
|
|
128
|
+
## Layout
|
|
129
|
+
|
|
130
|
+
| Module | Responsibility |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `bidsval.schema` | Resolve a selector to one schema object; read BIDS vocabulary from it. The only version-aware code. |
|
|
133
|
+
| `bidsval.files` | Index a dataset's files (`FileTree`). |
|
|
134
|
+
| `bidsval.context` | Build the per-file context: entities, datatype, inheritance-merged sidecar, associated files, loaded content. |
|
|
135
|
+
| `bidsval.expr` | Evaluate BIDS schema expressions against a context. |
|
|
136
|
+
| `bidsval.rules` | Apply the schema's checks, sidecar fields (presence + value type), and tabular-column rules; plus bespoke checks. |
|
|
137
|
+
| `bidsval.validate` | `validate` / `validate_subject` / `validate_file`. |
|
|
138
|
+
| `bidsval.render` | Render a report as text / JSON / SARIF / HTML. |
|
|
139
|
+
| `bidsval.issues` / `bidsval.report` | Typed findings and results. |
|
|
140
|
+
| `bidsval.cli` | The `bidsval` command. |
|
|
141
|
+
|
|
142
|
+
Done: schema engine; file/context/rule layers; dataset/subject/file validation;
|
|
143
|
+
JSON sidecar field presence and value-type checks; the associations layer
|
|
144
|
+
(events, bval/bvec, channels, ASL, coordsystem, ...); tabular-column checks;
|
|
145
|
+
empty-file / unreadable-NIfTI checks; bundled + URL + `latest` schema selection;
|
|
146
|
+
text / JSON / SARIF / HTML outputs.
|
|
147
|
+
|
|
148
|
+
## Roadmap
|
|
149
|
+
|
|
150
|
+
Filename/path legality, file integrity, the cross-file and tabular checks (including
|
|
151
|
+
full value-type checking and type redefinition), inheritance checks, CITATION.cff,
|
|
152
|
+
derivatives recursion, and the coordsystems/atlas-description aggregates are all in
|
|
153
|
+
(see [comparison vs the Deno reference validator](docs/comparison-vs-deno.md) for full
|
|
154
|
+
coverage). Remaining:
|
|
155
|
+
|
|
156
|
+
1. Deferred reference checks: HED (needs a HED validator dependency) and symlink checks
|
|
157
|
+
(the annex-symlink tension). Only the gzip/ome/tiff content-header aggregates are
|
|
158
|
+
still unbuilt.
|
|
159
|
+
2. The ahead-of-market features: requirement-level completeness per subject, reasoned
|
|
160
|
+
waivers, explain mode, and one-click fixes (provenance and fix hints are already on
|
|
161
|
+
every finding).
|
|
162
|
+
|
|
163
|
+
## Documentation
|
|
164
|
+
|
|
165
|
+
See [`docs/`](docs/index.md):
|
|
166
|
+
|
|
167
|
+
- [usage](docs/usage.md) - install, the CLI, the Python API.
|
|
168
|
+
- [CLI reference](docs/cli-reference.md) - every command and option, with examples and exit codes.
|
|
169
|
+
- [schema selection](docs/schema-selection.md) - the single `--schema` selector.
|
|
170
|
+
- [output formats](docs/output-formats.md) - `--output-type`, `--out-dir`, `--show`.
|
|
171
|
+
- [how it works](docs/internals.md) - the complete technical reference: design, dependencies, every layer, flowcharts, and a glossary.
|
|
172
|
+
- [comparison vs the Deno reference validator](docs/comparison-vs-deno.md) - coverage, results, and the no-false-positives evidence.
|
|
173
|
+
|
|
174
|
+
## Develop
|
|
175
|
+
|
|
176
|
+
```shell
|
|
177
|
+
pytest # unit suite, incl. the schema expression oracle
|
|
178
|
+
BIDSVAL_REAL_DATA=1 pytest tests/test_real_data.py # real-data validation (if datasets present)
|
|
179
|
+
ruff check src tests
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "bidsval"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "A schema-driven, pydantic-typed, in-process BIDS validator."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10,<3.15"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "bidsval contributors" }]
|
|
13
|
+
keywords = ["BIDS", "validation", "neuroimaging", "schema", "pydantic"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Science/Research",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Topic :: Scientific/Engineering",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
# Dependencies.
|
|
27
|
+
# Bounds strategy (same as BIDS-Manager):
|
|
28
|
+
# lower bound = oldest version that works with any supported Python (3.10+).
|
|
29
|
+
# upper bound = latest version tested in the reference env. On older Pythons
|
|
30
|
+
# pip picks the newest release that fits both the version range
|
|
31
|
+
# AND that Python's compatibility.
|
|
32
|
+
# The content readers (nibabel, pandas, mne) are REQUIRED, not optional, so a
|
|
33
|
+
# default install validates file contents out of the box. The loaders still
|
|
34
|
+
# degrade safely (return empty/None) if a reader is ever missing or a file is
|
|
35
|
+
# malformed, so a rule that needs that content simply does not fire.
|
|
36
|
+
dependencies = [
|
|
37
|
+
# Schema engine: the BIDS schema and its expression-language parser. The
|
|
38
|
+
# keystone of the architecture; all BIDS knowledge enters through here.
|
|
39
|
+
"bidsschematools>=1.0,<=1.2.2",
|
|
40
|
+
|
|
41
|
+
# Strongly-typed, serialisable result model (Issue / ValidationReport).
|
|
42
|
+
"pydantic>=2,<=2.13.4",
|
|
43
|
+
|
|
44
|
+
# Content readers.
|
|
45
|
+
"nibabel>=5.0,<=5.4.2", # NIfTI headers (read by default)
|
|
46
|
+
"pandas>=2.0,<3.0", # TSV columns (pandas 3 changes string dtype: cap < 3.0)
|
|
47
|
+
"mne>=1.6,<=1.12.1", # EEG / MEG / iEEG readers (for forthcoming content checks)
|
|
48
|
+
"pyyaml>=5.4,<=6.0.3", # CITATION.cff parsing
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
dev = ["pytest>=7", "ruff>=0.1"]
|
|
53
|
+
|
|
54
|
+
[project.scripts]
|
|
55
|
+
bidsval = "bidsval.cli:main"
|
|
56
|
+
|
|
57
|
+
[project.urls]
|
|
58
|
+
Homepage = "https://github.com/karellopez/bidsval"
|
|
59
|
+
Repository = "https://github.com/karellopez/bidsval"
|
|
60
|
+
Issues = "https://github.com/karellopez/bidsval/issues"
|
|
61
|
+
|
|
62
|
+
[tool.setuptools.packages.find]
|
|
63
|
+
where = ["src"]
|
|
64
|
+
|
|
65
|
+
[tool.setuptools.package-data]
|
|
66
|
+
# Ship the bundled schema(s) so the default schema is pinned to a known BIDS
|
|
67
|
+
# version and works fully offline, independent of the installed bidsschematools.
|
|
68
|
+
bidsval = ["schema/bundled/*.json"]
|
|
69
|
+
|
|
70
|
+
[tool.ruff]
|
|
71
|
+
line-length = 100
|
|
72
|
+
target-version = "py310"
|
|
73
|
+
src = ["src", "tests"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
# A pragmatic, widely-used set: pycodestyle errors, pyflakes, isort, pyupgrade,
|
|
77
|
+
# and a few bugbear checks. Kept intentionally modest so the rules help rather
|
|
78
|
+
# than nag.
|
|
79
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint.per-file-ignores]
|
|
82
|
+
# The HTML renderer embeds a CSS/HTML template; long template lines are fine.
|
|
83
|
+
"src/bidsval/render/html.py" = ["E501"]
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
testpaths = ["tests"]
|
|
87
|
+
addopts = "-q"
|
bidsval-0.0.1/setup.cfg
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""bidsval - a schema-driven, pydantic-typed, in-process BIDS validator.
|
|
2
|
+
|
|
3
|
+
The public surface grows as the validator does. Today it exposes the two pieces
|
|
4
|
+
that the rest of the engine is built on:
|
|
5
|
+
|
|
6
|
+
* the schema resolver (:func:`bidsval.schema.resolve`), the single place that
|
|
7
|
+
turns a schema selector into one in-memory schema object, and
|
|
8
|
+
* the expression evaluator (:func:`bidsval.expr.evaluate_string`), which runs a
|
|
9
|
+
BIDS schema expression against a context.
|
|
10
|
+
|
|
11
|
+
Result types (:class:`~bidsval.issues.Issue`, :class:`~bidsval.report.ValidationReport`)
|
|
12
|
+
are re-exported here so consumers can ``from bidsval import Issue, ValidationReport``.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from .expr import evaluate_string
|
|
18
|
+
from .issues import DatasetIssues, Issue, Severity
|
|
19
|
+
from .report import FileVerdict, ValidationReport
|
|
20
|
+
from .schema import available_versions, bids_version, resolve, schema_version
|
|
21
|
+
from .validate import validate, validate_file, validate_subject
|
|
22
|
+
|
|
23
|
+
try: # populated from package metadata once installed
|
|
24
|
+
from importlib.metadata import version
|
|
25
|
+
|
|
26
|
+
__version__ = version("bidsval")
|
|
27
|
+
except Exception: # pragma: no cover - source checkout without metadata
|
|
28
|
+
__version__ = "0.0.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"Severity",
|
|
32
|
+
"Issue",
|
|
33
|
+
"DatasetIssues",
|
|
34
|
+
"FileVerdict",
|
|
35
|
+
"ValidationReport",
|
|
36
|
+
"resolve",
|
|
37
|
+
"available_versions",
|
|
38
|
+
"schema_version",
|
|
39
|
+
"bids_version",
|
|
40
|
+
"evaluate_string",
|
|
41
|
+
"validate",
|
|
42
|
+
"validate_subject",
|
|
43
|
+
"validate_file",
|
|
44
|
+
"__version__",
|
|
45
|
+
]
|