The normalized model

Whatever version you fetch, iiisight hands you the same v3-shaped, typed, frozen model. It is a consumer subset of the Presentation API — the descriptive and structural properties a reader needs. Every collection field is a tuple that defaults to empty (never None), so traversal never trips on a missing list.

The shape

Collection ─ items ─▶ Manifest | Collection | Reference
Manifest ─ canvases ─▶ Canvas
         ─ structures ─▶ Range          (table of contents)
         ─ annotations ─▶ AnnotationPage (manifest-level, non-painting)
Canvas ─ items ─▶ AnnotationPage ─ items ─▶ Annotation ─ body ─▶ ContentResource
       ─ annotations ─▶ AnnotationPage    (non-painting: comments, tags, …)
ContentResource ─ service ─▶ ImageService

See the API reference for every field.

Traversal

manifest = iiisight.normalize(document)

for canvas in manifest.canvases:
    print(canvas.id, canvas.width, canvas.height, canvas.duration)

    # painting-annotation image bodies (derived, pure — no I/O)
    for image in canvas.images:
        print(image.id, image.format, image.width, image.height)

    # non-painting annotations (comments, captions, …)
    for page in canvas.annotations:
        for annotation in page.items:
            print(annotation.motivation, annotation.body, annotation.target)

Canvas.images and Canvas.image_service are computed properties over the parsed data — they never fetch. To load an image service’s info.json, ask the client explicitly (see Images & tiles).

Language maps

IIIF strings are language maps ({"en": ["Title"]}). iiisight wraps them in LanguageMap:

label = manifest.label
str(label)          # a display string (preferred/any language)
label.text("en")    # the English value(s), joined
label.get("fr")     # list[str] for French (empty list if absent)
label.languages()   # available language codes

Descriptive fields like label, summary, and metadata[i].value are all language maps.

References vs. embedded resources

Inside a collection or a range, an item may be a fully-embedded resource or a bare pointer. iiisight models the pointer as a Reference (id / type / label). Fetch it with client.resolve(reference) or resolve a whole collection with client.expand(...).

for item in collection.items:
    if isinstance(item, iiisight.Reference):
        manifest = await client.resolve(item)   # sync: client.resolve(item)
    else:
        manifest = item                          # already embedded

Services

Manifests, canvases, and image bodies can carry services (search, autocomplete, auth). These are parsed into Service objects on a resource’s services field, with the original JSON preserved on service.raw for specialized consumers. Image API services on a body stay typed as ImageService on ContentResource.service. See Search and Auth for the helpers that interpret them.

Descriptive properties and the source document

Beyond label/summary/metadata, every resource carries the descriptive properties the Presentation API defines: provider (a list of Agent), thumbnail (a list of ContentResource), homepage / rendering / see_also (lists of Link), part_of (a list of Reference), required_statement (a MetadataEntry), rights, behavior, and nav_date.

Each resource also keeps its source document on .raw — the JSON it was normalized from (v2 inputs are upgraded to v3 first, so raw is the v3-shaped document). This is for consumers that need the original verbatim (archiving, round-tripping a field the model doesn’t surface):

manifest.provider[0].label          # a parsed Agent's label
manifest.raw["metadata"]            # the untouched source metadata array