nirs4all-tools
Offline, one-way, no-in-place migration tools for legacy nirs4all
artifacts (workspaces, .n4a bundles, loose prediction files).
This is the standalone home for the legacy readers that used to live inside
the nirs4all runtime. The V1 runtime carries no legacy reader and no
auto-migration trigger; instead, nirs4all-tools converts old stores into
the format the runtime already reads (nirs4all-workspace-v2), so users keep
their predictions/pipelines without the runtime ever opening a legacy store.
Status: first transform (lane
L18, lockLOCK-MIG, decisionDEC-MIG-001). The CLI surface, the no-in-place safety machinery, detection, the contract vocabulary,inspect,migrate --dry-run, and--copy-onlyare implemented. The first schema transform lowerssqlite-workspace-legacy-arraysmetadata into a fresh workspace-v2store.sqlite; legacy array rows are lowered into runtime-readablearrays/<dataset>.parquetsidecars when the optionalparquetextra is installed, and the raw rows are still preserved as checksummed JSONL audit provenance. A native-results-v1 preview can lower one current dag-ml native results directory into runtime-readable workspace-v2 metadata plus array sidecars after strict hash/schema preflight. A legacyruns/*/*/manifest.yamlpreview can lower one completed run when it references one complete*_predictions.jsonpayload and the YAML/JSON metadata agree.
The one contract: no-in-place
Every command guarantees the source is never modified:
- the source is opened read-only (SQLite via
file:…?mode=ro&immutable=1); --outputis mandatory and must be disjoint from the input (aliasing / nesting is refused, exit40);- the output must be empty unless
--resume; - the whole source tree is snapshotted
(path, size, mtime_ns)before and after every run — including failure and abort paths — and asserted byte-for-byte identical (a mismatch is exit70).
Install
pip install -e ".[dev]" # scaffold core is pure standard library
pip install -e ".[duckdb]" # add DuckDB-source reading (optional)
pip install -e ".[parquet]" # add Parquet lowering/validation (optional)
pip install -e ".[trusted-joblib]" # explicit, trusted sklearn PLS inspection only
pip install -e ".[trusted-joblib,n4mm-export]" # opt-in trusted PLS -> PREDICT-only N4MM export
CLI
nirs4all-tools --version
# Read-only: detect what a legacy location contains.
nirs4all-tools legacy inspect <input> [--format json|text] [--report PATH]
# Convert into a fresh output (one-way, no-in-place).
nirs4all-tools legacy migrate <input> --output DIR --target nirs4all-workspace-v2 \
[--manifest PATH] [--report PATH] [--id-map PATH] [--unsupported-report PATH] \
[--checksums sha256] [--dry-run | --verify] [--strict | --best-effort] \
[--copy-only] [--resume] [--trusted-load-joblib]
# Verify an output against its manifest (reads no source).
nirs4all-tools legacy verify <output-dir> --manifest PATH [--report PATH]
# Deliberately narrow: produces model.n4mm plus an attestation, never a
# workspace or archive. joblib is deserialized only with this explicit flag.
nirs4all-tools legacy export-n4mm <trusted-pls.joblib> --output DIR --trusted-load-joblib
Current schema-transform support is intentionally narrow:
-
legacy export-n4mmcan, only after explicit--trusted-load-joblib, prove a finite affine equation from exactly a fitted sklearnPLSRegressionand export it through the publicpls4allbinding (Methods ABI 2.3) as a native PREDICT-onlymodel.n4mmplus an attestation. It refuses pipelines and arbitrary estimators, never runs automatically, and never fabricates a workspace or archive: a standalone joblib has no signed graph, score, cohort, or lineage evidence; -
sqlite-workspace-legacy-arraysmetadata is lowered tostore.sqliteschema v2; -
the legacy
prediction_arraystable is decoded offline, lowered to the runtime array sidecar schema (arrays/<dataset>.parquet), and also preserved inpreserved/legacy-prediction-arrays.jsonlfor audit; -
one standalone current dag-ml
native-results-v1directory with a validscore_set_hashand canonicalpredictions.parquetprojection is lowered to workspace-v2 run/pipeline/chain/prediction/artifact metadata plus runtime-readablearrays/<dataset>.parquetsidecars; the original native payload is still checksummed underpreserved/native-results-v1/; -
malformed, older, mixed, or multi-artifact
native-results-v1sources fail--strictwith a machine-checkable schema/preflight cause, and best-effort mode preserves them opaque with the same reason in the manifest; -
one standalone complete
*_predictions.jsonloose-prediction payload is lowered to workspace-v2 run/pipeline/chain/prediction metadata plus runtime-readablearrays/<dataset>.parquetsidecars when theparquetextra is installed; the original loose JSON and sibling metadata files are still checksummed underpreserved/loose-predictions/; -
one standalone legacy
runs/*/*/manifest.yamltree is lowered when its single manifest points to one complete*_predictions.jsonunder the same source root andrun_id,pipeline_id, dataset, model, and preprocessing metadata match; the manifest tree and referenced prediction payload remain checksummed underpreserved/; -
.n4a,.n4a.py, and non-lowerablenative-results-v1artifacts are preserved as opaque checksummed payloads underpreserved/with an empty workspace-v2 store; -
non-lowerable legacy workspace payloads such as
store.duckdb, legacyruns/trees outside the single-manifest preview, incomplete or mixed loose prediction files, and already-v2 SQLite stores are also preserved opaque by default in best-effort mode;--strictrefuses them before writing; -
every real migration writes
unsupported-report.jsonalongside the manifest, report, and id-map; dry runs write the same machine-readable unsupported report only when--unsupported-report PATHis provided; -
best-effort migration exits
10only when semantic lowering is unavailable and content must be preserved opaque; -
--strictrequires semantic lowering and exits0for fully lowered array sources or native-results metadata previews.
Exit codes
| Code | Meaning |
|---|---|
0 |
success, no warnings |
10 |
migrated with warnings (best-effort preserved opaque / non-fatal skips) |
20 |
unsupported input (unknown / forward-version source, or strict unsupported item) |
30 |
verification failed |
40 |
refused by policy (in-place / aliased output, non-empty output without --resume) |
70 |
internal error (incl. source-tree integrity assertion failure) |
Contracts
Four durable JSON contracts are emitted alongside a migrated workspace
(SW4_MIG_CONVERTER_spec.md §7–10):
legacy_migration_manifest.v1— the exhaustive inventory + checksum + id-map ledger;legacy_migration_report.v1— the human/UX digest + next action;legacy_id_map.v1— the never-lossy old→new id map.legacy_unsupported_report.v1— the machine-readable list of unsupported, refused, or opaque-preserved items.
Development
ruff check .
mypy
pytest
Checked-in converter goldens live under tests/fixtures/legacy/. They are
small reduced legacy payloads for old workspaces, run/pipeline manifests, and
prediction arrays. Tests copy or materialize them into temporary directories
before migration so the source goldens stay read-only and the no-in-place
contract remains observable.
License
Dual-licensed CeCILL-2.1 OR AGPL-3.0-or-later (plus commercial), consistent
with the nirs4all ecosystem policy. See LICENSE. Contact:
nirs4all-admin@cirad.fr.
Metadata
Release files for nirs4all-tools 0.0.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nirs4all_tools-0.0.6.tar.gz | 73.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nirs4all_tools-0.0.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 132.8 kB
Release files / nirs4all_tools-0.0.6.tar.gz
| Download URL | nirs4all_tools-0.0.6.tar.gz |
|---|---|
| Size | 73.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
759dd606b2e75fa6d2ab3cdf2839921c53a75511d76ebe5f28a40ee18a44f481
|
|
BLAKE2b-256 checksum How to use checksums |
9ae22f64f4a9ee850f7ee2e0b46c4d1a53c50bc0473d3b9e99d47a30542cc8f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.
Transparency logRelease files / nirs4all_tools-0.0.6-py3-none-any.whl
| Download URL | nirs4all_tools-0.0.6-py3-none-any.whl |
|---|---|
| Size | 59.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd425c2205ceacc1c9e787b74ee3a2b21e8beccaed70c43d063acb3cc0f8ce30
|
|
BLAKE2b-256 checksum How to use checksums |
80bb1cd3df617cf9718d57cba5e3a93fdf50df46e5b87b2e24c90c524e04ec6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.
Transparency log