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.idvalue. As of 3.1 the registry carries zero literal entries; the AAO-published IAB-standard formats project via catalogcanonical: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 NoneGlob-match
valueagainst a registryformat_id_globpattern.Per the registry schema:
*matches any segment. Patterns are compared against the v1format_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 TrueCheck whether a v1 format's structural shape matches a registry entry.
patternis the registry entry'sstructuralblock (a :class:adcp.types.V1CanonicalStructuralor 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_typesis a subset requirement — every type the pattern lists must be present inasset_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'svast_versionslist. 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
structuralblock.
Returns
Trueiff every constraint declared onpatternis 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.ValidationErrorwith a contextual message naming the registry path + ADCP version so adopters can diagnose a corrupt bundle.Ancestors
- builtins.RuntimeError
- builtins.Exception
- builtins.BaseException