Validation of EO assets: stac-validator, rio-cogeo, geometry checks and
tolerance regression tests.
The cross-cutting layer, made a repository. Unglamorous, heavily reused.
src/eo_qa/
stac.py catalog validation
cog.py internal structure, overviews
geometry.py is_valid + repair
regression.py <- the component that gives it value
lineage.py scene -> product -> conclusion
Reprojection, resampling and correction introduce legitimate numerical drift. The tests compare against a declared tolerance, not exact equality. Without this there is no way to know whether a change in SAR preprocessing broke the optical index.
Core install (numpy + pyyaml only — everything tested here runs on this):
pip install -e ".[dev]"The heavy operational stack (stac-validator, rio-cogeo, rasterio, shapely,
pystac-client) is optional and imported lazily inside the file/schema wrappers:
pip install -e ".[full]"Tolerance regression — the component that gives this repo its value:
python -c "import numpy as np; from eo_qa.regression import assert_close; \
assert_close(np.array([1.0, 2.0]), np.array([1.0, 2.0000001]), rtol=1e-5, atol=1e-8); \
print('within tolerance')"Report worst-case drift, validate a ring, or build a provenance chain:
from eo_qa.regression import max_drift
from eo_qa.geometry import is_valid, repair
from eo_qa.lineage import LineageBuilder
print(max_drift([100.0], [101.0])) # max_abs=1 max_rel=0.009901
print(is_valid(repair([[0, 0], [1, 0], [1, 1], [0, 1]]))) # True
lineage = (
LineageBuilder()
.from_scene("S1A_20240101", sensor="Sentinel-1", datetime="2024-01-01T06:00:00Z")
.derive("coh_20240101", process="insar-coherence", window=5)
.conclude("subsidence detected", confidence=0.9)
.build()
)
print(lineage.to_yaml())Run the test suite:
pytest -qMIT.