Skip to main content

A tolerant, async (and sync) Python client for consuming IIIF.

Project description

iiisight

Goal: a reusable Python package for building applications that consume IIIF — the read-side substrate for viewers, search, harvesting, and conformance tooling.

A tolerant, async Python client for consuming IIIF. Fetch a manifest or collection, normalize v2→v3 so you work against one model, walk canvases / ranges / annotations, and pull tile-aware image regions — behind a single typed interface.

Why

Python's IIIF tooling is real but fragmented — split by concern and by spec version, and all of it synchronous:

  • iiif-prezi3 is the construction library — it builds (and can load static) Presentation v3 documents. It doesn't fetch from URLs, doesn't handle v2, isn't async, and offers no traversal or Image API helpers.
  • piffle parses/builds Image API URLs and can from_url() a manifest and iterate canvases — the closest thing to a client — but it's sync, does no v2→v3 normalization, has thin range/annotation traversal, and stops short of tile-aware region math.
  • iiif-prezi (v2 reference) and prezi-2-to-3 (standalone v2→v3 upgrade) cover the older version and the upgrade in isolation.

Every piece exists somewhere; no single library assembles them for a consumer. There is no async, tolerant, version-agnostic read model with tile-aware retrieval — the shape the JS ecosystem gets from @iiif/parser. That integration is the gap iiisight fills. Two of its capabilities — async fetching and tile-aware Image API retrieval — exist nowhere else in Python today.

Positioning

iiisight's identity is the read/consume side of IIIF, done well in one place. Overlapping existing tools is fine — even desirable — when consolidating a capability into the same tolerant, async client makes it better or cheaper than today's fragmented status quo. The test for pulling something in is not "does another tool already do this?" but "does iiisight's existing machinery make the unified version genuinely better, and does it stay read-shaped?" By that test an Image API conformance probe (we already fetch info.json and build region requests) and a consumer-oriented manifest lint (our normalizer already locates every deviation it repairs) are natural extensions, not scope creep.

Reuse vs. reinvent is then a pure engineering call, not deference: reuse (e.g. iiif-prezi3's v3 types, prezi-2-to-3's upgrade) when the dependency is clean and saves maintenance; own the layer when its constraints — sync, write-oriented model, low tolerance — would cap how good the unified tool can be. Consolidating "better in one place" will often favor owning more of the stack so tolerance, async, and diagnostics stay first-class.

Design pillars

  • Read-first — consuming IIIF, not authoring it. Building manifests is iiif-prezi3's job.
  • Async-first, sync-supported — non-blocking fetches for manifests, collections, info.json, and tiles (httpx), with a first-class sync Client for the many GLAM/library-tech consumers on sync stacks. Both share one pure, I/O-free core.
  • Tolerant — accept real-world, spec-imperfect documents; degrade gracefully instead of raising on the first surprise.
  • Normalized — present one model regardless of source version; upgrade Presentation v2 → v3 under the hood.
  • Ergonomic traversal — walk collections → manifests → canvases → ranges → annotations without hand-parsing JSON-LD.
  • Tile-aware Image API — read a service's info.json and compute correct region/size/tile requests rather than fetching full-resolution images.

IIIF API coverage

IIIF is a family of six APIs. As a consume-side client, iiisight can support all of them to varying depth — core delivery now, the rest as read-shaped layers over the same machinery:

IIIF API Stable iiisight support Tier
Presentation 3.0 (4.0 RC) Full — fetch, tolerant parse, v2→v3 normalize, traverse Core
Image 3.0 (+2.x) Full — info.json parse, URL build/parse, tile-aware retrieval Core
Content Search 2.0 (+1.0) Issue search to the service, parse hits as annotations (reuses our model) Extension
Content State 1.0 Decode/encode a resource/region reference, resolve → fetch Extension
Change Discovery 1.0 Consume Activity-Streams OrderedCollection for harvesting/sync Adjacent
Auth Flow 2.0 (+1.0) Partial — model the auth services + drive a non-interactive token flow; interactive login stays the host app's job Later

Version handling: Presentation 2.0/2.1 → normalized to 3.0; the 4.0 release candidate informs forward-compatible modeling but 3.0 is the normalization target until 4.0 is stable. Image API 2.x and 3.0 URL/info.json syntaxes are both understood.

Two honest boundaries: Auth is inherently partial for a library — the interactive login step needs a browser/UI only the host app can own. And server sides stay out — iiisight is a client of Image / Search / Auth endpoints, never an implementation of one.

Validation & conformance

Overlap here is welcome, built as optional layers over the same client once the core read path is solid — not as separate tools:

  • Image API conformance probe — the natural fit, because Image API validation is a client making requests to a service, which iiisight's tile-aware layer already does. A strict "probe this endpoint against its claimed compliance level" mode reuses the fetch machinery directly.
  • Consumer-oriented manifest lint — a byproduct of tolerance: the normalizer records structured diagnostics (missing field → assumed default, wrong type → coerced, v2 → upgraded, bad URL → skipped) as it repairs a document, so it can report "what a real client had to guess or fix to read this." This is client-compatibility feedback, distinct from (and complementary to) strict spec conformance.

The client core stays tolerant; validation is a separate reporting posture over the same parse, never a stricter default that would make the client reject real-world documents.

Non-goals

The one deliberate exclusion is authoring — building and serializing new manifests is a different posture (write vs. read) and audience; iiif-prezi3 owns it and iiisight stays a consumer. iiisight is likewise a client of Image / Search / Auth endpoints, never a server implementation of any of them.

Distribution

iiisight is a pure-Python library published to PyPI — no compiled extensions, so it installs as a single universal wheel everywhere Python runs:

pip install iiisight
  • Library-first, not an application or service: you import iiisight and bring your own event loop; there is no server or daemon.
  • Lean footprint — one runtime dependency (httpx). Optional features live behind extras, e.g. iiisight[prezi3] (iiif-prezi3 interop) and iiisight[cli] (a thin command-line front-end).
  • Optional CLI — the reporting layers make natural commands via [project.scripts]: iiisight lint <manifest-url>, iiisight probe <image-service>, shipped under the cli extra so the core stays a pure library.
  • Releases are git-tag driven (setuptools-scm → python -m build → OIDC trusted publishing); see CLAUDE.md.

Usage

Full documentation — installation, a quickstart, task-oriented guides, and the API reference — lives on Read the Docs. A tour of the main workflows follows; everything is available in both async (flagship) and sync forms — AsyncClient / Client mirror httpx's naming, and every await client.… has a no-await twin.

Fetch and traverse

import iiisight

async with iiisight.AsyncClient() as client:
    manifest = await client.fetch_manifest("https://example.org/manifest.json")
    print(str(manifest.label))                       # LanguageMap -> display string
    for canvas in manifest.canvases:
        print(canvas.width, canvas.height, [img.id for img in canvas.images])
    for entry in manifest.structures:                # ranges / table of contents
        print(str(entry.label))

# sync equivalent — same methods, no await
with iiisight.Client() as client:
    manifest = client.fetch_manifest("https://example.org/manifest.json")

v2 and v3 manifests normalize to the same model; a v2 document is upgraded under the hood. Network I/O is always explicit — expand() resolves a collection's references, load_info() fetches an image service's info.json:

collection = await client.fetch_collection("https://example.org/collection.json")
manifests = await client.expand(collection)          # fetch referenced manifests

Tile-aware Image API retrieval

service = await client.load_info(manifest.canvases[0])   # fetch info.json
service.url(region="full", size="max")                   # spec-correct Image API URL
service.thumbnail_url(width=400)                          # prefers an advertised size
for tile in service.tile_grid(scale_factor=4):           # a full tile grid at a zoom
    print(tile.region, tile.size, tile.url)
data = await client.fetch_region(service, region="0,0,512,512", size="256,")

Content Search

page = await client.search(manifest, "cathedral")        # discovers the search service
for hit in page.items:
    print(hit.target, hit.body)

Content State

state = iiisight.content_state.decode(token)             # bare URI, JSON, or base64url
doc = await client.resolve(state.reference)              # fetch what it points at
token = iiisight.content_state.encode("https://example.org/canvas/1", region="xywh=0,0,50,50")

Auth Flow 2.0 (metadata + non-interactive)

probe = iiisight.find_probe_service(manifest.canvases[0])
if probe:                                                # resource is access-controlled
    result = await client.probe(probe)                   # check access
    if not result.accessible and probe.token_service:
        token = await client.access_token(probe.token_service)   # non-interactive only
        result = await client.probe(probe, token=token.access_token)

Interactive browser login is the host application's job; iiisight supplies the service metadata to drive it.

Lint

report = iiisight.lint(manifest)          # what a real client had to repair
print(report.summary())                   # "1 error(s), 2 warning(s), 3 info"
for problem in report.errors + report.warnings:
    print(problem.severity, problem.code, problem.path, problem.message)

Status

Working, pre-1.0 (see PLAN.md for phase-by-phase status). Done: the tolerant normalizer + typed model, the v2→v3 upgrade, async/sync fetch clients, tile-aware Image API retrieval (validated against live servers), Content Search, Content State, Auth Flow 2.0, and the consumer lint. Still to come: the Image API conformance probe, Change Discovery, an optional CLI, and the first PyPI release (the name iiisight is available). The public API may still change before 1.0.

License

Apache-2.0 — see LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iiisight-0.1.tar.gz (88.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iiisight-0.1-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

File details

Details for the file iiisight-0.1.tar.gz.

File metadata

  • Download URL: iiisight-0.1.tar.gz
  • Upload date:
  • Size: 88.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for iiisight-0.1.tar.gz
Algorithm Hash digest
SHA256 22ac17b5172f37cac3521ef96910983499cb81895607638ecdb9c8ec601a83a9
MD5 7cc9e16332536eabb5bd2304f639f541
BLAKE2b-256 9d01706e6d8a7ba2fbcb3b334063a03a36332828b711667cfa2a8fd4717f05d1

See more details on using hashes here.

File details

Details for the file iiisight-0.1-py3-none-any.whl.

File metadata

  • Download URL: iiisight-0.1-py3-none-any.whl
  • Upload date:
  • Size: 39.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for iiisight-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2e693fd8f4916b42509f73933858be41a59889fa88c6f70eea63366c24981070
MD5 4c95249987ed2545c150117031d159aa
BLAKE2b-256 9a1e45b7c9b5d8096d4df5b69f8f2ed79d0d7371914f32b413d3ee641202622b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page