Skip to main content

terria-catalog

A Pythonic SDK for creating, modifying, validating and publishing TerriaJS initialization catalogs.

terria-catalog lets you build and edit Terria init files as strongly-typed Python objects — CatalogGroup, GeoJsonCatalogItem, WebMapServiceCatalogItem, and friends — instead of hand-editing JSON or juggling dictionaries. It mirrors Terria's own terminology and object model (derived directly from the TerriaJS source Traits classes), and produces valid Terria init JSON that is compatible with the official specification.

It is designed to be the canonical way our Digital Twin ecosystem creates and modifies catalogs stored in Amazon S3 — but it has no hard dependency on S3 (or even on any I/O): storage and serialization are cleanly decoupled and injectable.

from terria_catalog import Catalog, GeoJsonCatalogItem

catalog = Catalog.from_s3(bucket="my-bucket", key="init/catalog.json")

catalog.add(
    GeoJsonCatalogItem(
        name="Reservoirs",
        id="reservoirs",
        url="https://example.org/reservoirs.geojson",
    ),
    path="/Water Resources/Reservoirs",  # missing groups are auto-created
)

catalog.move("reservoirs", "/Water Resources")
catalog.update("reservoirs", description="Major reservoirs in the basin")
catalog.remove("some-old-dataset")

catalog.publish()  # validates, serializes, and writes back to S3

You never touch JSON. You never touch dictionaries. The JSON exists only inside the serializer.


Installation

pip install terria-catalog          # core (no cloud dependencies)
pip install 'terria-catalog[s3]'    # + boto3 for the S3 storage backend

Requires Python 3.10+.


Core concepts

Concept Type Notes
The whole init file Catalog Facade: holds the member tree, homeCamera, and other init-level properties.
A folder CatalogGroup ("group") First-class object; nestable; add/remove members through it.
A dataset CatalogItem subclasses e.g. GeoJsonCatalogItem, WebMapServiceCatalogItem.
A shared trait Rectangle, InfoSection, GeoJsonStyle, TableStyle, … Plain typed value objects.
Where it's stored StorageBackend (LocalStorage, S3Storage) Injected; the catalog doesn't care where it lives.
Turning objects into JSON TerriaJsonSerializer The only place JSON exists.

Supported item types

Fully modeled (with type-specific traits):

GeoJsonCatalogItem · WebMapServiceCatalogItem · WebMapTileServiceCatalogItem · CsvCatalogItem · ShapefileCatalogItem · CogCatalogItem · CesiumTerrainCatalogItem · Cesium3DTilesCatalogItem · IonImageryCatalogItem · ArcGisMapServerCatalogItem · ArcGisFeatureServerCatalogItem

Placeholders (correct type, traits not yet modeled — data still round-trips): KmlCatalogItem, CzmlCatalogItem, GpxCatalogItem, GltfCatalogItem, WebFeatureServiceCatalogItem, OpenStreetMapCatalogItem, MapboxVectorTileCatalogItem.

Any unknown Terria type encountered when loading a catalog becomes a GenericCatalogMember so no data is ever lost on a load/save round-trip.


The public API

Loading

from terria_catalog import Catalog

Catalog.from_s3(bucket="b", key="init/catalog.json")  # needs [s3] extra
Catalog.from_file("wwwroot/init/catalog.json")
Catalog.from_json(json_string)
Catalog()  # a new, empty catalog

Editing (paths or ids everywhere)

catalog.add(item, path="/Water Resources/Reservoirs")  # returns the item
catalog.remove("dataset-id")  # id, name, or path
catalog.update("dataset-id", description="...", opacity=0.6)
catalog.move("dataset-id", "/Infrastructure/Dams")
catalog.reorder("/Water Resources", ["reservoirs", "gauges"])

Identifiers are resolved as a path if they contain /, otherwise by id (then by name). Unknown keyword arguments to update() are stored in the member's extra mapping, so you can set traits the SDK doesn't model yet.

Groups as first-class objects

water = catalog.group("/Water Resources")  # created if missing
water.add(GeoJsonCatalogItem(name="Reservoirs", id="r", url="..."))
water.create_group("Rivers")  # idempotent
water.group("Rivers/Perennial")  # relative, auto-creating
water.remove("r")

Validation & transactions

catalog.validate()  # raises ValidationFailedError on problems
errors = catalog.validate(raise_on_error=False)

with catalog.transaction():  # atomic: rolls back on error…
    catalog.add(...)
    catalog.move(...)
    catalog.remove(...)
# …or if validation fails at the end of the block

Built-in validators cover duplicate ids, duplicate paths, invalid hierarchy, missing required properties, and unknown Terria types.

Publishing

catalog.publish()  # to the bound storage backend
catalog.publish(LocalStorage("out.json"))
catalog.to_json()  # -> str  (no I/O)
catalog.to_dict()  # -> dict (no I/O)

Safe releases: versioning, rollback & concurrency

catalog.publish() is a plain overwrite (last-write-wins). When several pipelines edit the same S3 catalog and you need rollback + a CDN cache refresh, use ReleaseManager:

from terria_catalog import ReleaseManager, S3Storage

manager = ReleaseManager(
    S3Storage("my-bucket", "init/catalog.json"),  # enable S3 bucket versioning
    cache_invalidator=my_cloudfront_invalidator,  # your CacheInvalidator impl
)

# Concurrency-safe read-modify-write: reloads & retries if another pipeline wins.
manager.update(lambda cat: cat.add(item, path="/Climate"), message="add rainfall")

# Rollback to a previous version.
versions = manager.history()  # newest first
manager.rollback(to=versions[1].version_id)

ReleaseManager.publish() validates first and returns a Release handle (ETag, version id, checksum, timestamp). Optimistic concurrency uses conditional writes (If-Match), so competing pipelines retry instead of clobbering each other. The CacheInvalidator interface is where CloudFront (or any CDN) plugs in — the library itself has no CDN dependency. Environment specifics (bucket, IAM, the actual CloudFront call) stay in your deployment code.


Use it with your AI (no JSON, no code study)

Colleagues can manage the catalog in natural language through their assistant of choice. Three surfaces, one safe tool set (validate → preview → confirm → publish, with version history and rollback):

  • MCP server — for Claude Desktop/Code, Cursor, etc. pip install 'terria-catalog[mcp]', point it at a catalog with env vars, run terria-catalog-mcp. Then just chat: "add the 2026 flood COG under Flood Forecasting and publish."
  • CLI — terria-catalog --s3 bucket/init/catalog.json add --type cog … (with --json and --dry-run), ideal for shell-driving agents.
  • Python — terria_catalog.agent.CatalogSession + run_tool / export_schemas for custom function-calling agents.

There's also a Claude Skill (skills/terria-catalog/) and a drop-in system prompt. Full guide: docs/AI_USAGE.md.

Design philosophy

  • Objects, not JSON. Consumers manipulate typed Terria objects. JSON lives only in serializers/terria_json.py.
  • Decoupled storage. The catalog talks to a StorageBackend interface; S3 is just one implementation and is imported lazily so core has no cloud deps.
  • Injectable everything. Serializer, storage, config and validators are all passed in, never hard-wired.
  • Open for extension. Adding a new item type is: create a dataclass that sets terria_type, export it, add a test. It self-registers — no serializer, registry, or facade changes required.

See docs/ARCHITECTURE.md for the full design and examples/ for runnable scripts.


Documentation

Development

pip install -e '.[dev]'
pre-commit install

ruff check . && ruff format --check .
black --check .
mypy
pytest --cov=terria_catalog

See CONTRIBUTING.md.

License

MIT © International Water Management Institute (IWMI).

Release files for terria-catalog 0.1.2

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

Source distribution (sdist)

Source distribution for terria-catalog 0.1.2
File Size Uploaded
terria_catalog-0.1.2.tar.gz 61.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for terria-catalog 0.1.2
File Interpreter ABI Platform
terria_catalog-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 131.2 kB

Release files / terria_catalog-0.1.2.tar.gz

Download URL terria_catalog-0.1.2.tar.gz
Size 61.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a8db275862df8d82fb950cac499d2c4ea8c8df031a57a10bedb44432648068cc
BLAKE2b-256 checksum
How to use checksums
c6a4fcba44c4f0dd70097833128519e7a5cde33dd041b6ca8100f584a07a9fc9
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 30, 2026.

Transparency log

Release files / terria_catalog-0.1.2-py3-none-any.whl

Download URL terria_catalog-0.1.2-py3-none-any.whl
Size 70.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fa9b9edee078a239b20b9cde3a0e0212fa28fb750f0aa40fd3ae323109a7da79
BLAKE2b-256 checksum
How to use checksums
a3b51891e150b2ae4b0cc30083638829a1ebb0c7ad9268ffe1e3357b69411069
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 30, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.0

2 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