Skip to main content

laterite — a Rust-backed AGS4 reader, writer and validator

laterite

A Rust-backed AGS4 toolchain for the AGS4 geotechnical data format — validate, read as typed data, query, build, fix, diff, certify, and convert ↔ Excel — with a modern, born-typed polars API.

Coming from python-ags4? laterite.compat is a faithful, faster stand-in for its AGS4, check, utils and data modules — one token changes: from python_ags4 import AGS4 becomes from laterite.compat import AGS4, and your code keeps working.

ci python cov PyPI Python versions License: MIT

Install

pip install laterite                     # base AGS4 (polars + duckdb, pyarrow-free)
pip install "laterite[compat]"           # + pandas (python-ags4 drop-in) — still pyarrow-free
pip install "laterite[compat,pyarrow]"   # + the optional pyarrow accelerator (or [all])

Requires Python ≥ 3.12. The wheel is abi3, so one binary covers 3.12 / 3.13 / 3.14. Installing it also puts the lat CLI on your PATH.

The [compat] drop-in is pyarrow-free and fast on its own; adding pyarrow swaps the pandas step for pyarrow's to_pandas and unlocks the Arrow-backed string dtype — an accelerator, never a requirement.

Use

import laterite

# Validate — errors + warnings by default (FYI is opt-in)
report = laterite.validate("delivery.ags")
report.is_valid
for rule, findings in report.by_rule().items():
    print(rule, len(findings))

# Read born-typed columns: a 2DP heading is a float, a DT a datetime
ags = laterite.read("delivery.ags")
ags.groups                       # ['PROJ', 'LOCA', 'SAMP', …]
ags["LOCA"]["LOCA_GL"][0]        # → 12.3  (a polars DataFrame per group)

# SQL across groups, no conversion step
ags.sql("SELECT loca_id, count(*) FROM SAMP GROUP BY 1")

# Repair a dirty file into a fresh handle, then keep working with it
fixed = ags.fix(risky=True)      # pads short rows, transliterates non-ASCII, …

# Typed graph: PROJ → LOCA → SAMP → …
from laterite.ags4 import read_typed
for loca in read_typed("delivery.ags").locas:
    print(loca.loca_id, loca.loca_gl)

# python-ags4 drop-in — swap the import, keep your code
from laterite import compat as AGS4
tables, headings = AGS4.AGS4_to_dataframe("delivery.ags")
AGS4.dataframe_to_AGS4(tables, headings, "round-trip.ags")

read returns born-typed polars frames by default (or pandas with read(..., backend="pandas")) — both pyarrow-free, read back from a Python-owned in-memory DuckDB engine.

More than a faster python-ags4

python-ags4 is the reference Python library for AGS4 — validation plus pandas read/write — and it inspired this project. laterite matches that surface and adds a toolchain on top:

laterite python-ags4
Validate — numbered AGS4 rules ✅ ✅
Read → data frames ✅ born-typed polars or pandas pandas, all strings
Build / write AGS4 · Excel ↔ AGS4 ✅ ✅
Repair engine (fix) ✅ —
SQL across groups · revision diff ✅ —
Validity certificates (.ags.idx) ✅ —
Transport — zstd compress + age encrypt ✅ —
Typed PROJ → LOCA → SAMP graph ✅ —
pyarrow required no (optional accelerator) via pandas' own deps

Performance

Synthetic, spec-valid AGS4 from ags4-forge — the wide scaffold: 123 groups, realistic type mix, zero findings. macOS arm64, hot files, mean of 5 warm runs, python-ags4 1.2.0 vs laterite 0.12.0. Both agree on the findings.

Validation

File python-ags4 check_file laterite.validate speedup
4.9 MB 1.5 s 41 ms 36.8×
25.0 MB 3.7 s 188 ms 19.5×
103.0 MB 12.2 s 781 ms 15.7×
276.5 MB 31.4 s 2.0 s 15.9×
551.6 MB 67.1 s 4.1 s 16.4×

Read → typed — the honest comparison for real work. python-ags4 needs AGS4_to_dataframe + convert_to_numeric on every group to get numbers, and still leaves dates as text; laterite.read is born-typed, dates included.

