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.
Files changed (71) hide show
  1. bidsval-0.0.1/LICENSE +21 -0
  2. bidsval-0.0.1/PKG-INFO +217 -0
  3. bidsval-0.0.1/README.md +184 -0
  4. bidsval-0.0.1/pyproject.toml +87 -0
  5. bidsval-0.0.1/setup.cfg +4 -0
  6. bidsval-0.0.1/src/bidsval/__init__.py +45 -0
  7. bidsval-0.0.1/src/bidsval/cli.py +404 -0
  8. bidsval-0.0.1/src/bidsval/context/__init__.py +18 -0
  9. bidsval-0.0.1/src/bidsval/context/associations.py +219 -0
  10. bidsval-0.0.1/src/bidsval/context/builder.py +167 -0
  11. bidsval-0.0.1/src/bidsval/context/entities.py +38 -0
  12. bidsval-0.0.1/src/bidsval/context/inheritance.py +171 -0
  13. bidsval-0.0.1/src/bidsval/context/loaders.py +129 -0
  14. bidsval-0.0.1/src/bidsval/expr/__init__.py +20 -0
  15. bidsval-0.0.1/src/bidsval/expr/evaluator.py +342 -0
  16. bidsval-0.0.1/src/bidsval/expr/functions.py +351 -0
  17. bidsval-0.0.1/src/bidsval/files/__init__.py +14 -0
  18. bidsval-0.0.1/src/bidsval/files/bidsignore.py +75 -0
  19. bidsval-0.0.1/src/bidsval/files/tree.py +146 -0
  20. bidsval-0.0.1/src/bidsval/issues.py +128 -0
  21. bidsval-0.0.1/src/bidsval/render/__init__.py +25 -0
  22. bidsval-0.0.1/src/bidsval/render/html.py +100 -0
  23. bidsval-0.0.1/src/bidsval/render/json.py +56 -0
  24. bidsval-0.0.1/src/bidsval/render/sarif.py +72 -0
  25. bidsval-0.0.1/src/bidsval/render/text.py +41 -0
  26. bidsval-0.0.1/src/bidsval/report.py +103 -0
  27. bidsval-0.0.1/src/bidsval/rules/__init__.py +13 -0
  28. bidsval-0.0.1/src/bidsval/rules/bespoke.py +63 -0
  29. bidsval-0.0.1/src/bidsval/rules/citation.py +65 -0
  30. bidsval-0.0.1/src/bidsval/rules/column_types.py +181 -0
  31. bidsval-0.0.1/src/bidsval/rules/dataset_checks.py +143 -0
  32. bidsval-0.0.1/src/bidsval/rules/engine.py +356 -0
  33. bidsval-0.0.1/src/bidsval/rules/filenames.py +498 -0
  34. bidsval-0.0.1/src/bidsval/rules/guidance.py +120 -0
  35. bidsval-0.0.1/src/bidsval/rules/integrity.py +191 -0
  36. bidsval-0.0.1/src/bidsval/rules/tables.py +298 -0
  37. bidsval-0.0.1/src/bidsval/rules/values.py +102 -0
  38. bidsval-0.0.1/src/bidsval/schema/__init__.py +31 -0
  39. bidsval-0.0.1/src/bidsval/schema/bundled/1.10.0.json +1 -0
  40. bidsval-0.0.1/src/bidsval/schema/bundled/1.10.1.json +1 -0
  41. bidsval-0.0.1/src/bidsval/schema/bundled/1.11.0.json +1 -0
  42. bidsval-0.0.1/src/bidsval/schema/bundled/1.11.1.json +1 -0
  43. bidsval-0.0.1/src/bidsval/schema/bundled/1.8.0.json +1 -0
  44. bidsval-0.0.1/src/bidsval/schema/bundled/1.9.0.json +1 -0
  45. bidsval-0.0.1/src/bidsval/schema/cache.py +67 -0
  46. bidsval-0.0.1/src/bidsval/schema/introspect.py +142 -0
  47. bidsval-0.0.1/src/bidsval/schema/resolve.py +132 -0
  48. bidsval-0.0.1/src/bidsval/validate.py +228 -0
  49. bidsval-0.0.1/src/bidsval.egg-info/PKG-INFO +217 -0
  50. bidsval-0.0.1/src/bidsval.egg-info/SOURCES.txt +69 -0
  51. bidsval-0.0.1/src/bidsval.egg-info/dependency_links.txt +1 -0
  52. bidsval-0.0.1/src/bidsval.egg-info/entry_points.txt +2 -0
  53. bidsval-0.0.1/src/bidsval.egg-info/requires.txt +10 -0
  54. bidsval-0.0.1/src/bidsval.egg-info/top_level.txt +1 -0
  55. bidsval-0.0.1/tests/test_cli.py +127 -0
  56. bidsval-0.0.1/tests/test_dataset_checks.py +130 -0
  57. bidsval-0.0.1/tests/test_engine_units.py +84 -0
  58. bidsval-0.0.1/tests/test_expressions.py +84 -0
  59. bidsval-0.0.1/tests/test_filenames.py +85 -0
  60. bidsval-0.0.1/tests/test_functions.py +130 -0
  61. bidsval-0.0.1/tests/test_inheritance_and_tabular.py +95 -0
  62. bidsval-0.0.1/tests/test_integrity_and_guidance.py +124 -0
  63. bidsval-0.0.1/tests/test_layers.py +123 -0
  64. bidsval-0.0.1/tests/test_models.py +84 -0
  65. bidsval-0.0.1/tests/test_real_data.py +51 -0
  66. bidsval-0.0.1/tests/test_recursive.py +56 -0
  67. bidsval-0.0.1/tests/test_render.py +76 -0
  68. bidsval-0.0.1/tests/test_robustness.py +133 -0
  69. bidsval-0.0.1/tests/test_schema_resolve.py +61 -0
  70. bidsval-0.0.1/tests/test_validate.py +154 -0
  71. 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).
@@ -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"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ ]