mantleplace-mpb
Two things for anyone who works with a Mantle Place Bundle (MPB), in pure Python: the standard library and nothing else, so no GDAL, no PROJ and nothing compiled.
mpb validatechecks a bundle and says pass or fail, with every reason. It is the conformance check a producer, a reader's author or a CI job runs on a bundle.read_bundleopens a bundle and gives every file with its frame and its ODbL role, and the offset and axis transform that relate two files of one frame. It never reprojects.
pip install mantleplace-mpb
mpb validate site-bundle.zip # a zip, a folder, or either inside one wrapper folder
mpb validate site-bundle.zip --json # the machine-readable report
The package version is the MPB version it was tested against: 1.14.0 is held to the conformance
corpus written for MPB 1.14.0, and a .postN release changes the package and not the suite.
mpb --version and mantleplace_mpb.__version__ report it.
| Exit | Meaning |
|---|---|
| 0 | conformant: no error (warnings are reported; --strict makes them fail) |
| 1 | not conformant: each reason is a finding in the report |
| 2 | could not check: the input is unreadable, or its schema could not be fetched or trusted |
What it checks
The format is spec/format.md; this tool checks a bundle against it and
against the published schema, and restates neither.
- The archive. A zip, a folder, or either with the bundle inside one wrapper folder.
__MACOSX/and.DS_Storeare skipped wherever they sit. A zip entry that is not a plain relative path inside the bundle is refused and never read. - The schema. The manifest is held to the schema of the version it declares, fetched from
the published series at
https://mantle.place/.well-known/schemas/bundle-manifest/. The version must be listed in the series' freeze ledger, and the fetched bytes must match the sha256 the ledger records for them. The JSON Schema evaluator is built in and refuses any keyword it does not evaluate, so a schema it cannot fully check is "could not check", never "pass". - The pointer rule. Every
layoutpath (each string value;mesh_formatslists format names, not files), every per-artifactpathand everyfile_entrieskey must name a file or folder in the bundle, by a plain relative path that stays inside it.layout.manifestmust name the manifest. In a bundle stored as parts, a file another part holds is reported, not failed. - sha256, where present. Each stated hash is checked against the bytes, and a mismatch fails by file name. A pointer with no hash of its own takes the one the manifest's format tables state for the same path; a file with no hash anywhere is counted as unknown, not corrupt.
- Frames (
file_entries.<path>.frame). A frame is whole (its CRS, unit, axis order, axis mapping and coordinate mode, and for a raster its pixel convention and row order) and coherent: no raster fields on a non-raster, no geoid or vertical unit without a vertical CRS, no two axes along one line, and an offset file only wherelocation.site_originis there to measure from. - ODbL roles (
file_entries.<path>.odbl_role). A vector or tabular data file (.gpkg,.shp,.geojson,.dxf,.csvand the like) is never a Produced Work, and a file whose role isnonelists no ODbL source. A missing role reads asdatabaseand is a warning, as is a file with no entry at all.
It never reprojects, and it derives no placement value: a frame is checked for being whole and self-consistent, never recomputed.
The report
--json prints one object: the input and the form it was read as, the declared manifest
version and the schema it was held to, the verdict (pass, fail or error) and its
exitCode, a status per check, the sha256 counts, and findings. Each finding has a check, a
stable code (pointer.missing, sha256.mismatch, frame.partial, …), a severity (error,
warning or info), a message, and where it applies the JSON Pointer into the manifest and the
bundle path it is about.
Reading a bundle
from mantleplace_mpb import read_bundle
with read_bundle("site-bundle.zip") as bundle: # a zip, a folder or a wrapper folder
for f in bundle.files: # every file, the manifest and README included
print(f.path, f.role, f.frame.coordinate_mode if f.frame else f.frame_problem)
mesh = bundle.placement("Site/Terrain.glb")
mesh.axis_transform # 3x3: file x, y, z onto east, north, up
mesh.offset # the site origin the file is measured from
mesh.to_enu_metres((10.0, 5.0, 20.0)) # that point, east/north/up, in metres
move = bundle.transform("Site/Terrain.glb", "Elevation/DEM.tif")
move.apply((10.0, 5.0, 20.0)) # the same point in the raster's coordinates
- Every file, with its frame and role. A
BundleFilecarriespath,size,frame,role,licenseandsources. A file the manifest has no entry for has no frame and reads asdatabase; so does a role the reader does not know (declared_rolekeeps what was written). - A frame the reader cannot read is not guessed. An axis, mode or order outside the known
sets, a missing field, or two axes on one line leaves
frameasNoneandframe_problemsaying why. The file stays in the listing;placementrefuses it. - Within one frame, the offset and axis transform.
placement(path)gives the file's axis transform, its units and, for anoffset-mode file, the site origin as itsoffset.transform(source, destination)relates two files of one frame by axes, units and that origin, added. - Never a reprojection. Files whose horizontal CRS, vertical CRS, geoid or epoch differ are in
different frames:
transformraisesFrameMismatch. An origin stated only as latitude and longitude, or in another CRS than the file's, leavesoffsetasNonewithoffset_problemsaying so. CRS references are compared as written, so acodeand a WKT2 string for one CRS are two frames to this reader. - Reading is not validating. The reader opens the manifest and the archive and fetches
nothing. Run
mpb validatefirst when the bundle is not yours.
Offline
--schema-dir DIR reads <version>.json and frozen.lock.json from a directory instead of the
network, with the same ledger check when the ledger is there. The schemas are not copied into
this repository: the published series is the one source.
The conformance corpus
The validator is held to the bundle group of the shared corpus in
tools/manifest-conformance/corpus/: each case
describes a synthetic bundle as JSON, and the runner builds it as a folder, a zip and a wrapped
zip and requires the same verdict and the same finding codes from all three.
mpb corpus tools/manifest-conformance/corpus
python -m unittest discover -s tools/mantleplace-mpb/tests # offline, no install needed
Releasing
A release is a tag. python tools/mantleplace-mpb/release_check.py holds the package version to
the newest MPB version the corpus declares a case for (the tests run it on every pull request),
and release_check.py --tag mpb-<version> holds the tag to the package. Pushing the tag
mpb-<version> runs .github/workflows/release-mpb.yml: it tests, builds, checks the
distributions and publishes them to PyPI through trusted publishing, with no token stored
anywhere. To install from a checkout instead: pip install ./tools/mantleplace-mpb.
The 2.0 naming, case and folder rules arrive with the 2.0 corpus cases.
Metadata
Release files for mantleplace-mpb 1.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mantleplace_mpb-1.14.0.tar.gz | 48.7 kB | With provenance | Details for mantleplace_mpb-1.14.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mantleplace_mpb-1.14.0-py3-none-any.whl | Python 3 | none | any | Details for mantleplace_mpb-1.14.0-py3-none-any.whl |
Total release size: 86.9 kB
Release files / mantleplace_mpb-1.14.0.tar.gz
| Download URL | mantleplace_mpb-1.14.0.tar.gz |
|---|---|
| Size | 48.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2e58c22e99dada80514c864bb998abb14fb37bda776c2f58027ae443a0f8d886
|
|
BLAKE2b-256 checksum How to use checksums |
f063ba4cfd00ec89d97e5c3bba2fc1c63f9d13df6b681810624e9c961aaf4e7b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 24, 2026.
Transparency logRelease files / mantleplace_mpb-1.14.0-py3-none-any.whl
| Download URL | mantleplace_mpb-1.14.0-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
938c84ce0bf62c2ed51465104b6ce8374d996fc3607d449c35df0950b4487ab5
|
|
BLAKE2b-256 checksum How to use checksums |
365ebb08103670e30c81fa1339817befaae05b235606165fe45592f230460c75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 24, 2026.
Transparency logSecurity for mantleplace-mpb 1.14.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for mantleplace_mpb-1.14.0.tar.gz
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 Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.