Module adcp.canonical_formats.registry

v1↔v2 canonical mapping registry loader + matchers.

Implements the registry contract from registries/v1-canonical-mapping.json. Two match modes:

  • Glob — exact / wildcard match against a v1 format_id.id value. As of 3.1 the registry carries zero literal entries; the AAO-published IAB-standard formats project via catalog canonical: annotations (resolution-order step 2). The matcher is implemented to handle * wildcards anywhere in the pattern so future literal entries work without further code change.
  • Structural — match against the v1 format's slot shape, asset types, and VAST/DAAST version constraints. The primary fallback for v1 wire traffic.

Directional invariant: this registry is authoritative for v1 → v2 projection only. The v2 → v1 path in :mod:adcp.canonical_formats.v2_to_v1 does NOT consult the registry; it relies on the seller-asserted v1_format_ref[] on the v2 declaration.

Functions

def glob_match(value: str, pattern: str) ‑> bool
Expand source code
def glob_match(value: str, pattern: str) -> bool:
    """Glob-match ``value`` against a registry ``format_id_glob`` pattern.

    Per the registry schema: ``*`` matches any segment. Patterns are
    compared against the v1 ``format_id.id`` (NOT the ``{agent_url, id}``
    pair — the registry mantra is family identification, not full
    namespace resolution).

    Treats ``*`` as a permissive wildcard (any chars including ``_``).
    Other regex metacharacters are escaped — the pattern language is
    glob, not regex.

    .. note::
       **Experimental.** This helper is unused on the v2 → v1 path (the
       registry is consulted only on the v1 → v2 inbound path, which
       lands in #741's second PR). The signature may shift when that
       path consumes it; adopters SHOULD pin to the SDK release they
       integrate against.
    """
    if pattern == "*":
        return True
    regex = "^" + re.escape(pattern).replace(r"\*", ".*") + "$"
    return re.fullmatch(regex, value) is not None

Glob-match value against a registry format_id_glob pattern.

Per the registry schema: * matches any segment. Patterns are compared against the v1 format_id.id (NOT the {agent_url, id} pair — the registry mantra is family identification, not full namespace resolution).

Treats * as a permissive wildcard (any chars including _). Other regex metacharacters are escaped — the pattern language is glob, not regex.

Note