File python-ags4 + convert_to_numeric laterite.read speedup
4.9 MB 188 ms 15 ms 12.3×
25.0 MB 785 ms 74 ms 10.6×
103.0 MB 3.2 s 300 ms 10.7×
276.5 MB 8.7 s 780 ms 11.2×
551.6 MB 18.3 s 1.6 s 11.1×

Read → strings — like for like, both returning pandas frames of text.

File python-ags4 AGS4_to_dataframe laterite.compat speedup
4.9 MB 141 ms 38 ms 3.7×
25.0 MB 672 ms 148 ms 4.6×
103.0 MB 2.7 s 589 ms 4.6×
276.5 MB 7.2 s 1.5 s 4.9×
551.6 MB 15.3 s 3.0 s 5.1×

Validation — peak RSS

File python-ags4 check_file peak RSS laterite.validate peak RSS ratio
4.9 MB 171 MB 95 MB 1.80×
25.0 MB 343 MB 175 MB 1.96×
103.0 MB 1019 MB 470 MB 2.17×
276.5 MB 2664 MB 1121 MB 2.38×

Read → typed — peak RSS

File python-ags4 + convert_to_numeric peak RSS laterite.read peak RSS ratio
4.9 MB 156 MB 95 MB 1.64×
25.0 MB 315 MB 182 MB 1.73×
103.0 MB 938 MB 505 MB 1.86×
276.5 MB 2446 MB 1266 MB 1.93×

Read → strings — peak RSS

File python-ags4 AGS4_to_dataframe peak RSS laterite.compat peak RSS ratio
4.9 MB 149 MB 198 MB 0.75×
25.0 MB 314 MB 388 MB 0.81×
103.0 MB 918 MB 1098 MB 0.84×
276.5 MB 2205 MB 2556 MB 0.86×

Peak RSS of one fresh process per cell; the ratio is python-ags4's peak over laterite's, so above 1 laterite holds less. The largest rung is time-only. Read → strings measured on the pyarrow accelerator hop.

The compat door holds more than python-ags4 — those ratios sit below 1 on purpose: that is the cost of the pandas bridge, and publishing it is the point. laterite.validate and laterite.read are the recommended paths, on memory as on time.

The time ratio holds as files grow — the gap is a constant factor, not a head start that erodes. Reproduce any of this with uv run python tools/bench-vs-python-ags4.py in the repo: it generates the rungs, verifies each against a pinned SHA-256 so a change to the generator can't move the numbers unnoticed, and prints these exact tables.

Parity + clean-room

121 / 131 of python-ags4 1.2.0's own test suite passes through laterite.compat (92 %); the 10 remaining are deliberate non-closures, documented rule by rule. A weekly job compares the two public surfaces, so a function added upstream can't quietly go missing here.

compat is a package mirroring upstream's own layout, so upstream's import shapes work with one token changed:

from python_ags4 import AGS4          # becomes:
from laterite.compat import AGS4

from python_ags4.AGS4 import AGS4_to_dataframe   # becomes:
from laterite.compat.AGS4 import AGS4_to_dataframe

AGS4, check, utils and data are real, distinct submodules — so code that depends on module identity (monkeypatching check.X and expecting AGS4 not to see it) behaves as it does upstream. from laterite import compat as AGS4 also still works: the flat namespace is unchanged.

Two caveats before you swap. No top-level python_ags4 package ships, and that is deliberate and permanent — inside this wheel it would collide with the real distribution in site-packages. So the import token changes; the rest of the line does not. And compat mirrors the library API only: python-ags4's ags4_cli command is not mirrored, because laterite ships lat instead with its own JSON shapes.

The validator is clean-room from the published AGS4 specification, not adapted from another library's source — python-ags4 is LGPL-3.0, and that separation is what lets laterite ship under MIT. Details: COMPAT.md · OBSERVATIONS.md.

One engine, every stack

laterite on PyPI is the Python surface of one Rust AGS4 engine, shared across:

