terrio
Python bindings for terrio: read, write, convert and
reproject geospatial rasters, vector datasets and point clouds in pure Rust, without GDAL. Wheels need only
NumPy (and the small affine package).
pip install terrio
Coming from rasterio
rasterio scripts run with an import change: terrio.rio follows rasterio's API (datasets,
windows, CRSs, features, warping, merging, masking, warped VRTs, memory files), compared with
rasterio on real files. See Coming from rasterio.
import terrio.rio as rasterio
with rasterio.open("https://example.com/cog.tif") as src: # read lazily, by window
profile = src.profile
dem = src.read(1, out_shape=(512, 512), masked=True) # through the overviews
xarray
terrio.xarray is rioxarray's API without GDAL (pip install "terrio[xarray]"): rasters open
lazily as DataArrays with rioxarray's coordinates, attributes and encoding, and the .terrio
accessor has rioxarray's .rio methods. See xarray.
import xarray as xr
import terrio.xarray as txr
da = txr.open_rasterio("https://example.com/cog.tif", masked=True, chunks=True)
ds = xr.open_dataset("dem.tif", engine="terrio")
sub = da.terrio.clip_box(-105.5, 39.5, -105.0, 40.0, crs="EPSG:4326") # fetches its tiles only
sub.terrio.reproject("EPSG:32613", resampling="bilinear").terrio.to_raster("sub.tif", driver="COG")
Rasters
import terrio
dem = terrio.open_raster("dem.tif")
dem.width, dem.height, dem.count, dem.dtype # dtype is a NumPy name: "float32", "uint8"...
dem.crs, dem.transform, dem.bounds, dem.nodata
elevation = dem.read(1) # numpy array (rows, cols) of the raster's own dtype
everything = dem.read() # (bands, rows, cols)
# GeoTIFFs and COGs, local or remote, can be read by window: only the tiles a window needs are
# decoded, and fetched with HTTP range requests.
cog = terrio.open_raster("https://example.com/cog.tif", lazy=True)
cog.overviews # [(width, height), ...] of the overviews, largest first
tile = cog.read(1, window=(1024, 1024, 512, 512)) # (col_off, row_off, width, height)
thumb = cog.read(overview=2)
# PMTiles and MBTiles raster tiles too: zoom levels are overviews (PMTiles read in place).
tiles = terrio.open_raster("https://example.com/tiles.pmtiles", lazy=True)
out = terrio.Raster.from_array(elevation * 3.28084, dem.transform, crs=dem.crs, nodata=dem.nodata)
out.write("dem_feet.tif", compress="DEFLATE")
out.write("dem_feet_cog.tif", driver="COG")
out.write("dem.zarr", options={"FORMAT": "ZARR_V3", "GEOREFERENCING_CONVENTION": "SPATIAL_PROJ"}) # GeoZarr
# STAC: a mosaic of an asset over a search's items (or an item's asset, 'STAC:"item.json":red'), read by window.
red = terrio.open_raster('STACIT:"https://earth-search.aws.element84.com/v1/search?collections=sentinel-2-l2a&bbox=-105.05,40.5,-104.95,40.6&datetime=2023-07-05":asset=red', lazy=True)
terrio.open_raster("landsat.tif").write("landsat.pmtiles") # Byte rasters as tiles (or .mbtiles)
Vector data
ds = terrio.open_vector("countries.gpkg") # or .shp, .geojson, .fgb, .parquet, .kml, .zip...
layer = ds.layers[0] # also ds["countries"]
layer.name, layer.crs, layer.geometry_type, layer.fields, len(layer), layer.bounds
collection = layer.to_geojson() # a GeoJSON FeatureCollection dict
wkb = layer.to_wkb() # one WKB geometry per feature
columns = layer.columns() # attribute values by field
gdf = layer.to_geopandas() # with geopandas installed
terrio.write_vector(layer.to_crs("EPSG:3857"), "countries_3857.fgb")
terrio.write_vector(collection, "countries.geojson") # GeoJSON dicts, GeoDataFrames...
Point clouds
LAS 1.0 to 1.4 (point formats 0 to 10, extra bytes, waveforms), LAZ, COPC, EPT, PLY and E57.
Remote COPC files and EPT datasets are read in place: only the octree nodes a read needs are
fetched. Files larger than memory are read and written in chunks (PointCloudFile.chunks,
PointCloudWriter); PDAL's filters (smrf, outlier, range, sample, voxel_downsize,
voxel_center_nearest_neighbor) and TIN and nearest-neighbour gridding are PointCloud
methods.
f = terrio.open_points("https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz")
f.format, f.point_count, f.crs, f.bounds, f.header, f.dimensions
f.info(stats=True) # the summary `terrio info --json --stats` prints: classes, returns...
points = f.read(bounds=(637000, 851000, 637500, 851500), max_level=4) # or resolution=, max_points=
points = terrio.read_points("tile.laz", classes=[2], returns=["last", "only"])
z = points["z"] # NumPy arrays: x, y, z (scaled float64), intensity (uint16), classification...
points.to_dict() # {name: array}
points.to_numpy() # a structured array
points.write("ground.copc.laz") # LAS, LAZ, COPC, PLY or E57
dem = points.grid(1.0, stat="idw") # a Raster (min, max, mean, idw, count, stdev; like PDAL)
points.to_layer(dimensions=["z", "intensity"]).to_geopandas()
terrio.convert_points("tile.laz", "tile_wgs84.laz", t_srs="EPSG:4326")
terrio.convert_points("tile.laz", "ground.gpkg", classes=[2]) # a layer of points
terrio.PointCloud.from_dict({"x": xs, "y": ys, "z": zs, "intensity": i}, crs="EPSG:32610")
Operations
The operations take the command-line options as keyword arguments. Inputs are paths or objects in memory; outputs are returned, and also written when a destination is given.
terrio.info("dem.tif", stats=True) # the same dict as `terrio info --json`
terrio.convert("countries.shp", "europe.gpkg", where="CONTINENT = 'Europe'", select=["NAME"])
terrio.convert("https://example.com/cog.tif", "window.tif", srcwin=(0, 0, 512, 512))
terrio.translate("dem.tif", "small.tif", outsize=("25%", "25%"), resampling="average")
terrio.warp("dem.tif", "dem_4326.tif", t_srs="EPSG:4326", resampling="bilinear")
terrio.mosaic(["n40w106.tif", "n40w107.tif"], "mosaic.tif")
terrio.rasterize("counties.gpkg", "pop.tif", attribute="POPULATION", tr=(0.01, 0.01), ot="Int32")
polygons = terrio.polygonize("landcover.tif", connectedness=8)
shade = terrio.dem("dem.tif", "hillshade", z=2, multidirectional=True) # like gdaldem
terrio.dem("dem.tif", "color-relief", "relief.tif", color_file="colors.txt", alpha=True)
ndvi = terrio.calc("(B - A * 1.0) / (B + A * 1.0)", A="landsat.tif", A_band=3, B="landsat.tif", B_band=4,
type="Float32") # like gdal_calc.py, with NumPy's typing rules
dist = terrio.proximity("roads.tif", values=[1], distunits="GEO")
clean = terrio.sieve("landcover.tif", threshold=10, connectedness=8)
xs, ys = terrio.transform_points([699960], [3900000], "EPSG:32610", "EPSG:4326")
data = open("dem.tif", "rb").read()
raster = terrio.open_bytes(data, "dem.tif") # from bytes; to bytes with raster.to_bytes("x.tif")
Errors raise terrio.TerrioError subclasses, which also derive from the matching built-in
exceptions: NotFoundError is a FileNotFoundError, TerrioIOError an OSError, and
InvalidArgumentError, CRSError, UnsupportedError and InvalidDataError are ValueErrors.
Development
cd python
uv venv && uv pip install maturin numpy pytest
uv run maturin develop
uv run pytest # synthetic tests
TERRIO_TEST_DATA=../../terrio-data uv run pytest # real files, compared with GDAL when installed
Metadata
Release files for terrio 0.2.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 | |
|---|---|---|---|
| terrio-0.2.0.tar.gz | 1.3 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| terrio-0.2.0-cp310-abi3-win_arm64.whl | CPython 3.10 | abi3 | Windows ARM64 | Details |
| terrio-0.2.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| terrio-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| terrio-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ ARM64 | Details |
| terrio-0.2.0-cp310-abi3-manylinux_2_28_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| terrio-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| terrio-0.2.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| terrio-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 120.0 MB
Release files / terrio-0.2.0.tar.gz
| Download URL | terrio-0.2.0.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8fe05401b26d832964826e0a48a2b2b71936bc6288c28ee0f4b511b32671fb23
|
|
BLAKE2b-256 checksum How to use checksums |
0a4f137c07c3879f48b2d9c316c010fa4ae4f52d4427fbd3df3ed65777172c15
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-win_arm64.whl
| Download URL | terrio-0.2.0-cp310-abi3-win_arm64.whl |
|---|---|
| Size | 13.0 MB |
| Tags | CPython 3.10 Windows ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
fcee8f182e694e638ec2831221e33c90fd6fb46b06d2d95d7896f2a1b83358f5
|
|
BLAKE2b-256 checksum How to use checksums |
7c914541042857b17639883f8dd8609b49bb7b46151f6e11427aa9308553a891
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-win_amd64.whl
| Download URL | terrio-0.2.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 13.9 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
5043a7a0388389c45dc08b24fd01fd588542c314e6f1f82c0abbe16e40a9a0c0
|
|
BLAKE2b-256 checksum How to use checksums |
15cb27d4d378ba012618cb6a241ad174586dc53411f8ccbe178caeaac3224569
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | terrio-0.2.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 16.4 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
b8d21a3c634265440b9fa6b5c518c73ecfb6e36d909a7a32c157f3512c2451c6
|
|
BLAKE2b-256 checksum How to use checksums |
93dffd99172aa64debb058490d4c259c7c22d6f151f64f9ded9a6875899ead9a
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl
| Download URL | terrio-0.2.0-cp310-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 15.7 MB |
| Tags | CPython 3.10 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
a6d06a00c921496d685299f9f72c8b1a2612cdcbf2500dc8a2250dac99cbf485
|
|
BLAKE2b-256 checksum How to use checksums |
562c5ca1abf569fe34348585b0ad61c18cc645ec9e1af6c594179d59664d7d66
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-manylinux_2_28_aarch64.whl
| Download URL | terrio-0.2.0-cp310-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 15.5 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
8b55de3692feb898e42f1eab46055dcd966a91f809cb919a01b9f49682d40119
|
|
BLAKE2b-256 checksum How to use checksums |
c8acd6f1dac907de9d4ffc7c996cb3f148caf214e9fa75cb77000164875d3aca
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | terrio-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 15.5 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
b8bd1eeaf231a58533c1225d6919e6c2734f0f37bbc9a4204947e6bab990e8d3
|
|
BLAKE2b-256 checksum How to use checksums |
88606a3f48d51c7e89615f5f297a07e93659f3889a5c63b84d44a0ba003e22c4
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | terrio-0.2.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 14.0 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
29582c270a6705defddfc5528b7843b8c04f4debef2b4ddea279dbe93ad2a916
|
|
BLAKE2b-256 checksum How to use checksums |
c18a84023f4d7c9975509b693803c13853f78e3dac1bc6d5145c1469d21be5e6
|
| 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 15, 2026.
Transparency logRelease files / terrio-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | terrio-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 14.6 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
6d3708c2567048a6d1ea9649fd65959776574b874337f8eb8bd0954ade91b04a
|
|
BLAKE2b-256 checksum How to use checksums |
d403e1e97cda62ec87dc81b6e74200d9815dec342226317711b99994b7ed4022
|
| 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 15, 2026.
Transparency log