Experimental. This helper is unused on the v2 → v1 path (the registry is consulted only on the v1 → v2 inbound path, which lands in #741's second PR). The signature may shift when that path consumes it; adopters SHOULD pin to the SDK release they integrate against.

def load_default_registry() ‑> adcp.types.generated_poc.registries.v1_canonical_mapping.V1V2CanonicalFormatMappingRegistry
Expand source code
def load_default_registry() -> V1V2CanonicalFormatMappingRegistry:
    """Load and parse the AAO-published v1↔v2 mapping registry.

    Returns a fresh deep copy of the cached parsed registry — callers
    can safely mutate the returned instance without affecting other
    callers in the same process. The underlying parsed registry is
    cached per process (the registry is immutable for a given SDK
    build, keyed by ``ADCP_VERSION``).

    .. note::
       **Experimental.** The registry is consulted only on the v1 → v2
       inbound path (lands in #741 part 2). Adopters using this helper
       to inspect the bundled mappings SHOULD pin to the SDK release
       they integrate against; the return shape may sharpen when the
       inbound consumer lands.

    Raises:
        RegistryLoadError: when the bundle is missing, malformed JSON,
            or fails schema validation.
    """
    return _load_registry_uncopied().model_copy(deep=True)

Load and parse the AAO-published v1↔v2 mapping registry.

Returns a fresh deep copy of the cached parsed registry — callers can safely mutate the returned instance without affecting other callers in the same process. The underlying parsed registry is cached per process (the registry is immutable for a given SDK build, keyed by ADCP_VERSION).

Note

Experimental. The registry is consulted only on the v1 → v2 inbound path (lands in #741 part 2). Adopters using this helper to inspect the bundled mappings SHOULD pin to the SDK release they integrate against; the return shape may sharpen when the inbound consumer lands.

Raises

RegistryLoadError
when the bundle is missing, malformed JSON, or fails schema validation.
def structural_match(*,
asset_types: list[str],
vast_versions: list[str] | None = None,
daast_versions: list[str] | None = None,
width: int | None = None,
height: int | None = None,
pattern: Any) ‑> bool
Expand source code
def structural_match(
    *,
    asset_types: list[str],
    vast_versions: list[str] | None = None,
    daast_versions: list[str] | None = None,
    width: int | None = None,
    height: int | None = None,
    pattern: Any,
) -> bool:
    """Check whether a v1 format's structural shape matches a registry entry.

    ``pattern`` is the registry entry's ``structural`` block (a
    :class:`adcp.types.V1CanonicalStructural` or equivalent dict). All
    constraints declared on the pattern MUST match; constraints absent
    from the pattern do not narrow the match.

    Args:
        asset_types: Asset types appearing in the v1 format's slots.
            The pattern's ``asset_types`` is a *subset* requirement —
            every type the pattern lists must be present in ``asset_types``.
        vast_versions: VAST version(s) declared on the v1 format (typically
            a single value like ``"4.2"``). Each must satisfy at least one
            constraint in the pattern's ``vast_versions`` list.
        daast_versions: DAAST version(s); same matching semantics as VAST.
        width: Slot dimension width (pixels), if applicable.
        height: Slot dimension height (pixels), if applicable.
        pattern: The registry entry's ``structural`` block.

    Returns:
        ``True`` iff every constraint declared on ``pattern`` is satisfied
        by the v1 format's structural shape.

    .. note::
       **Experimental.** Same caveat as :func:`glob_match` — the v1 → v2
       inbound consumer lands in the second half of #741.
    """
    if hasattr(pattern, "model_dump"):
        p = pattern.model_dump(exclude_none=True)
    else:
        p = dict(pattern) if pattern else {}

    want_types = p.get("asset_types")
    if want_types:
        for t in want_types:
            if t not in asset_types:
                return False

    want_vast = p.get("vast_versions")
    if want_vast:
        if not vast_versions:
            return False
        if not any(_versions_overlap(v, want_vast) for v in vast_versions):
            return False

    want_daast = p.get("daast_versions")
    if want_daast:
        if not daast_versions:
            return False
        if not any(_versions_overlap(v, want_daast) for v in daast_versions):
            return False

    want_dims = p.get("dimensions") or {}
    if want_dims.get("width") is not None and want_dims["width"] != width:
        return False
    if want_dims.get("height") is not None and want_dims["height"] != height:
        return False

    return True

Check whether a v1 format's structural shape matches a registry entry.

pattern is the registry entry's structural block (a :class:adcp.types.V1CanonicalStructural or equivalent dict). All constraints declared on the pattern MUST match; constraints absent from the pattern do not narrow the match.

Args

asset_types
Asset types appearing in the v1 format's slots. The pattern's asset_types is a subset requirement — every type the pattern lists must be present in asset_types.
vast_versions
VAST version(s) declared on the v1 format (typically a single value like "4.2"). Each must satisfy at least one constraint in the pattern's vast_versions list.
daast_versions
DAAST version(s); same matching semantics as VAST.
width
Slot dimension width (pixels), if applicable.
height
Slot dimension height (pixels), if applicable.
pattern
The registry entry's structural block.

Returns

True iff every constraint declared on pattern is satisfied by the v1 format's structural shape.

Note

Experimental. Same caveat as :func:glob_match() — the v1 → v2 inbound consumer lands in the second half of #741.

Classes

class RegistryLoadError (*args, **kwargs)
Expand source code
class RegistryLoadError(RuntimeError):
    """Raised when the bundled v1↔v2 registry cannot be loaded or parsed.

    Wraps the underlying :class:`FileNotFoundError`,
    :class:`json.JSONDecodeError`, or :class:`pydantic.ValidationError`
    with a contextual message naming the registry path + ADCP version so
    adopters can diagnose a corrupt bundle.
    """

Raised when the bundled v1↔v2 registry cannot be loaded or parsed.

Wraps the underlying :class:FileNotFoundError, :class:json.JSONDecodeError, or :class:pydantic.ValidationError with a contextual message naming the registry path + ADCP version so adopters can diagnose a corrupt bundle.

Ancestors

  • builtins.RuntimeError
  • builtins.Exception
  • builtins.BaseException