Surface Package Get it
Python laterite — PyPI pip install laterite
Node.js laterite — npm npm install laterite
CLI lat bundled with this wheel
DuckDB laterite_ags4 — community extension INSTALL laterite_ags4 FROM community;
Browser @laterite/ags4-wasm — npm, or the validator + data explorer npm install @laterite/ags4-wasm

Scriptable output is byte-identical across all of them, so a CI gate and a notebook can't disagree.

Docs

Full documentation — Learn, Cookbook, Concepts, and the Python API reference — at https://docs.laterite.dev/.

Metadata

Release files for laterite 0.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for laterite 0.14.0
File Size Uploaded
laterite-0.14.0.tar.gz 846.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for laterite 0.14.0
File
laterite-0.14.0-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
laterite-0.14.0-cp312-abi3-manylinux2014_x86_64.whl CPython 3.12 abi3 Linux glibc 2.17+ x86-64 Details
laterite-0.14.0-cp312-abi3-manylinux2014_aarch64.whl CPython 3.12 abi3 Linux glibc 2.17+ ARM64 Details
laterite-0.14.0-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details

Total release size: 28.4 MB

Release files / laterite-0.14.0.tar.gz

Download URL laterite-0.14.0.tar.gz
Size 846.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a176927207958ce59173b8fb6e551546316bfcdd6a3c44c875575f415375d120
BLAKE2b-256 checksum
How to use checksums
8977d9ac64fc60c65e046c5c0373254f475a56d6fa130d69413ac2128755aa4c
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 Oct 8, 2026.

Transparency log

Release files / laterite-0.14.0-cp312-abi3-win_amd64.whl

Download URL laterite-0.14.0-cp312-abi3-win_amd64.whl
Size 7.3 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
b3347ee8ed27dd5841b034a666d75a8d27145aa5fe12ecb331a963a8031d5dbd
BLAKE2b-256 checksum
How to use checksums
ee4cd52a08390c48d6b990829ff7e25a76d017556d74c08641496053d00bd1e2
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 Oct 8, 2026.

Transparency log

Release files / laterite-0.14.0-cp312-abi3-manylinux2014_x86_64.whl

Download URL laterite-0.14.0-cp312-abi3-manylinux2014_x86_64.whl
Size 7.1 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
666a7656b74c7fb1c56b06e1f15b0784b2c10223b43a57694e115940344a9f0e
BLAKE2b-256 checksum
How to use checksums
836cd1dac7571165ac32e3bcd5ddc864119bf4ee323ef039bb52866d12f0394b
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 Oct 8, 2026.

Transparency log

Release files / laterite-0.14.0-cp312-abi3-manylinux2014_aarch64.whl

Download URL laterite-0.14.0-cp312-abi3-manylinux2014_aarch64.whl
Size 6.7 MB
Tags CPython 3.12 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
47c36382c850d36754ce0af2959429bf4906c78b436327bac41a278264c4ee9f
BLAKE2b-256 checksum
How to use checksums
22dd2fb60b97ce8327df66763671ab7aa60a4ea2f79e71fbbc4037e4f6bdc872
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 Oct 8, 2026.

Transparency log

Release files / laterite-0.14.0-cp312-abi3-macosx_11_0_arm64.whl

Download URL laterite-0.14.0-cp312-abi3-macosx_11_0_arm64.whl
Size 6.4 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
18abea14e36d1e4d24c22d44b9cb2ccf82df9b9d79b8d50d328989c10b4c936a
BLAKE2b-256 checksum
How to use checksums
2a7497ec29ed9326b3fee768a3c1c7686a62f422b3e58d284a7c71f5e17ecf91
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 Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.15.0

5 release files

0.14.1

5 release files

This release

0.14.0 This release

5 release files

0.13.0

5 release files

0.12.0

5 release files

0.11.0

5 release files

0.9.0

4 release files

0.8.0

4 release files

0.7.0

4 release files

0.6.2

4 release files

0.6.1

4 release files

0.6.0

4 release files

0.5.1

4 release files

0.5.0

4 release files

0.4.0

3 release files

0.2.0

3 release files

0.1.0

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page