diff --git a/AGENTS.md b/AGENTS.md index d098a09b..d84218a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -219,6 +219,11 @@ from adcp import ADCPClient, ADCPMultiAgentClient, AgentConfig # Request/response types from adcp.types import GetProductsRequest, CreateMediaBuyRequest, Product, Package +# Or import from a curated partial module for a narrower surface: +# adcp.types.media_buy / creative / signals / protocol / buyer / seller +from adcp.types.media_buy import CreateMediaBuyRequest +# Never import from adcp.types.generated_poc.* or adcp.types._generated (internal) + # Response variant types (discriminated unions) from adcp.types.aliases import CreateMediaBuySuccessResponse, CreateMediaBuyErrorResponse diff --git a/CLAUDE.md b/CLAUDE.md index 7092f68e..2f109cb5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,17 +27,27 @@ _generated.py (internal consolidation) ↓ aliases.py + capabilities.py + _ergonomic.py + _forward_compat.py ↓ -__init__.py (user-facing exports) +_eager.py (binds the full public surface; runs import-time patching) + ↓ +__init__.py (thin lazy facade; user-facing exports via PEP 562 __getattr__) ``` +`adcp.types/__init__.py` is a lazy facade (PEP 562): `import adcp.types` is +cheap, and the generated Pydantic graph is built on first access to a type +symbol, by importing `_eager.py` (the former eager `__init__` body). The +runtime `__getattr__`/`__dir__` live under `if not TYPE_CHECKING:` so type +checkers see the surface only via the explicit `TYPE_CHECKING` re-export block +— a typo'd import is flagged, not silently typed as `object`. + Only these modules may import from `generated_poc/` or `_generated.py` (enforced by `tests/test_import_layering.py`): - `_generated.py`: Consolidates exports from `generated_poc/` into a flat namespace +- `_eager.py`: Eager realization of the public surface — binds every exported name and runs the import-time patchers (`_ergonomic`, `_forward_compat`) - `aliases.py`: Creates semantic aliases for numbered discriminated union types - `capabilities.py`: Re-exports `get_adcp_capabilities_response` sub-models with disambiguated names - `_ergonomic.py`: Applies BeforeValidator coercion for type ergonomics - `_forward_compat.py`: Patches `Format.assets` / `RepeatableAssetGroup.assets` with open union types at import time -- `__init__.py`: Public API surface +- `__init__.py`: Public API surface (thin lazy facade) All other source code should import from `adcp.types` (the public API). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0261bbda..4f2232b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,6 +85,58 @@ src/adcp/ - `tests/type_checks/` is the adopter-facing type contract suite. Fixtures must pass `mypy --strict` without `# type: ignore` suppressions. +### Adding a public type/export + +`adcp` and `adcp.types` are lazy (PEP 562): `import adcp` is ~2ms and does not +build the generated Pydantic graph or import the client. The first access to any +AdCP type builds the full graph once (~1s per process). The runtime resolution +lives in a `__getattr__` under `if not TYPE_CHECKING:`; type checkers see the +surface only through an explicit `TYPE_CHECKING` re-export block. Because of that +split, a new public export must be added in **both** places — the lazy runtime +map and the `TYPE_CHECKING` block — or it silently breaks lazy resolution or +type-checker visibility. See the "Import Architecture for Generated Types" section +in `CLAUDE.md` for the layering this protects. + +Pick the surface you are adding to: + +- **Top-level `adcp` export** (`from adcp import Foo`): add the name to the owning + module's tuple in `_LAZY_MODULES`, to the matching `from import (...)` + block under `TYPE_CHECKING`, and to `__all__` — all three in + `src/adcp/__init__.py`. + +- **`adcp.types` export** (`from adcp.types import Foo`): the name is bound in + `src/adcp/types/_eager.py` (the eager body that realizes the graph). In + `src/adcp/types/__init__.py`, add it to `__all__` and to the `from + adcp.types._eager import (...)` block under `TYPE_CHECKING`. If it is an internal + re-export helper that is intentionally *not* in `__all__`, add it to + `_EAGER_ONLY_EXTRAS` instead (this constant must match `_eager`'s namespace + exactly). + +- **Curated partial module** (`adcp.types.media_buy`, `creative`, `signals`, + `protocol`, `buyer`, `seller`): add the name to that module's `__all__` and its + `from adcp.types import (...)` block under `TYPE_CHECKING`. The name must already + be exported from `adcp.types` — partial modules only re-curate that surface; they + never import the generated layer. + +Never import from `adcp.types.generated_poc.*` or `adcp.types._generated` outside +the allowlisted layering modules (`_generated.py`, `aliases.py`, `_ergonomic.py`, +`_forward_compat.py`, `capabilities.py`, `canonical_decl.py`, `_eager.py`, and +`types/__init__.py`). The generated class names are unstable across schema regen. + +After an intentional change to `adcp.__all__` or `adcp.types.__all__`, regenerate +the public-API snapshot: + +```bash +python scripts/regenerate_public_api_snapshot.py +``` + +These guards enforce the contract and run in `make ci-local`: + +- `tests/test_import_layering.py` — no new module may import the generated layer. +- `tests/test_lazy_types.py` — lazy/eager parity, fast-fail on unknown names, and + `_EAGER_ONLY_EXTRAS` matching `_eager`. +- `tests/test_public_api.py` — the public-API snapshot. + ### Documentation - Add docstrings to all public functions - Use Google-style docstrings diff --git a/MIGRATION_v3_to_v4.md b/MIGRATION_v3_to_v4.md index c6c39ef6..7e22b7e6 100644 --- a/MIGRATION_v3_to_v4.md +++ b/MIGRATION_v3_to_v4.md @@ -482,6 +482,14 @@ from adcp.types import ContextObject, TargetingOverlay top-level surface, check `from adcp.types import X` first — most generated types are re-exported there. +For a narrower import surface, six curated partial modules group types by +domain: `adcp.types.media_buy`, `adcp.types.creative`, `adcp.types.signals`, +`adcp.types.protocol`, `adcp.types.buyer`, and `adcp.types.seller`. Each is +lazy and re-exports only the types relevant to that area +(`from adcp.types.media_buy import CreateMediaBuyRequest`). These and +`adcp.types` are the supported surfaces — never import from +`adcp.types.generated_poc.*` or `adcp.types._generated`. + ## `__version__` now reflects the installed distribution `adcp.__version__` now reads from `importlib.metadata.version("adcp")` diff --git a/README.md b/README.md index da02ffca..a341e643 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,73 @@ Official Python SDK for the **Ad Context Protocol (AdCP)**. Build and connect to advertising agents that work synchronously OR asynchronously with the same code. +## Choose your path + +This README serves both sides of an AdCP integration. Jump to what you're doing: + +- **Connect as a buyer** → [Quick Start: Test Helpers](#quick-start-test-helpers) and [Quick Start: Distributed Operations](#quick-start-distributed-operations). Entry point: `from adcp import ADCPClient, AgentConfig`; start with the `client.simple.*` API. +- **Build a seller / agent** → [Building an AdCP Agent](#building-an-adcp-agent). Entry point: `from adcp.server import ADCPHandler, serve`. +- **Understand the type system & imports** → [Type Safety](#type-safety) (import surface, partial modules, cold-start note). +- **Test against reference agents** → [Quick Start: Test Helpers](#quick-start-test-helpers) and [Test Helpers](#test-helpers). Entry point: `from adcp.testing import test_agent, creative_agent`. + +## Table of Contents + +- [Building an AdCP Agent](#building-an-adcp-agent) + - [Multi-agent discovery manifest](#multi-agent-discovery-manifest) +- [Connecting to AdCP Agents](#connecting-to-adcp-agents) +- [The Core Concept](#the-core-concept) +- [Installation](#installation) +- [Quick Start: Test Helpers](#quick-start-test-helpers) + - [Simple vs. Standard API](#simple-vs-standard-api) + - [Available Test Helpers](#available-test-helpers) +- [Quick Start: Distributed Operations](#quick-start-distributed-operations) +- [AdCP version support](#adcp-version-support) +- [Documentation](#documentation) +- [Features](#features) + - [Test Helpers](#test-helpers) + - [Full Protocol Support](#full-protocol-support) + - [Type Safety](#type-safety) + - [Multi-Agent Operations](#multi-agent-operations) + - [Webhook Handling](#webhook-handling) + - [Security](#security) + - [Signed webhooks (AdCP 3.0): receiver quickstart](#signed-webhooks-adcp-30-receiver-quickstart) + - [Signed webhooks: sender quickstart](#signed-webhooks-sender-quickstart) + - [Debug Mode](#debug-mode) + - [Resource Management](#resource-management) + - [Error Handling](#error-handling) + - [Idempotency and retries](#idempotency-and-retries) + - [Building a seller: idempotency middleware](#building-a-seller-idempotency-middleware) + - [AdCP 3.0.0-rc.4 migration](#adcp-300-rc4-migration) +- [Available Tools](#available-tools) +- [Workflow Examples](#workflow-examples) + - [Complete Media Buy Workflow](#complete-media-buy-workflow) + - [Complete Creative Workflow](#complete-creative-workflow) + - [Integrated Workflow: Media Buy + Creatives](#integrated-workflow-media-buy--creatives) +- [Property Discovery (AdCP v2.2.0)](#property-discovery-adcp-v220) +- [Publisher Authorization Validation](#publisher-authorization-validation) + - [Authorization Discovery](#authorization-discovery) +- [Request Signing (AdCP 3.0 optional, 4.0 required)](#request-signing-adcp-30-optional-40-required) + - [Generate a keypair](#generate-a-keypair) + - [Sign an outgoing request](#sign-an-outgoing-request) + - [Auto-sign on `ADCPClient`](#auto-sign-on-adcpclient) + - [Auto-sign on raw httpx (no ADCPClient)](#auto-sign-on-raw-httpx-no-adcpclient) + - [Verify incoming requests (FastAPI)](#verify-incoming-requests-fastapi) + - [Migration & rollout](#migration--rollout) + - [Conformance](#conformance) +- [CLI Tool](#cli-tool) + - [Installation](#installation-1) + - [Quick Start](#quick-start) + - [Using Test Agents from CLI](#using-test-agents-from-cli) + - [Configuration Management](#configuration-management) + - [Direct URL Access](#direct-url-access) + - [Examples](#examples) + - [Configuration File](#configuration-file) +- [Environment Configuration](#environment-configuration) +- [Development](#development) +- [Contributing](#contributing) +- [License](#license) +- [Support](#support) + ## Building an AdCP Agent The fastest path to a working agent: subclass `ADCPHandler`, use response builders, call `serve()`. @@ -154,7 +221,7 @@ Pre-configured agents (all include `.simple` accessor): See [examples/simple_api_demo.py](examples/simple_api_demo.py) for a complete comparison. -> **Tip**: Import types from the main `adcp` package (e.g., `from adcp import GetProductsRequest`) rather than `adcp.types.generated` for better API stability. +> **Tip**: Import types from the main `adcp` package (e.g., `from adcp import GetProductsRequest`), from `adcp.types`, or from a curated partial module (`adcp.types.media_buy`, `.creative`, `.signals`, `.protocol`, `.buyer`, `.seller`) — never from the internal `adcp.types.generated_poc.*` layer. `import adcp` is lightweight; the generated type graph is built only when you import a type. ## Quick Start: Distributed Operations @@ -209,13 +276,20 @@ async with ADCPMultiAgentClient( ## AdCP version support -The 5.x line targets AdCP 3.0 stable. v3.1 support lands in SDK 6.0 against -the 3.1 stable spec — there is no opt-in preview surface in 5.x. If you talk -to a v3.1+ agent from 5.x, the SDK parses the response through v3.0 types -(unknown fields are preserved on the model but not surfaced as typed -attributes) and schema validation is skipped for that version. Track -[#741](https://github.com/adcontextprotocol/adcp-client-python/issues/741) -for 6.0 progress. +The 6.x line is built against **AdCP 3.1.0 stable** and natively validates +both AdCP 3.0 and 3.1 wire shapes. Check the versions at runtime: + +```python +import adcp + +adcp.get_adcp_sdk_version() # SDK package version, e.g. "6.4.1" +adcp.get_adcp_spec_version() # AdCP spec this build targets, e.g. "3.1.0" +``` + +If you talk to an agent on a newer spec than this SDK validates, the response +still parses — unknown fields are preserved on the model (but not surfaced as +typed attributes) and schema validation is skipped for that version, so +forward traffic degrades gracefully rather than failing. ## Documentation @@ -341,7 +415,31 @@ if media_buy.status == MediaBuyStatus.active: - **All 9 pricing options**: `CpcPricingOption`, `CpmFixedRatePricingOption`, `VcpmAuctionPricingOption`, etc. - **Request/Response types**: All 16 operations with full request/response types -For types not on the top-level surface, import from `adcp.types` (e.g., `from adcp.types import AssetStatus`). If a type you need isn't in `adcp.types`, open an issue — we'll add an alias. The `adcp.types.generated_poc.*` modules are internal; class names and module paths shift on every schema regeneration and are not a supported API. +For types not on the top-level surface, import from `adcp.types` (e.g., `from adcp.types import AssetStatus`), or from one of the curated partial modules that group the types by domain: + +```python +from adcp.types.media_buy import CreateMediaBuyRequest, MediaBuyStatus +from adcp.types.creative import Format, SyncCreativesRequest +from adcp.types.signals import GetSignalsRequest, SignalTargeting +from adcp.types.protocol import Error, Pagination, GetTaskStatusRequest +from adcp.types.buyer import GetProductsRequest, CpmPricingOption +from adcp.types.seller import Offering, PropertyList, ContentStandards +``` + +If a type you need isn't in `adcp.types`, open an issue — we'll add an alias. The `adcp.types.generated_poc.*` modules are internal; class names and module paths shift on every schema regeneration and are not a supported API. + +The six partial modules (`media_buy`, `creative`, `signals`, `protocol`, `buyer`, `seller`) are for curation and discoverability — they group types by domain and give you a smaller import surface. They are **not** a per-domain performance tier: the first AdCP type you touch through any of them builds the same single Pydantic graph. + +#### Cold start / import performance + +`import adcp` is lightweight (~2ms) and builds nothing — it does not import pydantic, the A2A SDK, or the client, and it does not construct the type graph. The first time you access *any* AdCP type — through `adcp`, `adcp.types`, or a partial module — the full generated Pydantic graph builds once per process (~1s). There is only one graph; subsequent type access is free. + +For latency-sensitive cold starts (AWS Lambda, agent tool invocations), warm the graph at startup so the cost lands before your first request: + +```python +import adcp.types +adcp.types.Product # forces the one-time graph build now, not on the hot path +``` #### Semantic Type Aliases @@ -364,7 +462,6 @@ def handle_response( **Available semantic aliases:** - Response types: `*SuccessResponse` / `*ErrorResponse` (e.g., `CreateMediaBuySuccessResponse`) -- Request variants: `*FormatRequest` / `*ManifestRequest` (e.g., `PreviewCreativeFormatRequest`) - Preview renders: `PreviewRenderImage` / `PreviewRenderHtml` / `PreviewRenderIframe` - Activation keys: `PropertyIdActivationKey` / `PropertyTagActivationKey` @@ -952,8 +1049,8 @@ Build and deliver production-ready creatives: ```python from adcp import ADCPClient, AgentConfig -from adcp import PreviewCreativeFormatRequest, BuildCreativeRequest -from adcp import CreativeManifest, PlatformDeployment +from adcp import PreviewCreativeRequest, BuildCreativeRequest +from adcp import CreativeManifest # 1. Connect to creative agent config = AgentConfig(id="creative_agent", agent_uri="https://...", protocol="mcp") @@ -963,18 +1060,25 @@ async with ADCPClient(config) as client: formats_result = await client.list_creative_formats() if formats_result.success: + # format_id is a FormatReferenceStructuredObject; reuse it directly format_id = formats_result.data.formats[0].format_id print(f"Using format: {format_id.id}") # 3. Preview creative (test before building) preview_result = await client.preview_creative( - PreviewCreativeFormatRequest( - target_format_id=format_id.id, - inputs={ - "headline": "Fresh Coffee Daily", - "cta": "Order Now" - }, - output_format="url" # Get preview URL + PreviewCreativeRequest( + request_type="single", + format_id=format_id, + inputs=[ + { + "name": "Coffee promo", + "macros": { + "headline": "Fresh Coffee Daily", + "cta": "Order Now", + }, + } + ], + output_format="url", # Get preview URL ) ) @@ -985,16 +1089,19 @@ async with ADCPClient(config) as client: # 4. Build production creative build_result = await client.build_creative( BuildCreativeRequest( - manifest=CreativeManifest( + idempotency_key="build-coffee-001", + creative_manifest=CreativeManifest( format_id=format_id, - brand_url="https://coffeeco.com", - # ... creative content + assets={ + "banner_image": { + "asset_type": "image", + "url": "https://cdn.coffeeco.com/banner_300x250.png", + "width": 300, + "height": 250, + } + }, ), - target_format_id=format_id.id, - deployment=PlatformDeployment( - type="platform", - platform_id="google_admanager" - ) + target_format_id=format_id, ) ) @@ -1009,7 +1116,7 @@ Combine both workflows for a complete campaign setup: ```python from adcp import ADCPMultiAgentClient, AgentConfig, BrandReference, PublisherPropertiesAll -from adcp import BuildCreativeRequest, CreateMediaBuyRequest +from adcp import BuildCreativeRequest, CreateMediaBuyRequest, CreativeManifest # Connect to both sales and creative agents async with ADCPMultiAgentClient( @@ -1029,12 +1136,24 @@ async with ADCPMultiAgentClient( # 2. Get creative formats from creative agent creative_agent = client.agent("creative") formats = await creative_agent.simple.list_creative_formats() + format_id = formats.formats[0].format_id # 3. Build creative asset creative_result = await creative_agent.build_creative( BuildCreativeRequest( - manifest=creative_manifest, - target_format_id=formats.formats[0].format_id.id, + idempotency_key="build-campaign-001", + creative_manifest=CreativeManifest( + format_id=format_id, + assets={ + "banner_image": { + "asset_type": "image", + "url": "https://cdn.coffeeco.com/banner_300x250.png", + "width": 300, + "height": 250, + } + }, + ), + target_format_id=format_id, ) ) diff --git a/docs/extending-types.md b/docs/extending-types.md index ada87a55..a49989f9 100644 --- a/docs/extending-types.md +++ b/docs/extending-types.md @@ -15,66 +15,74 @@ This guide shows how to extend ADCP types safely while maintaining protocol comp ## Picking the Right Base Class — Context-Specific Schema Variants -Several entity names (`Creative`, `Package`, `MediaBuy`, `Deployment`, `GeoCountriesExcludeItem`, etc.) appear in multiple spec slices with **genuinely different shapes**. Codegen emits each as a separate class. Top-level imports like `from adcp import Creative` resolve to one specific variant — typically not the one you want when extending response types. Subclassing the wrong variant produces silent type drift: construction works, but `mypy` flags `[assignment]` when you wire your subclass into the response that expects a different variant, and runtime serialization may drop fields the consuming code expects. +Several entity names (`Creative`, `Package`, `MediaBuy`, etc.) appear in multiple spec slices with **genuinely different shapes**. The bare name resolves to one specific variant — typically not the one you want when extending response types. The creative inside `ListCreativesResponse.creatives` is a different class from the creative inside `GetCreativeDeliveryResponse.creatives`, even though both are spelled `Creative` in the spec. Subclassing the wrong variant produces silent type drift: construction works, but `mypy` flags `[assignment]` when you wire your subclass into the response that expects a different variant, and runtime serialization may drop fields the consuming code expects. -**The fix is import discipline.** When extending a response model's element type, import the element from the same submodule the parent response is generated from — not from the top-level `adcp.types` namespace. +**The fix is to import the variant-specific alias.** For every name that collides across slices, `adcp.types` exports a disambiguated alias whose prefix names the slice it belongs to — `ListCreativesCreative`, `SyncCreativesCreative`, `DeliveryCreative`, `CapabilitiesCreative`, and so on. Import these from the public `adcp.types` namespace. Do **not** reach into `adcp.types.generated_poc.*` or `adcp.types._generated` — those are internal modules whose class names renumber on every schema regen, so an import that resolves today can silently move tomorrow. + +These prefixed aliases live in the flat `adcp.types` namespace, not in the curated partial modules (`adcp.types.creative`, `adcp.types.media_buy`, …). The partials export only the canonical, single-variant names (`Creative`, `Package`, `MediaBuy`). When you need a specific variant, import it from `adcp.types`. ### Common cases | Adopter use case | Import this | NOT this | |---|---|---| -| Extend the creative type used in `ListCreativesResponse.creatives` | `from adcp.types.generated_poc.creative.list_creatives_response import Creative` | `from adcp import Creative` (resolves to delivery variant) | -| Extend the creative used in `GetCreativeDeliveryResponse.creatives` | `from adcp.types.generated_poc.creative.get_creative_delivery_response import Creative` | `from adcp import Creative` (same name — different submodule, different shape) | -| Extend the package element of `CreateMediaBuyRequest.packages` | `from adcp.types.generated_poc.media_buy.package_request import PackageRequest` | `from adcp import Package` | -| Extend the affected-package element of `UpdateMediaBuyResponse.affected_packages` | `from adcp import Package` (canonical) — verify against the parent response | — | -| Extend the media-buy element of `GetMediaBuysResponse.media_buys` | `from adcp.types.generated_poc.media_buy.get_media_buys_response import MediaBuy` | `from adcp import MediaBuy` (top-level resolves to the canonical variant; the `get_media_buys_response` slice has a narrower shape) | -| Extend `Deployment` for `Signal.deployments` | `from adcp.types.generated_poc.core.deployment import Deployment1` (the structured class — `Deployment` is a `RootModel` wrapper) | `from adcp.types.generated_poc.core.deployment import Deployment` (you'll get the wrapper, not the fields) | -| Add fields to a geo-exclusion list (`TargetingOverlay.geo_countries_exclude` etc.) | The `Geo*ExcludeItem` classes are shape-identical to the inclusion variants but distinct classes — there is no clean inheritance path; declare your local class against the exclusion variant | — | +| Extend the creative type used in `ListCreativesResponse.creatives` | `from adcp.types import ListCreativesCreative` | `from adcp import Creative` (resolves to a different variant) | +| Extend the creative used in `GetCreativeDeliveryResponse.creatives` | `from adcp.types import DeliveryCreative` | `from adcp import Creative` (same name — different shape) | +| Extend the creative used in `SyncCreativesResponse` | `from adcp.types import SyncCreativesCreative` | `from adcp import Creative` | +| Extend the creative reported in `GetAdcpCapabilitiesResponse` | `from adcp.types import CapabilitiesCreative` | `from adcp import Creative` | +| Extend the package element of `CreateMediaBuyRequest.packages` | `from adcp.types import PackageRequest` (also in `adcp.types.media_buy`) | `from adcp import Package` | +| Extend the media-buy element of `GetMediaBuysResponse.media_buys` | `from adcp.types import GetMediaBuysMediaBuy` | `from adcp import MediaBuy` (resolves to the core variant; the list slice has a narrower shape) | +| Extend the media-buy reported in `GetAdcpCapabilitiesResponse` | `from adcp.types import CapabilitiesMediaBuy` | `from adcp import MediaBuy` | +| Extend a `Deployment` (e.g. for `Signal.deployments`) | `from adcp.types import Deployment` (a structured union over the deployment shapes) | reaching into `generated_poc` for an internal numbered class | + +The canonical names (`Creative`, `Package`, `MediaBuy`, `Deployment`) remain available from both `adcp` and the partial modules — use those when the bare name already resolves to the variant you want. The prefixed aliases exist for the cases where it doesn't. ### How to detect a wrong import -mypy under `--strict` will flag the override with `[assignment]`: +mypy under `--strict` will flag the override with `[assignment]` when the element type you subclassed isn't the one the parent response field declares: ```python -# parent: list[adcp.types.generated_poc.creative.list_creatives_response.Creative] | None -# you imported the delivery Creative by accident: -from adcp import Creative # delivery variant +# parent field declares the listing-slice creative; you subclassed a different variant: +from adcp import Creative # canonical variant — wrong slice here class InternalListCreative(Creative): internal_id: str | None = Field(default=None, exclude=True) -class MyListResponse(LibraryListCreativesResponse): +class MyListResponse(ListCreativesResponse): creatives: list[InternalListCreative] | None = None # ← mypy: [assignment] ``` -The fix is to switch the import to the listing-slice submodule. When the import is right, mypy is happy: +The fix is to subclass the listing-slice alias. When the variant matches, mypy is happy: ```python -from adcp.types.generated_poc.creative.list_creatives_response import Creative +from adcp.types import ListCreativesCreative, ListCreativesResponse -class InternalListCreative(Creative): +class InternalListCreative(ListCreativesCreative): internal_id: str | None = Field(default=None, exclude=True) -class MyListResponse(LibraryListCreativesResponse): - # Pydantic v2 covariant Sequence[X] in library types means list[Subclass] - # is a valid override here when Subclass IS-A parent's Creative. +class MyListResponse(ListCreativesResponse): + # Pydantic v2 covariant Sequence[X] in the library types means list[Subclass] + # is a valid override here when Subclass IS-A the parent's creative variant. creatives: list[InternalListCreative] | None = None # ✓ no ignore needed ``` -If the parent response uses a `Geo*ExcludeItem` (shape-identical-but-distinct class) and you want to substitute it with a different shape-compatible class, the override is genuinely cross-class. As of v5.4.0 the SDK ships a typed escape hatch — `adcp.types.SchemaVariant` — that marks the override as intentional and retires the `# type: ignore[assignment]`: +### When a variant has no public alias + +A few spec shapes have no disambiguated public name. The clearest example is the geo-exclusion element types behind `TargetingOverlay.geo_countries_exclude`, `geo_regions_exclude`, and `geo_metros_exclude`. Each exclusion list uses a distinct element class that is shape-identical to its inclusion counterpart (`GeoCountry`, `GeoRegion`, `GeoMetro`) but is not the same class and has no public alias in `adcp.types`. + +If you need to substitute a shape-compatible class into one of these fields, the override is genuinely cross-class, and there is no public element type to subclass. Use the typed escape hatch `adcp.types.SchemaVariant` against the public inclusion variant — it marks the substitution as intentional and retires the `# type: ignore[assignment]`: ```python -from adcp.types import SchemaVariant -from adcp.types.generated_poc.audiences import GeoCountriesExcludeItem # parent shape -# ... - -class MyAudienceFilters(LibraryAudienceFilters): - # Cross-class override: GeoCountry is the inclusion variant, distinct - # from GeoCountriesExcludeItem but shape-compatible. SchemaVariant marks - # the substitution as intentional; no ``# type: ignore[assignment]`` needed. +from adcp.types import SchemaVariant, GeoCountry + +class MyAudienceFilters(SomeLibraryFilters): + # Cross-variant override: GeoCountry is the public inclusion type, shape-compatible + # with the exclusion element. SchemaVariant marks the substitution as intentional; + # no ``# type: ignore[assignment]`` needed. excluded_countries: SchemaVariant[list[GeoCountry]] ``` +If you find a variant you need to extend that has neither a canonical nor a prefixed public alias, **open an issue** at [adcontextprotocol/adcp-client-python](https://github.com/adcontextprotocol/adcp-client-python/issues) asking for a public alias. Do not import the class from `adcp.types.generated_poc.*` as a workaround — those names renumber on schema regen, so the import is not stable. + `SchemaVariant[T]` collapses to `T` at runtime — Pydantic validates against the wrapped type unchanged. At type-check time the bundled mypy plugin (`adcp.types.mypy_plugin`) rewrites the annotation to `Any` so the LSP override check passes. **Adopters must enable the plugin in their mypy config** — add this line to `pyproject.toml`: ```toml @@ -86,7 +94,7 @@ Tradeoff: inside the override site, mypy sees the field as `Any`. If precise inf ### Tracking the spec-level fix -Several of the cases above (the `Geo*ExcludeItem` mirrors of inclusion items, the `Deployment` RootModel wrapper, the `MediaBuy` capability-vs-response collision) are tracked upstream as a spec rename request: [adcontextprotocol/adcp#4347](https://github.com/adcontextprotocol/adcp/issues/4347). When the rename ships, the workarounds in this section may collapse — but the core principle (import from the submodule that matches your intended response context) is durable. +The cross-slice name collisions (the geo exclusion mirrors of the inclusion items, the capability-vs-response variants) are tracked upstream as a spec rename request: [adcontextprotocol/adcp#4347](https://github.com/adcontextprotocol/adcp/issues/4347). When the rename ships, some of these variants may merge — but the core principle (import the public alias that matches your intended response context, never the internal `generated_poc` class) is durable. ## Field-Level Exclusion with `Field(exclude=True)` — Recommended @@ -95,29 +103,32 @@ The simplest and most reliable way to keep internal fields off the wire. Fields call-site `exclude={}` plumbing, no parent-model override required. ```python -from typing import Any from pydantic import Field -# Listing-slice Creative — see "Picking the Right Base Class" above. -from adcp.types.generated_poc.creative.list_creatives_response import Creative +# Listing-slice creative variant — see "Picking the Right Base Class" above. +from adcp.types import ListCreativesCreative from adcp.types.base import AdCPBaseModel -class InternalCreative(Creative): +class InternalCreative(ListCreativesCreative): """Creative extended with seller-internal fields.""" internal_approval_id: str | None = Field(default=None, exclude=True) seller_notes: str | None = Field(default=None, exclude=True) class CreativePayload(AdCPBaseModel): - """User-defined payload — creatives declared as base type.""" - creatives: list[Creative] + """User-defined payload — creatives declared as the base variant type.""" + creatives: list[ListCreativesCreative] resp = CreativePayload( creatives=[ InternalCreative( creative_id="c-1", - variants=[], + name="Spring promo", + format_id={"agent_url": "https://creative.example.com", "id": "display_300x250"}, + status="approved", + created_date="2024-01-15T10:30:00Z", + updated_date="2024-01-15T10:30:00Z", internal_approval_id="approv-42", seller_notes="approved by legal", ) @@ -125,8 +136,8 @@ resp = CreativePayload( ) wire = resp.model_dump() -# {"creatives": [{"creative_id": "c-1", "variants": []}]} -# internal_approval_id and seller_notes are absent — no parent override needed. +# internal_approval_id and seller_notes are absent from the output — +# no parent override needed. ``` `Field(exclude=True)` works with `model_dump()`, `model_dump_json()`, and all standard Pydantic @@ -146,12 +157,12 @@ required. ```python from typing import Any from pydantic import SerializationInfo, model_serializer -# Listing-slice Creative — see "Picking the Right Base Class" above. -from adcp.types.generated_poc.creative.list_creatives_response import Creative +# Listing-slice creative variant — see "Picking the Right Base Class" above. +from adcp.types import ListCreativesCreative from adcp.types.base import AdCPBaseModel -class InternalCreative(Creative): +class InternalCreative(ListCreativesCreative): """Creative with a normalized source_label field.""" source_label: str | None = None @@ -164,24 +175,50 @@ class InternalCreative(Creative): return result -# Direct serialization: serializer fires. -c = InternalCreative(creative_id="c-1", variants=[], source_label="HD_VIDEO") -c.model_dump() # {"creative_id": "c-1", "variants": [], "source_label": "hd_video"} +# Direct serialization: the subclass serializer fires. +c = InternalCreative( + creative_id="c-1", + name="Spring promo", + format_id={"agent_url": "https://creative.example.com", "id": "display_300x250"}, + status="approved", + created_date="2024-01-15T10:30:00Z", + updated_date="2024-01-15T10:30:00Z", + source_label="HD_VIDEO", +) +c.model_dump() # source_label normalized to "hd_video" +# (If you hit the MockValSer error described below, serialize this subclass with +# serialize_as_any=False.) -# Nested under an AdCPBaseModel parent with a base-type annotation: +# Nested under an AdCPBaseModel parent with a base-variant annotation: class CreativePayload(AdCPBaseModel): - creatives: list[Creative] # declared as base type + creatives: list[ListCreativesCreative] # declared as the base variant payload = CreativePayload(creatives=[c]) payload.model_dump() -# {"creatives": [{"creative_id": "c-1", "variants": [], "source_label": "hd_video"}]} -# Subclass serializer fired automatically — AdCPBaseModel.model_dump() defaults -# serialize_as_any=True. Pass serialize_as_any=False explicitly to suppress it. +# AdCPBaseModel.model_dump() defaults serialize_as_any=True so the subclass serializer +# is meant to fire through the base-typed field, producing the nested "hd_video". +# Pass serialize_as_any=False explicitly to suppress runtime-type dispatch. ``` If your parent extends plain `pydantic.BaseModel` (not `AdCPBaseModel`), you must pass `serialize_as_any=True` yourself — the default kwarg only ships on AdCP types. +> **Deferred-build caveat (known issue):** AdCP variant types are configured with +> `defer_build=True` to keep `import adcp` cheap. A subclass that defines its own +> `@model_serializer(mode="wrap")` invokes `handler(self, info)`, which dispatches to the +> base variant's pydantic-core serializer. On the first serialization that serializer can +> still be a deferred placeholder, and the failure surfaces as +> `PydanticSerializationError: ... 'MockValSer' object is not an instance of +> 'SchemaSerializer'` under the default `serialize_as_any=True`. Passing +> `serialize_as_any=False` serializes the subclass directly and works, but it forgoes the +> runtime-type dispatch this section relies on for nested base-typed fields. The +> `Field(exclude=True)` path above is **not** affected — only subclass *wrap serializers* +> hit this. **Prefer `Field(exclude=True)` for plain wire-isolation;** reach for +> `@model_serializer` only when you need transformation logic, and file an issue at +> [adcontextprotocol/adcp-client-python](https://github.com/adcontextprotocol/adcp-client-python/issues) +> if the `MockValSer` error blocks you — this is an SDK-side build-ordering bug, not +> something to work around by importing from `generated_poc`. + ## Migrating from Manual `model_dump()` Dispatch Overrides A common pattern in early SDK integrations is writing a parent override that manually re-calls @@ -189,8 +226,10 @@ A common pattern in early SDK integrations is writing a parent override that man ```python # ❌ Fragile: every new response type needs this boilerplate, and missing one is silent. +from adcp.types import ListCreativesCreative + class MyCreativePayload(AdCPBaseModel): - creatives: list[Creative] + creatives: list[ListCreativesCreative] def model_dump(self, **kwargs: Any) -> dict[str, Any]: result = super().model_dump(**kwargs) @@ -206,7 +245,7 @@ produces wrong output if a new child list field is added without updating the ov ```python # ✅ Delete the parent override entirely. Move exclusion to the child via Field(exclude=True). -class InternalCreative(Creative): +class InternalCreative(ListCreativesCreative): internal_approval_id: str | None = Field(default=None, exclude=True) # MyCreativePayload needs no model_dump() override — Pydantic handles it at all depths. @@ -218,7 +257,7 @@ class InternalCreative(Creative): # ✅ Move the logic to the child via @model_serializer. # AdCPBaseModel parents default serialize_as_any=True so the subclass serializer # fires automatically — no call-site kwarg needed. -class InternalCreative(Creative): +class InternalCreative(ListCreativesCreative): @model_serializer(mode="wrap") def _serialize(self, handler: Any, info: SerializationInfo) -> dict[str, Any]: result = handler(self, info) @@ -369,7 +408,7 @@ adcp_response = record.to_adcp_response() When processing webhook payloads with internal routing metadata: ```python -from adcp import McpMcpWebhookPayload +from adcp import McpWebhookPayload from pydantic import ConfigDict class InternalWebhookPayload(McpWebhookPayload): @@ -383,7 +422,7 @@ class InternalWebhookPayload(McpWebhookPayload): async def process_webhook(payload: dict) -> None: """Process webhook with internal tracking.""" # Parse with extensions - internal_payload = InternalMcpWebhookPayload.model_validate(payload) + internal_payload = InternalWebhookPayload.model_validate(payload) # Add internal routing internal_payload.internal_destination = determine_destination(internal_payload) diff --git a/docs/handler-authoring.md b/docs/handler-authoring.md index 8a9abf6e..e6d9730e 100644 --- a/docs/handler-authoring.md +++ b/docs/handler-authoring.md @@ -210,6 +210,15 @@ class MySeller(ADCPHandler): return GetProductsResponse(products=[...]) ``` +Import request/response types from `adcp.types` (or the top-level `adcp`). +For a narrower surface, six curated partial modules group types by domain: +`adcp.types.media_buy`, `adcp.types.creative`, `adcp.types.signals`, +`adcp.types.protocol`, `adcp.types.buyer`, and `adcp.types.seller` +(e.g. `from adcp.types.buyer import GetProductsRequest`). Never import +from `adcp.types.generated_poc.*` or `adcp.types._generated` — those are +internal and their module paths and class names change on every schema +regeneration. + **Validation errors surface as `INVALID_REQUEST`.** A Pydantic `ValidationError` at the boundary is converted to a structured AdCP error with the field path and validation detail — callers see the diff --git a/docs/request-signing-migration.md b/docs/request-signing-migration.md index a068674e..7109c6c2 100644 --- a/docs/request-signing-migration.md +++ b/docs/request-signing-migration.md @@ -44,14 +44,11 @@ Hold the PEM in your secret store — environment variable, GCP Secret Manager, Set `request_signing` on your capabilities response with empty `supported_for` / `warn_for` / `required_for` to start. Counterparties probing your capabilities can now see the block exists. ```python -from adcp.types.generated_poc.protocol.get_adcp_capabilities_response import ( - CoversContentDigest, - RequestSigning, -) +from adcp.types.capabilities import RequestSigning request_signing = RequestSigning( supported=True, - covers_content_digest=CoversContentDigest.either, + covers_content_digest="either", # "required" | "forbidden" | "either" required_for=[], warn_for=[], supported_for=[], diff --git a/examples/README.md b/examples/README.md index 71bed474..25869376 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,144 +1,162 @@ -# ADCP Python Client Examples +# AdCP Python SDK Examples -This directory contains examples demonstrating how to use the ADCP Python client's preview URL generation feature. +A categorized index of the runnable examples in this directory. Each +example is a single-file (or single-directory) demo with a module +docstring explaining what it shows and how to run it. -## Preview URL Generation Demo +Two sides of the protocol are covered: -This demo shows how to fetch creative format previews from the ADCP creative agent and display them in a web browser using the `` web component. +- **Buyer** — calling AdCP agents. Entry point: `from adcp import ADCPClient, AgentConfig`. + `client.simple.*` is the recommended starter API. +- **Seller** — building an AdCP agent. Entry point: + `from adcp.server import ADCPHandler, serve`, or the + `DecisioningPlatform` framework in `adcp.decisioning`. -### Quick Start +For task-level guidance beyond these scripts, see the `skills/` +directory at the repo root (buyer skills like `call-adcp-agent` and +`adcp-media-buy`; seller skills like `build-seller-agent`). -1. **Install the package** (if not already installed): - ```bash - pip install -e . - ``` +## Running an example -2. **Fetch preview URLs from the creative agent**: - ```bash - python examples/fetch_previews.py - ``` +Install the package, then run any script by path: - This will: - - Connect to the reference creative agent at `https://creative.adcontextprotocol.org` - - Call `list_creative_formats()` with `fetch_previews=True` - - Generate preview URLs for available formats - - Save the results to `examples/preview_urls.json` +```bash +pip install -e . +python examples/basic_usage.py +``` -3. **Start a local web server** (required for the web component to work): - ```bash - cd /path/to/adcp-client-python - python -m http.server 8000 - ``` +Some examples need a local mock-server or environment variables — see +the "Run" section in each file's module docstring for prerequisites. -4. **Open the demo in your browser**: - ``` - http://localhost:8000/examples/web_component_demo.html - ``` +## Buyer quickstart -### What You'll See +Calling AdCP agents as a buyer. -The demo page displays a grid of creative format previews, each showing: -- Format name -- Format ID -- Live preview rendered in the `` web component +- [`basic_usage.py`](basic_usage.py) — configure an `ADCPClient`, call `get_products`, handle sync vs async responses. +- [`simple_api_demo.py`](simple_api_demo.py) — the `.simple` accessor: pass kwargs directly, get unwrapped data, exceptions on error. +- [`multi_agent.py`](multi_agent.py) — configure multiple agents and run operations across all of them in parallel. +- [`test_helpers_demo.py`](test_helpers_demo.py) — use the built-in test agents from `adcp.testing` (`test_agent`, `creative_agent`) for quick demos. +- [`type_aliases_demo.py`](type_aliases_demo.py) — the ergonomic semantic type aliases for clearer code. +- [`fetch_agent_authorizations.py`](fetch_agent_authorizations.py) — discover which publishers have authorized your agent, via the agent's capabilities ("push") and via publisher `adagents.json` ("pull"). +- [`adagents_validation.py`](adagents_validation.py) — verify a sales agent is authorized to sell for a publisher's properties using the `adagents.json` validation utilities. -Features demonstrated: -- **Shadow DOM isolation** - No CSS conflicts between previews -- **Lazy loading** - Previews load only when visible -- **Responsive grid** - Adapts to different screen sizes -- **Interactive previews** - Full creative rendering with animations +Related skills: `call-adcp-agent` (wire-level invariants for any buyer +call), `adcp-media-buy`, `adcp-creative`, `adcp-signals`, +`adcp-governance`, `adcp-brand`, `adcp-si`. -### Files +## Building a seller agent -- **`fetch_previews.py`** - Python script to fetch preview URLs from the creative agent -- **`web_component_demo.html`** - HTML page demonstrating the `` web component -- **`preview_urls.json`** - Generated file containing preview URLs (created by fetch script) +Minimal-to-reference seller implementations. The `hello_seller_*` +files are each the smallest possible adopter for one AdCP specialism. -### How It Works +- [`minimal_sales_agent.py`](minimal_sales_agent.py) — single-file MCP sales agent ("Riverdale Gazette") covering the `get_adcp_capabilities` → `get_products` → `create_media_buy` flow. +- [`hello_seller.py`](hello_seller.py) — the canonical `DecisioningPlatform` starting point: the full required `sales-non-guaranteed` method surface, plus minimum valid buyer payloads. +- [`hello_seller_async_handoff.py`](hello_seller_async_handoff.py) — the three `create_media_buy` return shapes: sync success, correctable `AdcpError`, and `TaskHandoff` for HITL/background work. +- [`hello_seller_audience.py`](hello_seller_audience.py) — minimal `audience-sync` seller (`sync_audiences` with delta upsert). +- [`hello_seller_brand_rights.py`](hello_seller_brand_rights.py) — minimal `brand-rights` seller (`get_brand_identity`, `get_rights`, `acquire_rights` with a 4-arm success union). +- [`hello_seller_catalog.py`](hello_seller_catalog.py) — minimal `sales-catalog-driven` seller (adds `sync_catalogs`). +- [`hello_seller_collection_lists.py`](hello_seller_collection_lists.py) — minimal `collection-lists` seller (5-method CRUD + fetch-token issuance). +- [`hello_seller_content_standards.py`](hello_seller_content_standards.py) — minimal `content-standards` seller (CRUD + calibration + validation). +- [`hello_seller_creative.py`](hello_seller_creative.py) — minimal `creative-generative` / `creative-template` seller; template for AI-creative integrators returning a `CreativeManifest`. +- [`hello_seller_governance.py`](hello_seller_governance.py) — minimal `governance-spend-authority` / `governance-delivery-monitor` seller (note: requires `governance_aware=True`). +- [`hello_seller_property_lists.py`](hello_seller_property_lists.py) — minimal `property-lists` seller (5-method CRUD + fetch-token issuance). +- [`hello_seller_signals.py`](hello_seller_signals.py) — minimal `signal-marketplace` seller (`get_signals`, `activate_signal`); canonical `TaskHandoff` example. +- [`seller_agent.py`](seller_agent.py) — reference `ADCPHandler` seller for the `media_buy_seller` storyboard (9 steps, all core tools). +- [`typed_handler_demo.py`](typed_handler_demo.py) — declare handler `params` as a Pydantic model so the dispatcher validates at the boundary. +- [`scheduler_lifespan.py`](scheduler_lifespan.py) — lifecycle-bound background work via `serve(on_startup=, on_shutdown=)`. +- [`hello_mock_seller.py`](hello_mock_seller.py) — mock-mode upstream URL routing: swap the upstream per request for spec-conformance storyboards without a real backend. +- [`hello_proposal_manager.py`](hello_proposal_manager.py) — per-tenant `ProposalManager` binding via `PlatformRouter` (two-platform composition). +- [`hello_proposal_manager_v15.py`](hello_proposal_manager_v15.py) — the full v1.5 proposal lifecycle (`get_products` / `refine_products` / `finalize_proposal`) behind a minimal-LOC adopter. +- [`multi_platform_seller/`](multi_platform_seller/README.md) — directory example: N tenants, N `DecisioningPlatform` subclasses, one `serve()` process, dispatched by `PlatformRouter`. +- [`sales_proposal_mode_seller/`](sales_proposal_mode_seller/README.md) — directory example: the v1.5 `ProposalManager` surface end-to-end, passing the `proposal_finalize.yaml` storyboard. +- [`v3_reference_seller/`](v3_reference_seller/README.md) — directory example: canonical multi-tenant translator-pattern seller (AdCP wire in, real upstream ad server out); includes `MIGRATION.md`. -The Python script uses the new `fetch_previews` parameter: +Related skills: `build-seller-agent`, `build-generative-seller-agent`, +`build-retail-media-agent`, `build-creative-agent`, +`build-signals-agent`. The seller storyboard tests live at +[`../tests/test_seller_agent_storyboard.py`](../tests/test_seller_agent_storyboard.py). -```python -from adcp import ADCPClient -from adcp.types import AgentConfig, Protocol -from adcp.types.generated import ListCreativeFormatsRequest +## Authentication & multi-tenancy -creative_agent = ADCPClient( - AgentConfig( - id="creative_agent", - agent_uri="https://creative.adcontextprotocol.org", - protocol=Protocol.MCP, - ) -) +- [`mcp_with_auth_middleware.py`](mcp_with_auth_middleware.py) — multi-tenant MCP server with bearer-token auth via `BearerTokenAuthMiddleware` + `auth_context_factory`. +- [`buyer_agent_registry_sqlalchemy.py`](buyer_agent_registry_sqlalchemy.py) — SQLAlchemy-backed `BuyerAgentRegistry` for v3 sellers: the commercial-identity allowlist gate (signing-only and bearer-only factory shapes). -# Fetch formats with preview URLs -result = await creative_agent.list_creative_formats( - ListCreativeFormatsRequest(), - fetch_previews=True # ← New parameter! -) +## Webhooks -# Access preview data -formats_with_previews = result.metadata["formats_with_previews"] -for fmt in formats_with_previews: - preview_data = fmt["preview_data"] - print(f"Preview URL: {preview_data['preview_url']}") - print(f"Expires: {preview_data['expires_at']}") -``` +- [`hello_seller_with_webhooks.py`](hello_seller_with_webhooks.py) — wire an `InMemoryWebhookDeliverySupervisor` so completion webhooks reach buyers who register `push_notification_config.url`; uses `WebhookSender.from_bearer_token`. -The HTML page then uses the official ADCP web component to render the previews: +See `docs/handler-authoring.md#webhooks` for the full `WebhookSender` +constructor comparison (bearer vs RFC 9421 JWK signing). -```html - - +## Request signing & identity - - - -``` +- [`buyer_agent_registry_sqlalchemy.py`](buyer_agent_registry_sqlalchemy.py) — the commercial side of v3 identity (the cryptographic side lives in `adcp.signing`). The framework verifies signed traffic before this registry runs the commercial allowlist lookup. + +## Multi-agent / A2A task stores + +Durable, scope-isolated A2A `TaskStore` + `PushNotificationConfigStore` +implementations. Both carry an important security model in their +docstrings (tenant-scoped lookups; webhook-URL SSRF and plaintext +secret risks the adopter must address before production). -### Troubleshooting +- [`a2a_db_tasks.py`](a2a_db_tasks.py) — raw-SQLite reference durable stores; SQLite chosen because the SQL pattern ports directly to Postgres / MySQL. +- [`a2a_sqlalchemy_tasks.py`](a2a_sqlalchemy_tasks.py) — SQLAlchemy-ORM companion: wrap an existing schema behind the a2a-sdk Protocols; runs on any SQLAlchemy backend. -**"Preview URLs file not found" error:** -- Run `python examples/fetch_previews.py` first +## Creative preview & build -**Web component not loading:** -- Make sure you're using a web server (not `file://` URLs) -- Check that you have internet access (web component loads from CDN) +Fetch creative-format preview URLs from a creative agent and render +them with the `` web component. -**No previews showing:** -- Check browser console for errors -- Verify the creative agent is accessible: `https://creative.adcontextprotocol.org` +- [`fetch_preview_urls.py`](fetch_preview_urls.py) — connect to the reference creative agent, list formats, generate preview URLs, and save them to `preview_urls.json`. +- [`generate_mock_previews.py`](generate_mock_previews.py) — generate mock preview data (for when the reference creative agent returns text rather than structured format data). +- [`web_component_demo.html`](web_component_demo.html) — HTML page that renders the saved previews with the `` web component. +- [`preview_urls.json`](preview_urls.json) — generated preview-URL data consumed by the HTML demo. -### Using with Products +### Preview workflow -You can also fetch preview URLs for products: +```bash +# 1. Fetch preview URLs from the creative agent (writes preview_urls.json) +python examples/fetch_preview_urls.py + +# 2. Serve the repo over HTTP (the web component needs http://, not file://) +python -m http.server 8000 + +# 3. Open the demo +# http://localhost:8000/examples/web_component_demo.html +``` + +The Python side uses the `fetch_previews=True` parameter on +`list_creative_formats` (and `get_products`) to attach preview data to +the response metadata: ```python -from adcp.types.generated import GetProductsRequest +from adcp import ADCPClient +from adcp.types import AgentConfig, ListCreativeFormatsRequest, Protocol -# Setup publisher and creative agents -publisher_agent = ADCPClient(publisher_config) -creative_agent = ADCPClient(creative_config) +creative_agent = ADCPClient( + AgentConfig( + id="creative_agent", + agent_uri="https://creative.adcontextprotocol.org", + protocol=Protocol.MCP, + ) +) -# Get products with preview URLs -result = await publisher_agent.get_products( - GetProductsRequest(brief="video campaign"), +result = await creative_agent.list_creative_formats( + ListCreativeFormatsRequest(), fetch_previews=True, - creative_agent_client=creative_agent ) - -# Access product previews -products_with_previews = result.metadata["products_with_previews"] -for product in products_with_previews: - print(f"Product: {product['name']}") - for format_id, preview_data in product["format_previews"].items(): - print(f" Format {format_id}: {preview_data['preview_url']}") +formats_with_previews = result.metadata["formats_with_previews"] ``` -## More Examples +If the previews file is missing, run `python examples/fetch_preview_urls.py` +first. If the web component doesn't load, confirm you are serving over +`http://` (not `file://`) and have internet access — the component +loads from `https://creative.adcontextprotocol.org`. + +Related skill: `adcp-creative`. + +## More -For more examples, see the [documentation](https://docs.adcontextprotocol.org) and [integration tests](../tests/integration/). +For broader documentation see the +[AdCP docs](https://docs.adcontextprotocol.org) and the +[integration tests](../tests/integration/). diff --git a/examples/fetch_preview_urls.py b/examples/fetch_preview_urls.py index 2a63d124..5f1f4805 100644 --- a/examples/fetch_preview_urls.py +++ b/examples/fetch_preview_urls.py @@ -13,8 +13,7 @@ from pathlib import Path from adcp import ADCPClient -from adcp.types import AgentConfig, Protocol -from adcp.types._generated import ListCreativeFormatsRequest +from adcp.types import AgentConfig, ListCreativeFormatsRequest, Protocol async def main(): diff --git a/examples/simple_api_demo.py b/examples/simple_api_demo.py index 53760f86..85c0ab31 100644 --- a/examples/simple_api_demo.py +++ b/examples/simple_api_demo.py @@ -13,7 +13,7 @@ # Import test agents from adcp.testing import creative_agent, test_agent -from adcp.types._generated import GetProductsRequest +from adcp.types import GetProductsRequest async def demo_simple_api(): @@ -123,12 +123,16 @@ def demo_sync_usage(): print(" import asyncio") print(" from adcp.testing import test_agent") print() - print(" products = asyncio.run(test_agent.simple.get_products(brief='Coffee', buying_mode='brief'))") + print( + " products = asyncio.run(test_agent.simple.get_products(brief='Coffee', buying_mode='brief'))" + ) print(" print(f'Found {len(products.products)} products')") print() print(" # Or create an async function and run it:") print(" async def my_function():") - print(" products = await test_agent.simple.get_products(brief='Coffee', buying_mode='brief')") + print( + " products = await test_agent.simple.get_products(brief='Coffee', buying_mode='brief')" + ) print(" return products") print() print(" result = asyncio.run(my_function())") diff --git a/examples/test_helpers_demo.py b/examples/test_helpers_demo.py index e87c7c48..cf2a687a 100755 --- a/examples/test_helpers_demo.py +++ b/examples/test_helpers_demo.py @@ -16,7 +16,7 @@ test_agent_client, test_agent_no_auth, ) -from adcp.types._generated import GetProductsRequest, ListCreativeFormatsRequest +from adcp.types import GetProductsRequest, ListCreativeFormatsRequest async def simplest_example() -> None: diff --git a/llms.txt b/llms.txt index 2181e714..a4089bbe 100644 --- a/llms.txt +++ b/llms.txt @@ -38,6 +38,7 @@ serve(MySeller(), name="my-seller") - `adcp.server`: ADCPHandler, serve, adcp_server, response builders (seller-side) - `adcp.server.helpers`: adcp_error, valid_actions_for_status, resolve_account, inject_context - `adcp.types`: All Pydantic types (Product, MediaBuy, Creative, etc.) +- `adcp.types.{media_buy,creative,signals,protocol,buyer,seller}`: curated, domain-grouped subsets of `adcp.types` (smaller import surface; same types) - `adcp.types.guards`: Type guards (is_adcp_success, is_adcp_error, typed per-response guards) - `adcp.types.aliases`: Semantic names for discriminated union variants - `adcp.testing`: Pre-configured test agents (test_agent, creative_agent) @@ -56,12 +57,18 @@ serve(MySeller(), name="my-seller") ```python from adcp import ADCPClient, AgentConfig # Client setup from adcp.types import Product, GetProductsRequest # Domain types +from adcp.types.media_buy import CreateMediaBuyRequest # Domain-grouped subset from adcp.types.aliases import CreateMediaBuySuccessResponse # Union variants from adcp.types.guards import is_adcp_success # Response handling from adcp.server import ADCPHandler, serve # Server setup from adcp.server import adcp_error, resolve_account # DX helpers from adcp.server.responses import products_response # Response builders ``` +Which import path: default to `from adcp import X` (stable common surface). +Use `adcp.types.` for a curated domain grouping, or `adcp.types` for +the full surface / rarely-used types. NEVER import `adcp.types.generated_poc.*` +or `adcp.types._generated` — they renumber on every schema regen. +`import adcp` is lightweight; the pydantic type graph builds on first type use. ## Validation ```bash diff --git a/pyproject.toml b/pyproject.toml index e0c56f91..628b410c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules", + "Typing :: Typed", ] dependencies = [ @@ -170,6 +171,11 @@ Issues = "https://github.com/adcontextprotocol/adcp-client-python/issues" [tool.setuptools.packages.find] where = ["src"] +# Explicit: ``adcp.canonical_formats._fixtures`` is a data-only directory served +# via ``importlib.resources.files`` (see adcp.canonical_formats.fixtures). It +# resolves as a namespace package; pin namespaces=true so a future config change +# can't silently stop it from resolving. Guarded by tests/test_canonical_formats_fixtures*. +namespaces = true [tool.setuptools.package-data] adcp = [ diff --git a/src/adcp/__init__.py b/src/adcp/__init__.py index b16ad8c6..ea46db41 100644 --- a/src/adcp/__init__.py +++ b/src/adcp/__init__.py @@ -5,576 +5,47 @@ Official Python client for the Ad Context Protocol (AdCP). Supports both A2A and MCP protocols with full type safety. + +``import adcp`` is lightweight: the generated Pydantic schema graph and the +client / server / protocol stack are imported lazily, the first time a name +that needs them is accessed. ``from adcp import Product`` builds the type +graph; ``from adcp import ADCPError`` does not. Names resolve through the +module-level ``__getattr__`` (PEP 562); type checkers see the full surface +via the ``TYPE_CHECKING`` block at the bottom of this module. """ -from importlib.metadata import PackageNotFoundError -from importlib.metadata import version as _pkg_version +import importlib +import importlib.util +from typing import TYPE_CHECKING -from adcp.adagents import ( - AdagentsCacheEntry, - AdagentsEntryError, - AdagentsFetchResult, - AdagentsValidationReport, - AdAgentsValidationResult, - AgentAuthorizationsDirectoryResult, - AuthorizationContext, - DirectoryDiscoveryMethod, - DirectoryEdgeStatus, - DirectoryPublisherEntry, - DiscoveryMethod, - DivergenceReport, - EntryErrorKind, - PublisherDivergence, - detect_publisher_properties_divergence, - domain_matches, - fetch_adagents, - fetch_adagents_with_cache, - fetch_agent_authorizations, - fetch_agent_authorizations_from_directory, - filter_revoked_selectors, - get_all_properties, - get_all_tags, - get_properties_by_agent, - identifiers_match, - resolve_properties_for_agent, - validate_adagents_domain, - validate_adagents_structure, - verify_agent_authorization, - verify_agent_for_property, -) -from adcp.canonical_formats import ( - format_is_supported, - formats_are_equivalent, - upgrade_legacy_format_id, -) -from adcp.capabilities import ( # noqa: F401 - FeatureResolver, - build_synthetic_capabilities, - looks_like_v3_capabilities, - validate_capabilities, -) -from adcp.client import ADCPClient, ADCPMultiAgentClient, Checkpoint -from adcp.exceptions import ( # noqa: F401 - AdagentsAccessBlockedError, - AdagentsNotFoundError, - AdagentsTimeoutError, - AdagentsValidationError, - ADCPAuthenticationError, - ADCPConnectionError, - ADCPError, - ADCPFeatureUnsupportedError, - ADCPProtocolError, - ADCPSigningRequiredError, - ADCPTaskError, - ADCPTimeoutError, - ADCPToolNotFoundError, - ADCPWebhookError, - ADCPWebhookSignatureError, - ConfigurationError, - IdempotencyConflictError, - IdempotencyExpiredError, - IdempotencyUnsupportedError, - RegistryError, -) -from adcp.feed_mirror import ( - EventHandler, - FeedMirror, - FeedMirrorClient, - FeedMirrorError, - FeedState, - FeedStateStore, - RefreshResult, -) -from adcp.property_registry import PropertyRegistry -from adcp.registry import RegistryClient -from adcp.registry_sync import ( - ChangeHandler, - CursorStore, - FileCursorStore, - RegistrySync, -) +if TYPE_CHECKING: + # ``__version__`` is resolved lazily at runtime (see ``_resolve_version``) + # so ``import adcp`` doesn't pay the ~15ms ``importlib.metadata`` cost. + __version__: str -# Test helpers -from adcp.testing import ( - CREATIVE_AGENT_CONFIG, - TEST_AGENT_A2A_CONFIG, - TEST_AGENT_A2A_NO_AUTH_CONFIG, - TEST_AGENT_MCP_CONFIG, - TEST_AGENT_MCP_NO_AUTH_CONFIG, - TEST_AGENT_TOKEN, - create_test_agent, - creative_agent, - test_agent, - test_agent_a2a, - test_agent_a2a_no_auth, - test_agent_client, - test_agent_no_auth, -) +# Cache for the resolved SDK version. NOT named ``_version`` — that would +# collide with the ``adcp._version`` submodule, which clobbers the cache the +# moment anything imports it. +_sdk_version: str | None = None -# Re-export commonly-used request/response types for convenience -# Users should import from main package (e.g., `from adcp import GetProductsRequest`) -# rather than internal modules for better API stability -# Re-export core domain types and pricing options -# These are commonly used in typical workflows -from adcp.types import ( - # Account types - AccountAuthorization, - AccountReference, - # Type enums from PR #222 - AccountScope, - AccountWithAuthorization, - # Brand Rights - AcquireRightsRequest, - AcquireRightsResponse, - # Audience & Targeting - ActivateSignalRequest, - ActivateSignalResponse, - AdvertiserIndustry, - # Creative types - ArtifactWebhookPayload, - AssetContentType, - AudienceSource, - AuthorizationRequiredDetails, - # Core domain types - BrandReference, - BrandSource, - # Creative Operations - BuildCreativeRequest, - BuildCreativeResponse, - BuyingMode, - # Catalog types - Catalog, - CatalogAction, - CatalogFieldBinding, - CatalogFieldMapping, - CatalogGroupBinding, - CatalogItemStatus, - CatalogRequirements, - CatalogType, - CheckGovernanceRequest, - CheckGovernanceResponse, - ComplyTestControllerRequest, - ComplyTestControllerResponse, - ConsentBasis, - ContentIdType, - ContextMatchRequest, - ContextMatchResponse, - ContextObject, - # Pricing options (all types for product creation) - CpaPricingOption, - CpcPricingOption, - CpcvPricingOption, - CpmAuctionPricingOption, - CpmFixedRatePricingOption, - CpmPricingOption, - CppPricingOption, - CpvPricingOption, - # Media Buy Operations - CreateMediaBuyRequest, - CreateMediaBuyResponse, - Creative, - CreativeApproval, - CreativeApprovalStatus, - CreativeFilters, - CreativeManifest, - # Status enums (for control flow) - CreativeStatus, - CreativeVariant, - DateRange, - DatetimeRange, - DeliveryStatus, - DevicePlatform, - DeviceType, - DownstreamConnectionRequirement, - Duration, - # Common data types - Error, - ErrorCode, - EventType, - ExtensionObject, - FeedFormat, - FlatRatePricingOption, - Format, - FormatId, - FormatOptionReference, - GeneratedTaskStatus, - GetAccountFinancialsRequest, - GetAccountFinancialsResponse, - GetBrandIdentityRequest, - GetBrandIdentityResponse, - # Creative Delivery - GetCreativeDeliveryRequest, - GetCreativeDeliveryResponse, - GetCreativeFeaturesRequest, - GetCreativeFeaturesResponse, - GetMediaBuyDeliveryRequest, - GetMediaBuyDeliveryResponse, - GetMediaBuysRequest, - GetMediaBuysResponse, - GetPlanAuditLogsRequest, - GetPlanAuditLogsResponse, - GetProductsRequest, - GetProductsResponse, - GetRightsRequest, - GetRightsResponse, - GetSignalsRequest, - GetSignalsResponse, - GetTaskStatusRequest, - GetTaskStatusResponse, - Gtin, - IdentityMatchRequest, - IdentityMatchResponse, - KellerType, - # Account Operations - ListAccountsRequest, - ListAccountsResponse, - ListCreativeFormatsRequest, - ListCreativeFormatsResponse, - ListCreativesRequest, - ListCreativesResponse, - ListTasksRequest, - ListTasksResponse, - ListTransformersRequest, - ListTransformersResponse, - # Event Operations - LogEventRequest, - LogEventResponse, - McpWebhookPayload, - MediaBuy, - MediaBuyDeliveryStatus, - MediaBuyDeliveryWebhookResult, - MediaBuyPackage, - MediaBuyStatus, - MediaChannel, - NotificationConfig, - OfferingAssetConstraint, - OfferingAssetGroup, - # Optimization - OptimizationGoal, - # Format overlays - Overlay, - Package, - PackageRequest, - PackageSignalTargeting, - PackageSignalTargetingGroup, - PackageSignalTargetingGroups, - PaginationRequest, - Placement, - PlacementReference, - PreviewCreativeInteractiveResponse, - PreviewCreativeRequest, - PreviewCreativeResponse, - PreviewCreativeStaticResponse, - PriceGuidance, - PricingCurrency, - PricingModel, - Product, - ProductFilters, - ProductSignalTargetingOption, - Property, - PropertyIdActivationKey, - PropertyTagActivationKey, - Proposal, - ProvidePerformanceFeedbackRequest, - ProvidePerformanceFeedbackResponse, - PushNotificationConfig, - Refine, - ReportPlanOutcomeRequest, - ReportPlanOutcomeResponse, - ReportUsageRequest, - ReportUsageResponse, - ResponsePayloadJwsEnvelope, - SellerAgentReference, - SignalAvailabilityType, - SignalCatalogType, - SignalDefinitionEnrichment, - SignalFilters, - SignalListing, - SignalPricingOption, - SignalRef, - SignalTargeting, - SignalTargetingExpression, - SignalTargetingRules, - Snapshot, - SnapshotUnavailableReason, - SyncAccountsRequest, - SyncAccountsResponse, - SyncAudiencesRequest, - SyncAudiencesResponse, - SyncCatalogsInputRequired, - SyncCatalogsRequest, - SyncCatalogsResponse, - SyncCatalogsSubmitted, - SyncCatalogsWorking, - SyncCreativesRequest, - SyncCreativesResponse, - SyncEventSourcesRequest, - SyncEventSourcesResponse, - SyncPlansRequest, - SyncPlansResponse, - TargetingOverlay, - TimeBasedPricingOption, - TimeUnit, - Transform, - UpdateFrequency, - UpdateMediaBuyRequest, - UpdateMediaBuyResponse, - ValidateInputRequest, - ValidateInputResponse, - VcpmAuctionPricingOption, - VcpmFixedRatePricingOption, - VcpmPricingOption, - VerifyBrandClaimPayload, - VerifyBrandClaimRequest, - VerifyBrandClaimResponse, - VerifyBrandClaimsErrorResponse, - VerifyBrandClaimSignedResponse, - VerifyBrandClaimSignedSuccessPayload, - VerifyBrandClaimsPayload, - VerifyBrandClaimsRequest, - VerifyBrandClaimsRequestBulk, - VerifyBrandClaimsResponse, - VerifyBrandClaimsResponseBulk, - VerifyBrandClaimsSignedResponse, - VerifyBrandClaimsSignedSuccessPayload, - WcagLevel, - WebhookChallenge, - WebhookChallengeResponse, - WholesaleFeedEvent, - WholesaleFeedWebhook, - aliases, -) -# Import generated types modules - for internal use -# Note: Users should import specific types, not the whole module -from adcp.types import _generated as generated +def _resolve_version() -> str: + """Return the installed SDK version, resolved once and cached. -# Re-export semantic type aliases for better ergonomics -from adcp.types.aliases import ( - AccountReferenceById, - AccountReferenceByNaturalKey, - AcquireRightsAcquiredResponse, - AcquireRightsErrorResponse, - AcquireRightsPendingResponse, - AcquireRightsRejectedResponse, - AcquireRightsResponse1, - ActivateSignalErrorResponse, - ActivateSignalResponse1, - ActivateSignalSuccessResponse, - AgentDeployment, - AgentDestination, - AuthorizedAgent, - AuthorizedAgentsByInlineProperties, - AuthorizedAgentsByPropertyId, - AuthorizedAgentsByPropertyTag, - AuthorizedAgentsByPublisherProperties, - AuthorizedAgentsBySignalId, - AuthorizedAgentsBySignalTag, - BothPreviewRender, - BuildCreativeErrorResponse, - BuildCreativeResponse1, - BuildCreativeSubmittedResponse, - BuildCreativeSuccessResponse, - CalibrateContentErrorResponse, - CalibrateContentResponse1, - CalibrateContentSuccessResponse, - ComplyTestControllerResponse1, - CreateContentStandardsErrorResponse, - CreateContentStandardsResponse1, - CreateContentStandardsSuccessResponse, - CreateMediaBuyErrorResponse, - CreateMediaBuyResponse1, - CreateMediaBuySubmittedResponse, - CreateMediaBuySuccessResponse, - Deployment, - Destination, - GetAccountFinancialsErrorResponse, - GetAccountFinancialsResponse1, - GetAccountFinancialsSuccessResponse, - GetBrandIdentityErrorResponse, - GetBrandIdentityResponse1, - GetBrandIdentitySuccessResponse, - GetContentStandardsErrorResponse, - GetContentStandardsResponse1, - GetContentStandardsSuccessResponse, - GetCreativeDeliveryByBuyerRefRequest, - GetCreativeDeliveryByCreativeRequest, - GetCreativeDeliveryByMediaBuyRequest, - GetCreativeFeaturesErrorResponse, - GetCreativeFeaturesResponse1, - GetCreativeFeaturesSuccessResponse, - GetMediaBuyArtifactsErrorResponse, - GetMediaBuyArtifactsResponse1, - GetMediaBuyArtifactsSuccessResponse, - GetProductsBriefRequest, - GetProductsRefineRequest, - GetProductsWholesaleRequest, - GetRightsErrorResponse, - GetRightsResponse1, - GetRightsSuccessResponse, - GetSignalsDiscoveryRequest, - GetSignalsLookupRequest, - HtmlPreviewRender, - InlineDaastAsset, - InlineVastAsset, - KeyValueActivationKey, - ListContentStandardsErrorResponse, - ListContentStandardsResponse1, - ListContentStandardsSuccessResponse, - LogEventErrorResponse, - LogEventResponse1, - LogEventSuccessResponse, - PlatformDeployment, - PlatformDestination, - PreviewCreativeBatchResponse, - PreviewCreativeResponse1, - PreviewCreativeSingleResponse, - PreviewCreativeVariantResponse, - PricingOption, - PropertyId, - PropertyTag, - ProvidePerformanceFeedbackByBuyerRefRequest, - ProvidePerformanceFeedbackByMediaBuyRequest, - ProvidePerformanceFeedbackErrorResponse, - ProvidePerformanceFeedbackResponse1, - ProvidePerformanceFeedbackSuccessResponse, - PublisherProperties, - PublisherPropertiesAll, - PublisherPropertiesById, - PublisherPropertiesByTag, - SegmentIdActivationKey, - SiSendActionResponseRequest, - SiSendTextMessageRequest, - SyncAccountsErrorResponse, - SyncAccountsResponse1, - SyncAccountsSuccessResponse, - SyncAudiencesAudience, - SyncAudiencesErrorResponse, - SyncAudiencesResponse1, - SyncAudiencesSubmittedResponse, - SyncAudiencesSuccessResponse, - SyncCatalogResult, - SyncCatalogsErrorResponse, - SyncCatalogsResponse1, - SyncCatalogsSubmittedResponse, - SyncCatalogsSuccessResponse, - SyncCreativeResult, - SyncCreativesErrorResponse, - SyncCreativesResponse1, - SyncCreativesResponse3, - SyncCreativesSubmittedResponse, - SyncCreativesSuccessResponse, - SyncEventSourcesErrorResponse, - SyncEventSourcesResponse1, - SyncEventSourcesSuccessResponse, - UpdateContentStandardsErrorResponse, - UpdateContentStandardsResponse1, - UpdateContentStandardsSuccessResponse, - UpdateMediaBuyErrorResponse, - UpdateMediaBuyPackagesRequest, - UpdateMediaBuyPropertiesRequest, - UpdateMediaBuyResponse1, - UpdateMediaBuyResponse3, - UpdateMediaBuySubmittedResponse, - UpdateMediaBuySuccessResponse, - UrlDaastAsset, - UrlPreviewRender, - UrlVastAsset, - ValidateContentDeliveryErrorResponse, - ValidateContentDeliveryResponse1, - ValidateContentDeliverySuccessResponse, -) -from adcp.types.core import ( - AgentConfig, - Member, - Policy, - PolicyExemplar, - PolicyExemplars, - PolicyHistory, - PolicyRevision, - PolicySummary, - Protocol, - ResolvedBrand, - ResolvedProperty, - TaskResult, - TaskStatus, - WebhookMetadata, -) - -# Re-export type guards for response handling -from adcp.types.guards import is_adcp_error, is_adcp_success # noqa: F401 -from adcp.types.registry import ( - AgentCapabilities, - AgentCompliance, - AgentHealth, - AgentStats, - BrandActivity, - BrandRegistryItem, - DomainLookupResult, - FederatedAgentWithDetails, - FederatedPublisher, - FeedEvent, - FeedPage, - PropertyActivity, - PropertyIdentifier, - PropertyRegistryItem, - PropertySummary, - ValidationResult, -) -from adcp.utils import ( - get_asset_count, - get_format_assets, - get_individual_assets, - get_optional_assets, - get_repeatable_groups, - get_required_assets, - has_assets, - normalize_assets_required, - uses_deprecated_assets_field, -) -from adcp.validation import ( - SchemaValidationError, - UnknownFieldPolicy, - ValidationError, - ValidationHookConfig, - ValidationIssue, - ValidationMode, - ValidationOutcome, - validate_adagents, - validate_agent_authorization, - validate_product, - validate_publisher_properties_item, -) -from adcp.webhooks import ( - LegacyHmacFallback, - MemoryBackend, - WebhookChallengeError, - WebhookChallengeResult, - WebhookDedupStore, - WebhookDestinationPolicy, - WebhookReceiver, - WebhookReceiverConfig, - WebhookSender, - WebhookVerifyOptions, - challenge_webhook_destination, - create_a2a_webhook_payload, - create_mcp_webhook_payload, - create_webhook_challenge_payload, - extract_webhook_result_data, - generate_webhook_challenge_value, - generate_webhook_idempotency_key, - get_adcp_signed_headers_for_webhook, - sign_legacy_webhook, - sign_webhook, - to_wire_dict, - validate_webhook_challenge_response, -) + Deferred out of module import: ``importlib.metadata`` pulls in a sizable + stdlib subtree (~15ms), and most importers never read ``__version__``. + """ + global _sdk_version + if _sdk_version is None: + from importlib.metadata import PackageNotFoundError + from importlib.metadata import version as _pkg_version -try: - __version__ = _pkg_version("adcp") -except PackageNotFoundError: - # Running from a source tree without an installed distribution. - __version__ = "0.0.0+unknown" + try: + _sdk_version = _pkg_version("adcp") + except PackageNotFoundError: + # Running from a source tree without an installed distribution. + _sdk_version = "0.0.0+unknown" + return _sdk_version # Types removed in 4.0 — raise an informative ImportError instead of the @@ -615,13 +86,597 @@ } -def __getattr__(name: str) -> object: - if name in _REMOVED_IN_V4: - hint, anchor = _REMOVED_IN_V4[name] - raise ImportError( - f"`{name}` was removed in adcp 4.0: {hint}. " f"See MIGRATION_v3_to_v4.md#{anchor}." - ) - raise AttributeError(f"module 'adcp' has no attribute {name!r}") +# Lazy re-export map: owning module -> the public names it provides. These +# used to be eager ``from import (...)`` blocks at module top. +# ``__getattr__`` imports the owning module on first access to any of its +# names and caches the result. Grouped by module (and mirrored verbatim in the +# ``TYPE_CHECKING`` block at the bottom) so it stays readable and auditable. +_LAZY_MODULES: dict[str, tuple[str, ...]] = { + "adcp.adagents": ( + "AdagentsCacheEntry", + "AdagentsEntryError", + "AdagentsFetchResult", + "AdagentsValidationReport", + "AdAgentsValidationResult", + "AgentAuthorizationsDirectoryResult", + "AuthorizationContext", + "DirectoryDiscoveryMethod", + "DirectoryEdgeStatus", + "DirectoryPublisherEntry", + "DiscoveryMethod", + "DivergenceReport", + "EntryErrorKind", + "PublisherDivergence", + "detect_publisher_properties_divergence", + "domain_matches", + "fetch_adagents", + "fetch_adagents_with_cache", + "fetch_agent_authorizations", + "fetch_agent_authorizations_from_directory", + "filter_revoked_selectors", + "get_all_properties", + "get_all_tags", + "get_properties_by_agent", + "identifiers_match", + "resolve_properties_for_agent", + "validate_adagents_domain", + "validate_adagents_structure", + "verify_agent_authorization", + "verify_agent_for_property", + ), + "adcp.canonical_formats": ( + "format_is_supported", + "formats_are_equivalent", + "upgrade_legacy_format_id", + ), + "adcp.capabilities": ( + "FeatureResolver", + "build_synthetic_capabilities", + "looks_like_v3_capabilities", + "validate_capabilities", + ), + "adcp.client": ( + "ADCPClient", + "ADCPMultiAgentClient", + "Checkpoint", + ), + "adcp.exceptions": ( + "AdagentsAccessBlockedError", + "AdagentsNotFoundError", + "AdagentsTimeoutError", + "AdagentsValidationError", + "ADCPAuthenticationError", + "ADCPConnectionError", + "ADCPError", + "ADCPFeatureUnsupportedError", + "ADCPProtocolError", + "ADCPSigningRequiredError", + "ADCPTaskError", + "ADCPTimeoutError", + "ADCPToolNotFoundError", + "ADCPWebhookError", + "ADCPWebhookSignatureError", + "ConfigurationError", + "IdempotencyConflictError", + "IdempotencyExpiredError", + "IdempotencyUnsupportedError", + "RegistryError", + ), + "adcp.feed_mirror": ( + "EventHandler", + "FeedMirror", + "FeedMirrorClient", + "FeedMirrorError", + "FeedState", + "FeedStateStore", + "RefreshResult", + ), + "adcp.property_registry": ("PropertyRegistry",), + "adcp.registry": ("RegistryClient",), + "adcp.registry_sync": ( + "ChangeHandler", + "CursorStore", + "FileCursorStore", + "RegistrySync", + ), + "adcp.testing": ( + "CREATIVE_AGENT_CONFIG", + "TEST_AGENT_A2A_CONFIG", + "TEST_AGENT_A2A_NO_AUTH_CONFIG", + "TEST_AGENT_MCP_CONFIG", + "TEST_AGENT_MCP_NO_AUTH_CONFIG", + "TEST_AGENT_TOKEN", + "create_test_agent", + "creative_agent", + "test_agent", + "test_agent_a2a", + "test_agent_a2a_no_auth", + "test_agent_client", + "test_agent_no_auth", + ), + "adcp.types": ( + "AccountAuthorization", + "AccountReference", + "AccountScope", + "AccountWithAuthorization", + "AcquireRightsRequest", + "AcquireRightsResponse", + "ActivateSignalRequest", + "ActivateSignalResponse", + "AdvertiserIndustry", + "ArtifactWebhookPayload", + "AssetContentType", + "AudienceSource", + "AuthorizationRequiredDetails", + "BrandReference", + "BrandSource", + "BuildCreativeRequest", + "BuildCreativeResponse", + "BuyingMode", + "Catalog", + "CatalogAction", + "CatalogFieldBinding", + "CatalogFieldMapping", + "CatalogGroupBinding", + "CatalogItemStatus", + "CatalogRequirements", + "CatalogType", + "CheckGovernanceRequest", + "CheckGovernanceResponse", + "ComplyTestControllerRequest", + "ComplyTestControllerResponse", + "ConsentBasis", + "ContentIdType", + "ContextMatchRequest", + "ContextMatchResponse", + "ContextObject", + "CpaPricingOption", + "CpcPricingOption", + "CpcvPricingOption", + "CpmAuctionPricingOption", + "CpmFixedRatePricingOption", + "CpmPricingOption", + "CppPricingOption", + "CpvPricingOption", + "CreateMediaBuyRequest", + "CreateMediaBuyResponse", + "Creative", + "CreativeApproval", + "CreativeApprovalStatus", + "CreativeFilters", + "CreativeManifest", + "CreativeStatus", + "CreativeVariant", + "DateRange", + "DatetimeRange", + "DeliveryStatus", + "DevicePlatform", + "DeviceType", + "DownstreamConnectionRequirement", + "Duration", + "Error", + "ErrorCode", + "EventType", + "ExtensionObject", + "FeedFormat", + "FlatRatePricingOption", + "Format", + "FormatId", + "FormatOptionReference", + "GeneratedTaskStatus", + "GetAccountFinancialsRequest", + "GetAccountFinancialsResponse", + "GetBrandIdentityRequest", + "GetBrandIdentityResponse", + "GetCreativeDeliveryRequest", + "GetCreativeDeliveryResponse", + "GetCreativeFeaturesRequest", + "GetCreativeFeaturesResponse", + "GetMediaBuyDeliveryRequest", + "GetMediaBuyDeliveryResponse", + "GetMediaBuysRequest", + "GetMediaBuysResponse", + "GetPlanAuditLogsRequest", + "GetPlanAuditLogsResponse", + "GetProductsRequest", + "GetProductsResponse", + "GetRightsRequest", + "GetRightsResponse", + "GetSignalsRequest", + "GetSignalsResponse", + "GetTaskStatusRequest", + "GetTaskStatusResponse", + "Gtin", + "IdentityMatchRequest", + "IdentityMatchResponse", + "KellerType", + "ListAccountsRequest", + "ListAccountsResponse", + "ListCreativeFormatsRequest", + "ListCreativeFormatsResponse", + "ListCreativesRequest", + "ListCreativesResponse", + "ListTasksRequest", + "ListTasksResponse", + "ListTransformersRequest", + "ListTransformersResponse", + "LogEventRequest", + "LogEventResponse", + "McpWebhookPayload", + "MediaBuy", + "MediaBuyDeliveryStatus", + "MediaBuyDeliveryWebhookResult", + "MediaBuyPackage", + "MediaBuyStatus", + "MediaChannel", + "NotificationConfig", + "OfferingAssetConstraint", + "OfferingAssetGroup", + "OptimizationGoal", + "Overlay", + "Package", + "PackageRequest", + "PackageSignalTargeting", + "PackageSignalTargetingGroup", + "PackageSignalTargetingGroups", + "PaginationRequest", + "Placement", + "PlacementReference", + "PreviewCreativeInteractiveResponse", + "PreviewCreativeRequest", + "PreviewCreativeResponse", + "PreviewCreativeStaticResponse", + "PriceGuidance", + "PricingCurrency", + "PricingModel", + "Product", + "ProductFilters", + "ProductSignalTargetingOption", + "Property", + "PropertyIdActivationKey", + "PropertyTagActivationKey", + "Proposal", + "ProvidePerformanceFeedbackRequest", + "ProvidePerformanceFeedbackResponse", + "PushNotificationConfig", + "Refine", + "ReportPlanOutcomeRequest", + "ReportPlanOutcomeResponse", + "ReportUsageRequest", + "ReportUsageResponse", + "ResponsePayloadJwsEnvelope", + "SellerAgentReference", + "SignalAvailabilityType", + "SignalCatalogType", + "SignalDefinitionEnrichment", + "SignalFilters", + "SignalListing", + "SignalPricingOption", + "SignalRef", + "SignalTargeting", + "SignalTargetingExpression", + "SignalTargetingRules", + "Snapshot", + "SnapshotUnavailableReason", + "SyncAccountsRequest", + "SyncAccountsResponse", + "SyncAudiencesRequest", + "SyncAudiencesResponse", + "SyncCatalogsInputRequired", + "SyncCatalogsRequest", + "SyncCatalogsResponse", + "SyncCatalogsSubmitted", + "SyncCatalogsWorking", + "SyncCreativesRequest", + "SyncCreativesResponse", + "SyncEventSourcesRequest", + "SyncEventSourcesResponse", + "SyncPlansRequest", + "SyncPlansResponse", + "TargetingOverlay", + "TimeBasedPricingOption", + "TimeUnit", + "Transform", + "UpdateFrequency", + "UpdateMediaBuyRequest", + "UpdateMediaBuyResponse", + "ValidateInputRequest", + "ValidateInputResponse", + "VcpmAuctionPricingOption", + "VcpmFixedRatePricingOption", + "VcpmPricingOption", + "VerifyBrandClaimPayload", + "VerifyBrandClaimRequest", + "VerifyBrandClaimResponse", + "VerifyBrandClaimsErrorResponse", + "VerifyBrandClaimSignedResponse", + "VerifyBrandClaimSignedSuccessPayload", + "VerifyBrandClaimsPayload", + "VerifyBrandClaimsRequest", + "VerifyBrandClaimsRequestBulk", + "VerifyBrandClaimsResponse", + "VerifyBrandClaimsResponseBulk", + "VerifyBrandClaimsSignedResponse", + "VerifyBrandClaimsSignedSuccessPayload", + "WcagLevel", + "WebhookChallenge", + "WebhookChallengeResponse", + "WholesaleFeedEvent", + "WholesaleFeedWebhook", + "aliases", + "generated", + ), + "adcp.types.aliases": ( + "AccountReferenceById", + "AccountReferenceByNaturalKey", + "AcquireRightsAcquiredResponse", + "AcquireRightsErrorResponse", + "AcquireRightsPendingResponse", + "AcquireRightsRejectedResponse", + "AcquireRightsResponse1", + "ActivateSignalErrorResponse", + "ActivateSignalResponse1", + "ActivateSignalSuccessResponse", + "AgentDeployment", + "AgentDestination", + "AuthorizedAgent", + "AuthorizedAgentsByInlineProperties", + "AuthorizedAgentsByPropertyId", + "AuthorizedAgentsByPropertyTag", + "AuthorizedAgentsByPublisherProperties", + "AuthorizedAgentsBySignalId", + "AuthorizedAgentsBySignalTag", + "BothPreviewRender", + "BuildCreativeErrorResponse", + "BuildCreativeResponse1", + "BuildCreativeSubmittedResponse", + "BuildCreativeSuccessResponse", + "CalibrateContentErrorResponse", + "CalibrateContentResponse1", + "CalibrateContentSuccessResponse", + "ComplyTestControllerResponse1", + "CreateContentStandardsErrorResponse", + "CreateContentStandardsResponse1", + "CreateContentStandardsSuccessResponse", + "CreateMediaBuyErrorResponse", + "CreateMediaBuyResponse1", + "CreateMediaBuySubmittedResponse", + "CreateMediaBuySuccessResponse", + "Deployment", + "Destination", + "GetAccountFinancialsErrorResponse", + "GetAccountFinancialsResponse1", + "GetAccountFinancialsSuccessResponse", + "GetBrandIdentityErrorResponse", + "GetBrandIdentityResponse1", + "GetBrandIdentitySuccessResponse", + "GetContentStandardsErrorResponse", + "GetContentStandardsResponse1", + "GetContentStandardsSuccessResponse", + "GetCreativeDeliveryByBuyerRefRequest", + "GetCreativeDeliveryByCreativeRequest", + "GetCreativeDeliveryByMediaBuyRequest", + "GetCreativeFeaturesErrorResponse", + "GetCreativeFeaturesResponse1", + "GetCreativeFeaturesSuccessResponse", + "GetMediaBuyArtifactsErrorResponse", + "GetMediaBuyArtifactsResponse1", + "GetMediaBuyArtifactsSuccessResponse", + "GetProductsBriefRequest", + "GetProductsRefineRequest", + "GetProductsWholesaleRequest", + "GetRightsErrorResponse", + "GetRightsResponse1", + "GetRightsSuccessResponse", + "GetSignalsDiscoveryRequest", + "GetSignalsLookupRequest", + "HtmlPreviewRender", + "InlineDaastAsset", + "InlineVastAsset", + "KeyValueActivationKey", + "ListContentStandardsErrorResponse", + "ListContentStandardsResponse1", + "ListContentStandardsSuccessResponse", + "LogEventErrorResponse", + "LogEventResponse1", + "LogEventSuccessResponse", + "PlatformDeployment", + "PlatformDestination", + "PreviewCreativeBatchResponse", + "PreviewCreativeResponse1", + "PreviewCreativeSingleResponse", + "PreviewCreativeVariantResponse", + "PricingOption", + "PropertyId", + "PropertyTag", + "ProvidePerformanceFeedbackByBuyerRefRequest", + "ProvidePerformanceFeedbackByMediaBuyRequest", + "ProvidePerformanceFeedbackErrorResponse", + "ProvidePerformanceFeedbackResponse1", + "ProvidePerformanceFeedbackSuccessResponse", + "PublisherProperties", + "PublisherPropertiesAll", + "PublisherPropertiesById", + "PublisherPropertiesByTag", + "SegmentIdActivationKey", + "SiSendActionResponseRequest", + "SiSendTextMessageRequest", + "SyncAccountsErrorResponse", + "SyncAccountsResponse1", + "SyncAccountsSuccessResponse", + "SyncAudiencesAudience", + "SyncAudiencesErrorResponse", + "SyncAudiencesResponse1", + "SyncAudiencesSubmittedResponse", + "SyncAudiencesSuccessResponse", + "SyncCatalogResult", + "SyncCatalogsErrorResponse", + "SyncCatalogsResponse1", + "SyncCatalogsSubmittedResponse", + "SyncCatalogsSuccessResponse", + "SyncCreativeResult", + "SyncCreativesErrorResponse", + "SyncCreativesResponse1", + "SyncCreativesResponse3", + "SyncCreativesSubmittedResponse", + "SyncCreativesSuccessResponse", + "SyncEventSourcesErrorResponse", + "SyncEventSourcesResponse1", + "SyncEventSourcesSuccessResponse", + "UpdateContentStandardsErrorResponse", + "UpdateContentStandardsResponse1", + "UpdateContentStandardsSuccessResponse", + "UpdateMediaBuyErrorResponse", + "UpdateMediaBuyPackagesRequest", + "UpdateMediaBuyPropertiesRequest", + "UpdateMediaBuyResponse1", + "UpdateMediaBuyResponse3", + "UpdateMediaBuySubmittedResponse", + "UpdateMediaBuySuccessResponse", + "UrlDaastAsset", + "UrlPreviewRender", + "UrlVastAsset", + "ValidateContentDeliveryErrorResponse", + "ValidateContentDeliveryResponse1", + "ValidateContentDeliverySuccessResponse", + ), + "adcp.types.core": ( + "AgentConfig", + "Member", + "Policy", + "PolicyExemplar", + "PolicyExemplars", + "PolicyHistory", + "PolicyRevision", + "PolicySummary", + "Protocol", + "ResolvedBrand", + "ResolvedProperty", + "TaskResult", + "TaskStatus", + "WebhookMetadata", + ), + "adcp.types.guards": ( + "is_adcp_error", + "is_adcp_success", + ), + "adcp.types.registry": ( + "AgentCapabilities", + "AgentCompliance", + "AgentHealth", + "AgentStats", + "BrandActivity", + "BrandRegistryItem", + "DomainLookupResult", + "FederatedAgentWithDetails", + "FederatedPublisher", + "FeedEvent", + "FeedPage", + "PropertyActivity", + "PropertyIdentifier", + "PropertyRegistryItem", + "PropertySummary", + "ValidationResult", + ), + "adcp.utils": ( + "get_asset_count", + "get_format_assets", + "get_individual_assets", + "get_optional_assets", + "get_repeatable_groups", + "get_required_assets", + "has_assets", + "normalize_assets_required", + "uses_deprecated_assets_field", + ), + "adcp.validation": ( + "SchemaValidationError", + "UnknownFieldPolicy", + "ValidationError", + "ValidationHookConfig", + "ValidationIssue", + "ValidationMode", + "ValidationOutcome", + "validate_adagents", + "validate_agent_authorization", + "validate_product", + "validate_publisher_properties_item", + ), + "adcp.webhooks": ( + "LegacyHmacFallback", + "MemoryBackend", + "WebhookChallengeError", + "WebhookChallengeResult", + "WebhookDedupStore", + "WebhookDestinationPolicy", + "WebhookReceiver", + "WebhookReceiverConfig", + "WebhookSender", + "WebhookVerifyOptions", + "challenge_webhook_destination", + "create_a2a_webhook_payload", + "create_mcp_webhook_payload", + "create_webhook_challenge_payload", + "extract_webhook_result_data", + "generate_webhook_challenge_value", + "generate_webhook_idempotency_key", + "get_adcp_signed_headers_for_webhook", + "sign_legacy_webhook", + "sign_webhook", + "to_wire_dict", + "validate_webhook_challenge_response", + ), +} + +# name -> owning module (inverted once at import; cheap, strings only). +_LAZY: dict[str, str] = {name: module for module, names in _LAZY_MODULES.items() for name in names} + + +if not TYPE_CHECKING: + # Defined under ``not TYPE_CHECKING`` so type checkers do NOT see a + # module-level ``__getattr__`` (which would silence missing-attribute + # errors and type every unknown name as ``object``). At type-check time the + # surface comes only from the explicit ``TYPE_CHECKING`` block at the bottom + # of this module, so ``from adcp import Typo`` is flagged. At runtime these + # provide the lazy PEP 562 resolution. + + def __getattr__(name): + """Lazily resolve the public ``adcp`` surface (PEP 562). + + Resolution order: (1) ``__version__`` resolves on demand; (2) names + removed in 4.0 raise an informative :class:`ImportError`; (3) re-exported + symbols are imported from their owning module and cached; (4) real + submodules pass through to the import system so ``adcp.`` + attribute access keeps working. + """ + if name == "__version__": + value = _resolve_version() + globals()["__version__"] = value + return value + + if name in _REMOVED_IN_V4: + hint, anchor = _REMOVED_IN_V4[name] + raise ImportError( + f"`{name}` was removed in adcp 4.0: {hint}. " f"See MIGRATION_v3_to_v4.md#{anchor}." + ) + + module_path = _LAZY.get(name) + if module_path is not None: + value = getattr(importlib.import_module(module_path), name) + globals()[name] = value # cache: __getattr__ fires once per name + return value + + # Submodule passthrough — expose ``adcp.`` for real submodules so + # attribute access (not just ``import adcp.``) resolves as before. + if not name.startswith("__") and importlib.util.find_spec(f"adcp.{name}") is not None: + module = importlib.import_module(f"adcp.{name}") + globals()[name] = module + return module + + raise AttributeError(f"module 'adcp' has no attribute {name!r}") + + def __dir__(): + return sorted(set(__all__) | set(_LAZY) | set(globals()) | {"__version__"}) def get_adcp_spec_version() -> str: @@ -663,7 +718,7 @@ def get_adcp_sdk_version() -> str: SDK package version string. Falls back to ``"0.0.0+unknown"`` when running from an uninstalled source tree. """ - return __version__ + return _resolve_version() def get_adcp_version() -> str: @@ -1217,3 +1272,552 @@ def get_adcp_version() -> str: "PreviewCreativeStaticResponse", # Backward compat: types removed from upstream schemas ] + + +if TYPE_CHECKING: + # Eager re-exports for type checkers / IDEs. Resolved lazily at runtime + # via ``__getattr__`` so ``import adcp`` does not build the schema graph. + from adcp.adagents import ( + AdagentsCacheEntry, + AdagentsEntryError, + AdagentsFetchResult, + AdagentsValidationReport, + AdAgentsValidationResult, + AgentAuthorizationsDirectoryResult, + AuthorizationContext, + DirectoryDiscoveryMethod, + DirectoryEdgeStatus, + DirectoryPublisherEntry, + DiscoveryMethod, + DivergenceReport, + EntryErrorKind, + PublisherDivergence, + detect_publisher_properties_divergence, + domain_matches, + fetch_adagents, + fetch_adagents_with_cache, + fetch_agent_authorizations, + fetch_agent_authorizations_from_directory, + filter_revoked_selectors, + get_all_properties, + get_all_tags, + get_properties_by_agent, + identifiers_match, + resolve_properties_for_agent, + validate_adagents_domain, + validate_adagents_structure, + verify_agent_authorization, + verify_agent_for_property, + ) + from adcp.canonical_formats import ( + format_is_supported, + formats_are_equivalent, + upgrade_legacy_format_id, + ) + from adcp.capabilities import ( # noqa: F401 + FeatureResolver, + build_synthetic_capabilities, + looks_like_v3_capabilities, + validate_capabilities, + ) + from adcp.client import ADCPClient, ADCPMultiAgentClient, Checkpoint + from adcp.exceptions import ( # noqa: F401 + AdagentsAccessBlockedError, + AdagentsNotFoundError, + AdagentsTimeoutError, + AdagentsValidationError, + ADCPAuthenticationError, + ADCPConnectionError, + ADCPError, + ADCPFeatureUnsupportedError, + ADCPProtocolError, + ADCPSigningRequiredError, + ADCPTaskError, + ADCPTimeoutError, + ADCPToolNotFoundError, + ADCPWebhookError, + ADCPWebhookSignatureError, + ConfigurationError, + IdempotencyConflictError, + IdempotencyExpiredError, + IdempotencyUnsupportedError, + RegistryError, + ) + from adcp.feed_mirror import ( + EventHandler, + FeedMirror, + FeedMirrorClient, + FeedMirrorError, + FeedState, + FeedStateStore, + RefreshResult, + ) + from adcp.property_registry import PropertyRegistry + from adcp.registry import RegistryClient + from adcp.registry_sync import ( + ChangeHandler, + CursorStore, + FileCursorStore, + RegistrySync, + ) + from adcp.testing import ( + CREATIVE_AGENT_CONFIG, + TEST_AGENT_A2A_CONFIG, + TEST_AGENT_A2A_NO_AUTH_CONFIG, + TEST_AGENT_MCP_CONFIG, + TEST_AGENT_MCP_NO_AUTH_CONFIG, + TEST_AGENT_TOKEN, + create_test_agent, + creative_agent, + test_agent, + test_agent_a2a, + test_agent_a2a_no_auth, + test_agent_client, + test_agent_no_auth, + ) + from adcp.types import ( + # Account types + AccountAuthorization, + AccountReference, + # Type enums from PR #222 + AccountScope, + AccountWithAuthorization, + # Brand Rights + AcquireRightsRequest, + AcquireRightsResponse, + # Audience & Targeting + ActivateSignalRequest, + ActivateSignalResponse, + AdvertiserIndustry, + # Creative types + ArtifactWebhookPayload, + AssetContentType, + AudienceSource, + AuthorizationRequiredDetails, + # Core domain types + BrandReference, + BrandSource, + # Creative Operations + BuildCreativeRequest, + BuildCreativeResponse, + BuyingMode, + # Catalog types + Catalog, + CatalogAction, + CatalogFieldBinding, + CatalogFieldMapping, + CatalogGroupBinding, + CatalogItemStatus, + CatalogRequirements, + CatalogType, + CheckGovernanceRequest, + CheckGovernanceResponse, + ComplyTestControllerRequest, + ComplyTestControllerResponse, + ConsentBasis, + ContentIdType, + ContextMatchRequest, + ContextMatchResponse, + ContextObject, + # Pricing options (all types for product creation) + CpaPricingOption, + CpcPricingOption, + CpcvPricingOption, + CpmAuctionPricingOption, + CpmFixedRatePricingOption, + CpmPricingOption, + CppPricingOption, + CpvPricingOption, + # Media Buy Operations + CreateMediaBuyRequest, + CreateMediaBuyResponse, + Creative, + CreativeApproval, + CreativeApprovalStatus, + CreativeFilters, + CreativeManifest, + # Status enums (for control flow) + CreativeStatus, + CreativeVariant, + DateRange, + DatetimeRange, + DeliveryStatus, + DevicePlatform, + DeviceType, + DownstreamConnectionRequirement, + Duration, + # Common data types + Error, + ErrorCode, + EventType, + ExtensionObject, + FeedFormat, + FlatRatePricingOption, + Format, + FormatId, + FormatOptionReference, + GeneratedTaskStatus, + GetAccountFinancialsRequest, + GetAccountFinancialsResponse, + GetBrandIdentityRequest, + GetBrandIdentityResponse, + # Creative Delivery + GetCreativeDeliveryRequest, + GetCreativeDeliveryResponse, + GetCreativeFeaturesRequest, + GetCreativeFeaturesResponse, + GetMediaBuyDeliveryRequest, + GetMediaBuyDeliveryResponse, + GetMediaBuysRequest, + GetMediaBuysResponse, + GetPlanAuditLogsRequest, + GetPlanAuditLogsResponse, + GetProductsRequest, + GetProductsResponse, + GetRightsRequest, + GetRightsResponse, + GetSignalsRequest, + GetSignalsResponse, + GetTaskStatusRequest, + GetTaskStatusResponse, + Gtin, + IdentityMatchRequest, + IdentityMatchResponse, + KellerType, + # Account Operations + ListAccountsRequest, + ListAccountsResponse, + ListCreativeFormatsRequest, + ListCreativeFormatsResponse, + ListCreativesRequest, + ListCreativesResponse, + ListTasksRequest, + ListTasksResponse, + ListTransformersRequest, + ListTransformersResponse, + # Event Operations + LogEventRequest, + LogEventResponse, + McpWebhookPayload, + MediaBuy, + MediaBuyDeliveryStatus, + MediaBuyDeliveryWebhookResult, + MediaBuyPackage, + MediaBuyStatus, + MediaChannel, + NotificationConfig, + OfferingAssetConstraint, + OfferingAssetGroup, + # Optimization + OptimizationGoal, + # Format overlays + Overlay, + Package, + PackageRequest, + PackageSignalTargeting, + PackageSignalTargetingGroup, + PackageSignalTargetingGroups, + PaginationRequest, + Placement, + PlacementReference, + PreviewCreativeInteractiveResponse, + PreviewCreativeRequest, + PreviewCreativeResponse, + PreviewCreativeStaticResponse, + PriceGuidance, + PricingCurrency, + PricingModel, + Product, + ProductFilters, + ProductSignalTargetingOption, + Property, + PropertyIdActivationKey, + PropertyTagActivationKey, + Proposal, + ProvidePerformanceFeedbackRequest, + ProvidePerformanceFeedbackResponse, + PushNotificationConfig, + Refine, + ReportPlanOutcomeRequest, + ReportPlanOutcomeResponse, + ReportUsageRequest, + ReportUsageResponse, + ResponsePayloadJwsEnvelope, + SellerAgentReference, + SignalAvailabilityType, + SignalCatalogType, + SignalDefinitionEnrichment, + SignalFilters, + SignalListing, + SignalPricingOption, + SignalRef, + SignalTargeting, + SignalTargetingExpression, + SignalTargetingRules, + Snapshot, + SnapshotUnavailableReason, + SyncAccountsRequest, + SyncAccountsResponse, + SyncAudiencesRequest, + SyncAudiencesResponse, + SyncCatalogsInputRequired, + SyncCatalogsRequest, + SyncCatalogsResponse, + SyncCatalogsSubmitted, + SyncCatalogsWorking, + SyncCreativesRequest, + SyncCreativesResponse, + SyncEventSourcesRequest, + SyncEventSourcesResponse, + SyncPlansRequest, + SyncPlansResponse, + TargetingOverlay, + TimeBasedPricingOption, + TimeUnit, + Transform, + UpdateFrequency, + UpdateMediaBuyRequest, + UpdateMediaBuyResponse, + ValidateInputRequest, + ValidateInputResponse, + VcpmAuctionPricingOption, + VcpmFixedRatePricingOption, + VcpmPricingOption, + VerifyBrandClaimPayload, + VerifyBrandClaimRequest, + VerifyBrandClaimResponse, + VerifyBrandClaimsErrorResponse, + VerifyBrandClaimSignedResponse, + VerifyBrandClaimSignedSuccessPayload, + VerifyBrandClaimsPayload, + VerifyBrandClaimsRequest, + VerifyBrandClaimsRequestBulk, + VerifyBrandClaimsResponse, + VerifyBrandClaimsResponseBulk, + VerifyBrandClaimsSignedResponse, + VerifyBrandClaimsSignedSuccessPayload, + WcagLevel, + WebhookChallenge, + WebhookChallengeResponse, + WholesaleFeedEvent, + WholesaleFeedWebhook, + aliases, + ) + from adcp.types import _generated as generated + from adcp.types.aliases import ( + AccountReferenceById, + AccountReferenceByNaturalKey, + AcquireRightsAcquiredResponse, + AcquireRightsErrorResponse, + AcquireRightsPendingResponse, + AcquireRightsRejectedResponse, + AcquireRightsResponse1, + ActivateSignalErrorResponse, + ActivateSignalResponse1, + ActivateSignalSuccessResponse, + AgentDeployment, + AgentDestination, + AuthorizedAgent, + AuthorizedAgentsByInlineProperties, + AuthorizedAgentsByPropertyId, + AuthorizedAgentsByPropertyTag, + AuthorizedAgentsByPublisherProperties, + AuthorizedAgentsBySignalId, + AuthorizedAgentsBySignalTag, + BothPreviewRender, + BuildCreativeErrorResponse, + BuildCreativeResponse1, + BuildCreativeSubmittedResponse, + BuildCreativeSuccessResponse, + CalibrateContentErrorResponse, + CalibrateContentResponse1, + CalibrateContentSuccessResponse, + ComplyTestControllerResponse1, + CreateContentStandardsErrorResponse, + CreateContentStandardsResponse1, + CreateContentStandardsSuccessResponse, + CreateMediaBuyErrorResponse, + CreateMediaBuyResponse1, + CreateMediaBuySubmittedResponse, + CreateMediaBuySuccessResponse, + Deployment, + Destination, + GetAccountFinancialsErrorResponse, + GetAccountFinancialsResponse1, + GetAccountFinancialsSuccessResponse, + GetBrandIdentityErrorResponse, + GetBrandIdentityResponse1, + GetBrandIdentitySuccessResponse, + GetContentStandardsErrorResponse, + GetContentStandardsResponse1, + GetContentStandardsSuccessResponse, + GetCreativeDeliveryByBuyerRefRequest, + GetCreativeDeliveryByCreativeRequest, + GetCreativeDeliveryByMediaBuyRequest, + GetCreativeFeaturesErrorResponse, + GetCreativeFeaturesResponse1, + GetCreativeFeaturesSuccessResponse, + GetMediaBuyArtifactsErrorResponse, + GetMediaBuyArtifactsResponse1, + GetMediaBuyArtifactsSuccessResponse, + GetProductsBriefRequest, + GetProductsRefineRequest, + GetProductsWholesaleRequest, + GetRightsErrorResponse, + GetRightsResponse1, + GetRightsSuccessResponse, + GetSignalsDiscoveryRequest, + GetSignalsLookupRequest, + HtmlPreviewRender, + InlineDaastAsset, + InlineVastAsset, + KeyValueActivationKey, + ListContentStandardsErrorResponse, + ListContentStandardsResponse1, + ListContentStandardsSuccessResponse, + LogEventErrorResponse, + LogEventResponse1, + LogEventSuccessResponse, + PlatformDeployment, + PlatformDestination, + PreviewCreativeBatchResponse, + PreviewCreativeResponse1, + PreviewCreativeSingleResponse, + PreviewCreativeVariantResponse, + PricingOption, + PropertyId, + PropertyTag, + ProvidePerformanceFeedbackByBuyerRefRequest, + ProvidePerformanceFeedbackByMediaBuyRequest, + ProvidePerformanceFeedbackErrorResponse, + ProvidePerformanceFeedbackResponse1, + ProvidePerformanceFeedbackSuccessResponse, + PublisherProperties, + PublisherPropertiesAll, + PublisherPropertiesById, + PublisherPropertiesByTag, + SegmentIdActivationKey, + SiSendActionResponseRequest, + SiSendTextMessageRequest, + SyncAccountsErrorResponse, + SyncAccountsResponse1, + SyncAccountsSuccessResponse, + SyncAudiencesAudience, + SyncAudiencesErrorResponse, + SyncAudiencesResponse1, + SyncAudiencesSubmittedResponse, + SyncAudiencesSuccessResponse, + SyncCatalogResult, + SyncCatalogsErrorResponse, + SyncCatalogsResponse1, + SyncCatalogsSubmittedResponse, + SyncCatalogsSuccessResponse, + SyncCreativeResult, + SyncCreativesErrorResponse, + SyncCreativesResponse1, + SyncCreativesResponse3, + SyncCreativesSubmittedResponse, + SyncCreativesSuccessResponse, + SyncEventSourcesErrorResponse, + SyncEventSourcesResponse1, + SyncEventSourcesSuccessResponse, + UpdateContentStandardsErrorResponse, + UpdateContentStandardsResponse1, + UpdateContentStandardsSuccessResponse, + UpdateMediaBuyErrorResponse, + UpdateMediaBuyPackagesRequest, + UpdateMediaBuyPropertiesRequest, + UpdateMediaBuyResponse1, + UpdateMediaBuyResponse3, + UpdateMediaBuySubmittedResponse, + UpdateMediaBuySuccessResponse, + UrlDaastAsset, + UrlPreviewRender, + UrlVastAsset, + ValidateContentDeliveryErrorResponse, + ValidateContentDeliveryResponse1, + ValidateContentDeliverySuccessResponse, + ) + from adcp.types.core import ( + AgentConfig, + Member, + Policy, + PolicyExemplar, + PolicyExemplars, + PolicyHistory, + PolicyRevision, + PolicySummary, + Protocol, + ResolvedBrand, + ResolvedProperty, + TaskResult, + TaskStatus, + WebhookMetadata, + ) + from adcp.types.guards import is_adcp_error, is_adcp_success # noqa: F401 + from adcp.types.registry import ( + AgentCapabilities, + AgentCompliance, + AgentHealth, + AgentStats, + BrandActivity, + BrandRegistryItem, + DomainLookupResult, + FederatedAgentWithDetails, + FederatedPublisher, + FeedEvent, + FeedPage, + PropertyActivity, + PropertyIdentifier, + PropertyRegistryItem, + PropertySummary, + ValidationResult, + ) + from adcp.utils import ( + get_asset_count, + get_format_assets, + get_individual_assets, + get_optional_assets, + get_repeatable_groups, + get_required_assets, + has_assets, + normalize_assets_required, + uses_deprecated_assets_field, + ) + from adcp.validation import ( + SchemaValidationError, + UnknownFieldPolicy, + ValidationError, + ValidationHookConfig, + ValidationIssue, + ValidationMode, + ValidationOutcome, + validate_adagents, + validate_agent_authorization, + validate_product, + validate_publisher_properties_item, + ) + from adcp.webhooks import ( + LegacyHmacFallback, + MemoryBackend, + WebhookChallengeError, + WebhookChallengeResult, + WebhookDedupStore, + WebhookDestinationPolicy, + WebhookReceiver, + WebhookReceiverConfig, + WebhookSender, + WebhookVerifyOptions, + challenge_webhook_destination, + create_a2a_webhook_payload, + create_mcp_webhook_payload, + create_webhook_challenge_payload, + extract_webhook_result_data, + generate_webhook_challenge_value, + generate_webhook_idempotency_key, + get_adcp_signed_headers_for_webhook, + sign_legacy_webhook, + sign_webhook, + to_wire_dict, + validate_webhook_challenge_response, + ) diff --git a/src/adcp/types/__init__.py b/src/adcp/types/__init__.py index 1acb5625..d642b8c3 100644 --- a/src/adcp/types/__init__.py +++ b/src/adcp/types/__init__.py @@ -6,9 +6,25 @@ from adcp.types import Product, CreativeFilters from adcp import Product, CreativeFilters +This package is lazy: ``import adcp.types`` is cheap and does not build the +generated Pydantic schema graph. The graph (and its import-time coercion / +forward-compat patching) is realized on first access to any type symbol, +via :mod:`adcp.types._eager`. So ``from adcp.types import Product`` works as +a stable compatibility path, resolved through ``__getattr__`` (PEP 562). + +For a narrower, curated surface, import a partial module instead: + + from adcp.types.media_buy import CreateMediaBuyRequest + from adcp.types.creative import Format + from adcp.types.signals import GetSignalsRequest + from adcp.types.protocol import Error, Pagination + from adcp.types.buyer import GetProductsRequest + from adcp.types.seller import Offering, PropertyList + IMPORTANT: Never import directly from adcp.types.generated_poc or adcp.types._generated. These are internal modules regenerated from -upstream schemas. Only import from adcp.types (this module) or adcp. +upstream schemas. Only import from adcp.types (this module), one of the +partial modules above, or adcp. Type Coercion: Request types accept flexible input for developer ergonomics: @@ -27,870 +43,16 @@ from __future__ import annotations +import importlib +import importlib.util +from typing import TYPE_CHECKING + __pdoc__ = { "generated_poc": False, "mypy_plugin": False, + "_eager": False, } -# Apply type coercion to generated types (must be imported before other types) -# Note: the deprecation shim for the removed ``format_category`` submodule -# lives as a real file at ``generated_poc/enums/format_category.py`` — no -# sys.modules dance needed; Python's import system picks it up natively. -# ``scripts/post_generate_fixes.py`` restores that file after codegen wipes -# ``generated_poc/``. -from adcp.types import ( - _ergonomic, # noqa: F401 - _forward_compat, # noqa: F401 # imports FormatAssetUnion from aliases (triggers aliases import) - aliases, # noqa: F401 -) - -# Also make submodules available for advanced use -from adcp.types import _generated as generated # noqa: F401 - -# Import all types from generated code -# V3 Protocol Discovery types -# V3 Content Standards types -# V3 Sponsored Intelligence types -# V3 Governance (Property Lists) types -# Re-export webhook payload type for webhook handling -from adcp.types._generated import ( - A2UiComponent, - A2UiSurface, - Account, - AccountAuthorization, - AccountReference, - AccountScope, - AccountWithAuthorization, - AcquireRightsRequest, - AcquireRightsResponse, - ActivateSignalRequest, - ActivateSignalResponse, - AdcpProtocol, - AdvertiserIndustry, - AggregatedTotals, - AiTool, - Artifact, - ArtifactWebhookPayload, - AssetContentType, - AssignedPackage, - Assignments, - AudienceSource, - Authentication, - AuthenticationScheme, - AuthorizationRequiredDetails, - AuthorizedAgents, - AvailableMetric, - AvailablePackage, - BrandReference, - BuildCreativeRequest, - BuildCreativeResponse, - BusinessEntity, - BuyingMode, - ByPackageItem, - CalibrateContentRequest, - CalibrateContentResponse, - Catalog, - CatalogAction, - CatalogFieldBinding, - CatalogFieldBinding1, - CatalogFieldMapping, - CatalogItemStatus, - CatalogRequirements, - CatalogType, - CheckGovernanceRequest, - CheckGovernanceResponse, - CoBrandingRequirement, - CollectionList, - CollectionListChangedWebhook, - CollectionListFilters, - Colors, - ComplyTestControllerRequest, - ComplyTestControllerResponse, - Contact, - ContentIdType, - ContentStandards, - ContextMatchRequest, - ContextMatchResponse, - ContextObject, - Country, - CpaPricingOption, - CpcPricingOption, - CpcvPricingOption, - CpmPricingOption, - CppPricingOption, - CpvPricingOption, - CreateCollectionListRequest, - CreateCollectionListResponse, - CreateContentStandardsRequest, - CreateContentStandardsResponse, - CreateMediaBuyRequest, - CreateMediaBuyResponse, - CreatePropertyListRequest, - CreatePropertyListResponse, - Creative, - CreativeAction, - CreativeAgent, - CreativeAgentCapability, - CreativeApproval, - CreativeApprovalStatus, - CreativeAsset, - CreativeAssignment, - CreativeFilters, - CreativeManifest, - CreativePolicy, - CreativeStatus, - CreativeVariant, - CreditLimit, - DaastTrackingEvent, - DaastVersion, - DailyBreakdownItem, - DateRange, - DatetimeRange, - DayOfWeek, - DaypartTarget, - DeleteCollectionListRequest, - DeleteCollectionListResponse, - DeletePropertyListRequest, - DeletePropertyListResponse, - DeliveryForecast, - DeliveryMeasurement, - DeliveryMetrics, - DeliveryStatus, - DeliveryType, - DemographicSystem, - DevicePlatform, - DeviceType, - Dimensions, - DimensionUnit, - DoohMetrics, - DownstreamConnectionRequirement, - Duration, - ErrorCode, - EventType, - ExtensionObject, - FeedbackSource, - FeedFormat, - Field1, - FieldModel, - FlatRatePricingOption, - ForecastableMetric, - ForecastMethod, - ForecastPoint, - ForecastRange, - ForecastRangeUnit, - Format, - FormatCard, - FormatCardDetailed, - FormatIdParameter, - FormatOptionReference, - FormatReferenceStructuredObject, - FrequencyCap, - FrequencyCapScope, - GeoCountry, - GeoMetro, - GeoRegion, - GetAccountFinancialsRequest, - GetAccountFinancialsResponse, - GetAdcpCapabilitiesRequest, - GetAdcpCapabilitiesResponse, - GetBrandIdentityRequest, - GetBrandIdentityResponse, - GetCollectionListRequest, - GetCollectionListResponse, - GetContentStandardsRequest, - GetContentStandardsResponse, - GetCreativeDeliveryRequest, - GetCreativeDeliveryResponse, - GetCreativeFeaturesRequest, - GetCreativeFeaturesResponse, - GetMediaBuyArtifactsRequest, - GetMediaBuyArtifactsResponse, - GetMediaBuyDeliveryRequest, - GetMediaBuyDeliveryResponse, - GetMediaBuysRequest, - GetMediaBuysResponse, - GetPlanAuditLogsRequest, - GetPlanAuditLogsResponse, - GetProductsRequest, - GetProductsResponse, - GetPropertyListRequest, - GetPropertyListResponse, - GetRightsRequest, - GetRightsResponse, - GetSignalsRequest, - GetSignalsResponse, - GetTaskStatusRequest, - GetTaskStatusResponse, - GovernanceAgent, - Gtin, - HttpMethod, - Identifier, - IdentityMatchRequest, - IdentityMatchResponse, - Input, - JavascriptModuleType, - KellerType, - LandingPageRequirement, - ListAccountsRequest, - ListAccountsResponse, - ListCollectionListsRequest, - ListCollectionListsResponse, - ListContentStandardsRequest, - ListContentStandardsResponse, - ListCreativeFormatsRequest, - ListCreativeFormatsResponse, - ListCreativesRequest, - ListCreativesResponse, - ListPropertyListsRequest, - ListPropertyListsResponse, - ListTasksRequest, - ListTasksResponse, - LogEventRequest, - LogEventResponse, - Logo, - MarkdownFlavor, - McpWebhookPayload, - MeasurementPeriod, - MediaBuy, - MediaBuyDelivery, - MediaBuyDeliveryWebhookResult, - MediaBuyFeatures, - MediaBuyPackage, - MediaBuyStatus, - MediaChannel, - Metadata, - NotificationConfig, - NotificationType, - Offering, - OfferingAssetConstraint, - OfferingAssetGroup, - OfferPrice, - OptimizationGoal, - Overlay, - Pacing, - PackageRequest, - PackageSignalTargeting, - PackageSignalTargetingGroup, - PackageSignalTargetingGroups, - PackageUpdate, - Pagination, - PaginationRequest, - PaginationResponse, - Parameters, - PaymentTerms, - PerformanceFeedback, - Placement, - PlacementReference, - PostalArea, - PreviewCreativeRequest, - PreviewCreativeResponse, - PreviewOutputFormat, - PreviewRender, - PriceGuidance, - PricingCurrency, - PricingModel, - PrimaryCountry, - Product, - ProductCard, - ProductCardDetailed, - ProductFilters, - ProductSignalTargetingOption, - Property, - PropertyIdentifierTypes, - PropertyList, - PropertyListChangedWebhook, - PropertyListFilters, - PropertyListReference, - PropertyType, - Proposal, - ProtocolEnvelope, - ProtocolResponse, - ProvidePerformanceFeedbackRequest, - ProvidePerformanceFeedbackResponse, - PublisherDomain, - PublisherIdentifierTypes, - PushNotificationConfig, - QuartileData, - QuerySummary, - ReachUnit, - Refine, - RefinementApplied, - RefinementApplied1, - RefinementApplied2, - RefinementApplied3, - Renders, - ReportingBucket, - ReportingCapabilities, - ReportingFrequency, - ReportingPeriod, - ReportingWebhook, - ReportPlanOutcomeRequest, - ReportPlanOutcomeResponse, - ReportUsageRequest, - ReportUsageResponse, - Request, - Response, - ResponsePayloadJwsEnvelope, - Responsive, - RightsPricingOption, - RightsTerms, - Security, - SellerAgentReference, - Setup, - SiCapabilities, - SiGetOfferingRequest, - SiGetOfferingResponse, - Signal, - SignalAvailabilityType, - SignalCatalogType, - SignalDefinitionEnrichment, - SignalFilters, - SignalListing, - SignalPricingOption, - SignalRef, - SignalTargeting, - SignalTargetingExpression, - SignalTargetingRules, - SiIdentity, - SiInitiateSessionRequest, - SiInitiateSessionResponse, - SiSendMessageRequest, - SiSendMessageResponse, - SiTerminateSessionRequest, - SiTerminateSessionResponse, - SiUiElement, - Snapshot, - SnapshotUnavailableReason, - Sort, - SortApplied, - SortDirection, - StatusSummary, - SyncAccountsRequest, - SyncAccountsResponse, - SyncAudiencesRequest, - SyncAudiencesResponse, - SyncCatalogsInputRequired, - SyncCatalogsRequest, - SyncCatalogsResponse, - SyncCatalogsSubmitted, - SyncCatalogsWorking, - SyncCreativesRequest, - SyncCreativesResponse, - SyncEventSourcesRequest, - SyncEventSourcesResponse, - SyncGovernanceRequest, - SyncGovernanceResponse, - SyncPlansRequest, - SyncPlansResponse, - Tags, - TargetingOverlay, - TaskType, - TimeBasedPricingOption, - TimeUnit, - TmpError, - Totals, - Transform, - UpdateCollectionListRequest, - UpdateCollectionListResponse, - UpdateContentStandardsRequest, - UpdateContentStandardsResponse, - UpdateFrequency, - UpdateMediaBuyRequest, - UpdateMediaBuyResponse, - UpdatePropertyListRequest, - UpdatePropertyListResponse, - UpdateRightsRequest, - UpdateRightsResponse, - UrlAssetType, - ValidateContentDeliveryRequest, - ValidateContentDeliveryResponse, - ValidateInputRequest, - ValidateInputResponse, - ValidationMode, - VastTrackingEvent, - VastVersion, - VcpmPricingOption, - VenueBreakdownItem, - VerifyBrandClaimPayload, - VerifyBrandClaimRequest, - VerifyBrandClaimResponse, - VerifyBrandClaimsErrorResponse, - VerifyBrandClaimSignedResponse, - VerifyBrandClaimSignedSuccessPayload, - VerifyBrandClaimsPayload, - VerifyBrandClaimsRequest, - VerifyBrandClaimsRequestBulk, - VerifyBrandClaimsResponse, - VerifyBrandClaimsResponseBulk, - VerifyBrandClaimsSignedResponse, - VerifyBrandClaimsSignedSuccessPayload, - ViewThreshold, - WcagLevel, - WebhookChallenge, - WebhookChallengeResponse, - WebhookResponseType, - WholesaleFeedEvent, - WholesaleFeedWebhook, -) -from adcp.types._generated import ( - AudioAsset as AudioContent, -) -from adcp.types._generated import ( - CssAsset as CssContent, -) -from adcp.types._generated import ( - HtmlAsset as HtmlContent, -) -from adcp.types._generated import ( - ImageAsset as ImageContent, -) -from adcp.types._generated import ( - JavascriptAsset as JavascriptContent, -) -from adcp.types._generated import ( - ListTransformersRequestCreativeAgent as ListTransformersRequest, -) -from adcp.types._generated import ( - ListTransformersResponseCreativeAgent as ListTransformersResponse, -) -from adcp.types._generated import ( - Offer as TmpOffer, -) -from adcp.types._generated import TaskStatus as GeneratedTaskStatus -from adcp.types._generated import ( - TextAsset as TextContent, -) -from adcp.types._generated import ( - UrlAsset as UrlContent, -) -from adcp.types._generated import ( - VideoAsset as VideoContent, -) -from adcp.types._generated import ( - WebhookAsset as WebhookContent, -) -from adcp.types._generated import _ErrorFromError as Error -from adcp.types._generated import _PackageFromPackage as Package - -# Import semantic aliases for discriminated unions -from adcp.types.aliases import ( - AccountReferenceById, - AccountReferenceByNaturalKey, - AcquireRightsAcquiredResponse, - AcquireRightsErrorResponse, - AcquireRightsPendingResponse, - AcquireRightsRejectedResponse, - AcquireRightsResponse1, - ActivateSignalErrorResponse, - ActivateSignalResponse1, - ActivateSignalSuccessResponse, - AgentDeployment, - AgentDestination, - AudioFormatAsset, - AudioFormatGroupAsset, - AuthorizedAgent, - AuthorizedAgentsByInlineProperties, - AuthorizedAgentsByPropertyId, - AuthorizedAgentsByPropertyTag, - AuthorizedAgentsByPublisherProperties, - AuthorizedAgentsBySignalId, - AuthorizedAgentsBySignalTag, - BothPreviewRender, - BriefFormatAsset, - # Cross-module name collision aliases (#911, Step 2) - BuildCreativeCreative, - BuildCreativeErrorResponse, - BuildCreativeResponse1, - BuildCreativeSubmittedResponse, - BuildCreativeSuccessResponse, - CalibrateContentErrorResponse, - CalibrateContentResponse1, - CalibrateContentSuccessResponse, - CanonicalAssetSource, - CanonicalCompositionModel, - CanonicalFormatAgentPlacement, - CanonicalFormatBase, - CanonicalFormatDaastAudio, - CanonicalFormatDisplayTag, - CanonicalFormatHostedAudio, - CanonicalFormatHostedVideo, - CanonicalFormatHtml5Banner, - CanonicalFormatImage, - CanonicalFormatImageCarousel, - CanonicalFormatKind, - CanonicalFormatNativeInFeed, - CanonicalFormatResponsiveCreative, - CanonicalFormatSponsoredPlacement, - CanonicalFormatVastVideo, - CanonicalProjectionReference, - CanonicalSlotOverride, - CapabilitiesAccount, - CapabilitiesCreative, - CapabilitiesMediaBuy, - CatalogFormatAsset, - CatalogGroupBinding, - ComplyErrorResponse, - ComplyListScenariosResponse, - ComplySimulationResponse, - ComplyStateTransitionResponse, - ComplyTestControllerResponse1, - ConsentBasis, - CoreAccount, - CoreCreditLimit, - CoreGovernanceAgent, - CoreMediaBuy, - CoreSetup, - CreateContentStandardsErrorResponse, - CreateContentStandardsResponse1, - CreateContentStandardsSuccessResponse, - CreateMediaBuyAuthentication, - CreateMediaBuyErrorResponse, - CreateMediaBuyResponse1, - CreateMediaBuySubmittedResponse, - CreateMediaBuySuccessResponse, - CssFormatAsset, - CssFormatGroupAsset, - DaastFormatAsset, - DaastFormatGroupAsset, - DeliveryCreative, - Deployment, - Destination, - DurationUnit, - FormatAssetUnion, - FormatId, - GetAccountFinancialsErrorResponse, - GetAccountFinancialsResponse1, - GetAccountFinancialsSuccessResponse, - GetBrandIdentityErrorResponse, - GetBrandIdentityField, - GetBrandIdentityResponse1, - GetBrandIdentitySuccessResponse, - GetContentStandardsErrorResponse, - GetContentStandardsResponse1, - GetContentStandardsSuccessResponse, - GetCreativeDeliveryByBuyerRefRequest, - GetCreativeDeliveryByCreativeRequest, - GetCreativeDeliveryByMediaBuyRequest, - GetCreativeFeaturesErrorResponse, - GetCreativeFeaturesResponse1, - GetCreativeFeaturesSuccessResponse, - GetMediaBuyArtifactsErrorResponse, - GetMediaBuyArtifactsResponse1, - GetMediaBuyArtifactsSuccessResponse, - GetMediaBuysMediaBuy, - GetProductsBriefRequest, - GetProductsField, - GetProductsInputRequiredResponse, - GetProductsRefineRequest, - GetProductsResponseUnion, - GetProductsSubmittedResponse, - GetProductsSuccessResponse, - GetProductsWholesaleRequest, - GetProductsWorkingResponse, - GetRightsErrorResponse, - GetRightsResponse1, - GetRightsSuccessResponse, - GetSignalsDiscoveryRequest, - GetSignalsLookupRequest, - GetSignalsResponseUnion, - GetSignalsSignal, - GetSignalsSubmittedResponse, - GetSignalsSuccessResponse, - GetSignalsWorkingResponse, - GovernanceAuthentication, - GroupFormatAssetUnion, - HtmlFormatAsset, - HtmlFormatGroupAsset, - HtmlPreviewRender, - ImageFormatAsset, - ImageFormatGroupAsset, - InlineDaastAsset, - InlineVastAsset, - JavascriptFormatAsset, - JavascriptFormatGroupAsset, - KeyValueActivationKey, - ListContentStandardsErrorResponse, - ListContentStandardsResponse1, - ListContentStandardsSuccessResponse, - ListCreativesCreative, - ListCreativesSort, - ListTasksSort, - LogEventErrorResponse, - LogEventResponse1, - LogEventSuccessResponse, - MarkdownFormatAsset, - MarkdownFormatGroupAsset, - MediaBuyDeliveryStatus, - NotificationAuthentication, - OverlayUnit, - PixelTrackerAsset, - PixelTrackerEvent, - PixelTrackerMethod, - PlatformDeployment, - PlatformDestination, - PreviewCreativeBatchResponse, - PreviewCreativeResponse1, - PreviewCreativeSingleResponse, - PreviewCreativeVariantResponse, - PricingOption, - ProductFormatDeclaration, - ProductFormatSellerPreference, - PropertyId, - PropertyTag, - ProvenanceDeclaredBy, - ProvidePerformanceFeedbackByBuyerRefRequest, - ProvidePerformanceFeedbackByMediaBuyRequest, - ProvidePerformanceFeedbackErrorResponse, - ProvidePerformanceFeedbackResponse1, - ProvidePerformanceFeedbackSuccessResponse, - PublisherProperties, - PublisherPropertiesAll, - PublisherPropertiesById, - PublisherPropertiesByTag, - PushNotificationAuthentication, - RealEstateUnit, - Recovery, - RepeatableAssetGroup, - ReportingWebhookAuthentication, - SegmentIdActivationKey, - SiSendActionResponseRequest, - SiSendTextMessageRequest, - SiSponsoredContextDeclaredBy, - Source, - SyncAccountsAccount, - SyncAccountsCreditLimit, - SyncAccountsErrorResponse, - SyncAccountsResponse1, - SyncAccountsSetup, - SyncAccountsSuccessResponse, - SyncAudiencesAudience, - SyncAudiencesErrorResponse, - SyncAudiencesResponse1, - SyncAudiencesSubmittedResponse, - SyncAudiencesSuccessResponse, - SyncCatalogResult, - SyncCatalogsErrorResponse, - SyncCatalogsResponse1, - SyncCatalogsSubmittedResponse, - SyncCatalogsSuccessResponse, - SyncCreativeResult, - SyncCreativesCreative, - SyncCreativesErrorResponse, - SyncCreativesResponse1, - SyncCreativesResponse3, - SyncCreativesSubmittedResponse, - SyncCreativesSuccessResponse, - SyncEventSourcesErrorResponse, - SyncEventSourcesResponse1, - SyncEventSourcesSetup, - SyncEventSourcesSuccessResponse, - SyncGovernanceAccount, - SyncGovernanceGovernanceAgent, - TasksListSort, - TextFormatAsset, - TextFormatGroupAsset, - UnknownFormatAsset, - UnknownGroupAsset, - UpdateContentStandardsErrorResponse, - UpdateContentStandardsResponse1, - UpdateContentStandardsSuccessResponse, - UpdateMediaBuyErrorResponse, - UpdateMediaBuyPackagesRequest, - UpdateMediaBuyPropertiesRequest, - UpdateMediaBuyResponse1, - UpdateMediaBuyResponse3, - UpdateMediaBuySubmittedResponse, - UpdateMediaBuySuccessResponse, - UrlDaastAsset, - UrlFormatAsset, - UrlFormatGroupAsset, - UrlPreviewRender, - UrlVastAsset, - V1CanonicalDimensions, - V1CanonicalGlobPattern, - V1CanonicalMapping, - V1CanonicalStructural, - V1CanonicalStructuralPattern, - V1CanonicalV2Projection, - V1V2CanonicalFormatMappingRegistry, - ValidateContentDeliveryErrorResponse, - ValidateContentDeliveryResponse1, - ValidateContentDeliverySuccessResponse, - VastFormatAsset, - VastFormatGroupAsset, - VehicleUnit, - VideoFormatAsset, - VideoFormatGroupAsset, - WebhookFormatAsset, - WebhookFormatGroupAsset, - WholesaleFeedSignal, -) - -# Re-export core types (not in generated, but part of public API) -# Note: We don't import TaskStatus here to avoid shadowing GeneratedTaskStatus -# Users should import TaskStatus from adcp.types.core directly if they need the core enum -from adcp.types.core import ( - AgentConfig, - Member, - Policy, - PolicyExemplar, - PolicyExemplars, - PolicyHistory, - PolicyRevision, - PolicySummary, - Protocol, - ResolvedBrand, - ResolvedProperty, - TaskResult, - WebhookMetadata, -) - -# Deprecated: types removed from _generated.py but classes still exist in generated_poc -from adcp.types.generated_poc.brand import Asset, Disclaimer, Fonts, ProductCatalog -from adcp.types.generated_poc.core.catalog_item_delivery_metrics import ( - CatalogItemDeliveryMetrics as ByCatalogItemItem, -) -from adcp.types.generated_poc.core.outcome_measurement import ( - OutcomeMeasurementDeprecated as OutcomeMeasurement, -) -from adcp.types.generated_poc.enums.metric_type import MetricTypeDeprecated as MetricType - -# Status: _generated picks invoice status (get_account_financials_response) due to -# alphabetical module sort. Import the delivery status variant directly for backward compat. -from adcp.types.generated_poc.media_buy.get_media_buy_delivery_response import ( # noqa: E501 - Status, -) - -# Re-export type guards for discriminated union response handling -from adcp.types.guards import ( # noqa: F401 - is_activate_signal_error, - is_activate_signal_success, - is_adcp_error, - is_adcp_success, - is_build_creative_error, - is_build_creative_submitted, - is_build_creative_success, - is_calibrate_content_success, - is_create_media_buy_error, - is_create_media_buy_success, - is_get_account_financials_error, - is_get_account_financials_success, - is_get_creative_features_success, - is_log_event_error, - is_log_event_success, - is_performance_feedback_error, - is_performance_feedback_success, - is_sync_accounts_error, - is_sync_accounts_success, - is_sync_catalogs_error, - is_sync_catalogs_submitted, - is_sync_catalogs_success, - is_sync_creatives_error, - is_sync_creatives_submitted, - is_sync_creatives_success, - is_update_media_buy_error, - is_update_media_buy_success, - is_validate_content_delivery_success, -) -from adcp.types.projections import ( - AccountResponse, - BusinessEntityResponse, - project_geo_postal_areas, - to_account_response, -) -from adcp.types.registry import BrandSource - -# Schema-variant marker for cross-class entity overrides (#710). Adopters -# annotate Pydantic field overrides with ``SchemaVariant[T]`` instead of -# ``# type: ignore[assignment]`` when substituting a sibling class for the -# parent's declared type. Activate the mypy plugin via -# ``[tool.mypy] plugins = ["adcp.types.mypy_plugin"]`` to suppress the -# override-compat check on those fields. -from adcp.types.variants import SchemaVariant - -# Semantic aliases for auto-generated field enum names -ListCreativesField = Field1 - -# FieldModel: _generated picks brand.get_brand_identity_request.FieldModel due to -# alphabetical module sort. Override to preserve backward compat with the original -# get_products_request variant (which the generator renamed to Field1 in that module). -FieldModel = GetProductsField # type: ignore[misc,assignment] # noqa: F811 - -# Backward compatibility aliases -AssetType = AssetContentType # Use AssetContentType instead -Measurement = OutcomeMeasurement # Renamed upstream to OutcomeMeasurement -Preview = PreviewCreativeResponse -Results = GetMediaBuyDeliveryResponse - -# Pricing type renames: upstream merged auction/fixed variants into single types -CpmAuctionPricingOption = CpmPricingOption -CpmFixedRatePricingOption = CpmPricingOption -VcpmAuctionPricingOption = VcpmPricingOption -VcpmFixedRatePricingOption = VcpmPricingOption - -# Activation key schema change: property_id/property_tag → segment_id/key_value -PropertyIdActivationKey = SegmentIdActivationKey -PropertyTagActivationKey = KeyValueActivationKey - -# Deprecated: types removed from upstream schemas entirely -# Performance was removed; PerformanceFeedback is the replacement -Performance = PerformanceFeedback - -# MediaSubAsset (SubAsset1) and TextSubAsset (SubAsset2) were removed from the -# upstream schema with no replacement. These stubs exist only to provide a clear -# error message for code that still references them. - - -class MediaSubAsset: - """Removed from ADCP schema. Previously SubAsset with asset_kind='media'.""" - - def __init__(self, *args: object, **kwargs: object) -> None: - raise TypeError( - "MediaSubAsset was removed from the ADCP schema. " "There is no direct replacement." - ) - - -class TextSubAsset: - """Removed from ADCP schema. Previously SubAsset with asset_kind='text'.""" - - def __init__(self, *args: object, **kwargs: object) -> None: - raise TypeError( - "TextSubAsset was removed from the ADCP schema. " "There is no direct replacement." - ) - - -# Preview response rename aliases (per-mode Request variants were removed when -# PreviewCreativeRequest collapsed to a single class with a request_type enum). -PreviewCreativeStaticResponse = PreviewCreativeSingleResponse -PreviewCreativeInteractiveResponse = PreviewCreativeBatchResponse - -# Schema renames from filter ref split (v1.0.0) -Action = CreativeAction -Capability = CreativeAgentCapability -CoBranding = CoBrandingRequirement -LandingPage = LandingPageRequirement -Method = HttpMethod -ModuleType = JavascriptModuleType -TrackingEvent = VastTrackingEvent # Split into DaastTrackingEvent and VastTrackingEvent -Unit = DimensionUnit -OutputFormat = PreviewOutputFormat -ResponseType = WebhookResponseType -Scheme = AuthenticationScheme -SignalType = SignalCatalogType -UrlType = UrlAssetType -AvailableReportingFrequency = ReportingFrequency - -# Internal normalization helpers used by generated response models and server -# envelope handling. Keep these importable through ``adcp.types`` for the -# repo's generated-type layering rule, but leave them out of ``__all__`` so they -# do not become part of the documented public API. -from adcp.types.media_buy_status_helpers import ( # noqa: E402 - MEDIA_BUY_LEGACY_STATUS_VALUES as MEDIA_BUY_LEGACY_STATUS_VALUES, -) -from adcp.types.media_buy_status_helpers import ( - unwrap_enum_value as unwrap_enum_value, -) - __all__ = [ # A2UI types "A2UiComponent", @@ -1586,9 +748,10 @@ def __init__(self, *args: object, **kwargs: object) -> None: # Backward compat: activation key schema change "PropertyIdActivationKey", "PropertyTagActivationKey", - # Backward compat: preview alias renames - "PreviewCreativeFormatRequest", - "PreviewCreativeManifestRequest", + # Backward compat: preview alias renames. The per-mode *Request variants + # (PreviewCreativeFormatRequest / PreviewCreativeManifestRequest) were + # removed upstream when PreviewCreativeRequest collapsed to a single class + # with a request_type discriminator — use PreviewCreativeRequest directly. "PreviewCreativeStaticResponse", "PreviewCreativeInteractiveResponse", # Backward compat: types removed from upstream schemas @@ -1648,13 +811,71 @@ def __init__(self, *args: object, **kwargs: object) -> None: "OverlayUnit", "RealEstateUnit", "VehicleUnit", + # Curated partial surfaces (lazy submodules): + "media_buy", + "creative", + "signals", + "protocol", + "buyer", + "seller", # Submodules for advanced use: "generated", "aliases", ] +# Curated partial-surface submodules, advertised in ``__all__`` (resolved as +# real submodules by ``__getattr__`` below — see the submodule passthrough). +_PARTIAL_MODULES = frozenset({"media_buy", "creative", "signals", "protocol", "buyer", "seller"}) + +# Names importable from ``adcp.types`` but intentionally NOT in ``__all__``: +# internal re-export helpers (response type guards + a few normalization +# helpers) kept on this surface for backwards compatibility. ``__getattr__`` +# treats these as resolvable; the documented public list stays ``__all__``. +# ``tests/test_lazy_types.py`` fails if this drifts from what ``_eager`` binds. +_EAGER_ONLY_EXTRAS = frozenset( + { + "Field1", + "MEDIA_BUY_LEGACY_STATUS_VALUES", + "Measurement", + "unwrap_enum_value", + "is_activate_signal_error", + "is_activate_signal_success", + "is_adcp_error", + "is_adcp_success", + "is_build_creative_error", + "is_build_creative_submitted", + "is_build_creative_success", + "is_calibrate_content_success", + "is_create_media_buy_error", + "is_create_media_buy_success", + "is_get_account_financials_error", + "is_get_account_financials_success", + "is_get_creative_features_success", + "is_log_event_error", + "is_log_event_success", + "is_performance_feedback_error", + "is_performance_feedback_success", + "is_sync_accounts_error", + "is_sync_accounts_success", + "is_sync_catalogs_error", + "is_sync_catalogs_submitted", + "is_sync_catalogs_success", + "is_sync_creatives_error", + "is_sync_creatives_submitted", + "is_sync_creatives_success", + "is_update_media_buy_error", + "is_update_media_buy_success", + "is_validate_content_delivery_success", + } +) + +# Names ``__getattr__`` resolves from the eager graph. Anything else fails fast +# (``AttributeError``) without paying to build the schema graph — so typos and +# ``hasattr`` probes for unknown names stay cheap. +_RESOLVABLE = frozenset(__all__) | _EAGER_ONLY_EXTRAS -# Deprecated backward-compat aliases (kept out of ``__all__``). + +# Deprecated backward-compat alias (kept out of ``__all__``). # # AdCP 3.1.0-rc.10 restructured postal-area targeting: the inline # ``{system, values}`` ``GeoPostalArea`` shape became the ``PostalArea`` @@ -1674,19 +895,871 @@ def __init__(self, *args: object, **kwargs: object) -> None: ) -def __getattr__(name: str) -> object: - """Resolve deprecated type aliases (PEP 562). +if not TYPE_CHECKING: + # Defined under ``not TYPE_CHECKING`` so type checkers do not see a module- + # level ``__getattr__`` (which would silence missing-attribute errors and + # type every unknown name as ``object``). Type checkers get the surface from + # the explicit ``TYPE_CHECKING`` block below, so a typo'd import is flagged; + # at runtime these provide the lazy PEP 562 resolution. + + def __getattr__(name: str) -> object: + """Lazily resolve the AdCP type surface (PEP 562). + + ``import adcp.types`` stays cheap; the generated Pydantic graph — and its + import-time coercion / forward-compat patching — is built on first access + to any type *symbol*, by importing :mod:`adcp.types._eager`. Resolved names + are cached into this module's namespace, so ``__getattr__`` fires at most + once per name. + + Real submodules (the curated partial surfaces, ``aliases``, the internal + generated layer) resolve through the import system rather than ``_eager``. + That matters for correctness, not just speed: ``aliases`` imports + ``_generated`` from this package, and routing that through ``_eager`` would + re-enter the eager body (``_forward_compat`` → ``aliases``) and deadlock on + a circular import. Passing submodules straight to the import system avoids it. + + Also keeps the removed ``GeoPostalArea`` name importable while emitting a + :class:`DeprecationWarning` that names the migration target. + """ + if name == "GeoPostalArea": + import warnings + + warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2) + from adcp.types._generated import PostalArea5 + + # Cache so the warning fires once: subsequent ``adcp.types.GeoPostalArea`` + # accesses hit the module dict directly and skip ``__getattr__``. + globals()["GeoPostalArea"] = PostalArea5 + return PostalArea5 + + # Submodule passthrough — the curated partial surfaces, ``aliases``, and + # the internal generated layer are real submodules; import them directly + # so they never round-trip through the eager body (which would re-enter + # on the ``_forward_compat`` → ``aliases`` cycle). ``_PARTIAL_MODULES`` is + # the fast path for the curated set; ``find_spec`` covers the rest. + if name in _PARTIAL_MODULES or ( + not name.startswith("__") and importlib.util.find_spec(f"adcp.types.{name}") is not None + ): + module = importlib.import_module(f"adcp.types.{name}") + globals()[name] = module + return module + + # Fail fast for unknown names: don't build the (expensive) schema graph just + # to discover an attribute doesn't exist. Keeps typos and ``hasattr`` probes + # for unknown names cheap. + if name not in _RESOLVABLE: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + value = getattr(importlib.import_module("adcp.types._eager"), name) + globals()[name] = value # cache: __getattr__ fires once per name + return value - Keeps the removed ``GeoPostalArea`` name importable from ``adcp.types`` - while emitting a :class:`DeprecationWarning` that names the migration - target. It resolves to the ``PostalArea`` union's legacy arm - (``PostalArea5``), which is shape-compatible with the removed type. - """ - if name == "GeoPostalArea": - import warnings + def __dir__() -> list[str]: + return sorted(set(__all__) | set(globals())) - warnings.warn(_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2) - from adcp.types._generated import PostalArea5 - return PostalArea5 - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the full importable + # surface; resolved lazily through ``__getattr__`` at runtime. ``_eager`` + # defines ``__all__`` so names listed in ``adcp.types.__all__`` re-export + # cleanly under mypy --strict; the internal helpers not in ``__all__`` use + # the explicit ``X as X`` re-export form (matching the original module). + # ``generated`` / ``aliases`` are submodule re-exports; the six partial + # submodules resolve as real submodules; the two dead back-compat + # ``__all__`` entries are intentionally unbound. + from adcp.types import _generated as generated # noqa: F401 + from adcp.types import aliases # noqa: F401 + from adcp.types._eager import ( + MEDIA_BUY_LEGACY_STATUS_VALUES as MEDIA_BUY_LEGACY_STATUS_VALUES, + ) + from adcp.types._eager import ( # noqa: F401 + A2UiComponent, + A2UiSurface, + Account, + AccountAuthorization, + AccountReference, + AccountReferenceById, + AccountReferenceByNaturalKey, + AccountResponse, + AccountScope, + AccountWithAuthorization, + AcquireRightsAcquiredResponse, + AcquireRightsErrorResponse, + AcquireRightsPendingResponse, + AcquireRightsRejectedResponse, + AcquireRightsRequest, + AcquireRightsResponse, + AcquireRightsResponse1, + Action, + ActivateSignalErrorResponse, + ActivateSignalRequest, + ActivateSignalResponse, + ActivateSignalResponse1, + ActivateSignalSuccessResponse, + AdcpProtocol, + AdvertiserIndustry, + AgentConfig, + AgentDeployment, + AgentDestination, + AggregatedTotals, + AiTool, + Artifact, + ArtifactWebhookPayload, + Asset, + AssetContentType, + AssetType, + AssignedPackage, + Assignments, + AudienceSource, + AudioContent, + AudioFormatAsset, + AudioFormatGroupAsset, + Authentication, + AuthenticationScheme, + AuthorizationRequiredDetails, + AuthorizedAgent, + AuthorizedAgents, + AuthorizedAgentsByInlineProperties, + AuthorizedAgentsByPropertyId, + AuthorizedAgentsByPropertyTag, + AuthorizedAgentsByPublisherProperties, + AuthorizedAgentsBySignalId, + AuthorizedAgentsBySignalTag, + AvailableMetric, + AvailablePackage, + AvailableReportingFrequency, + BothPreviewRender, + BrandReference, + BrandSource, + BriefFormatAsset, + BuildCreativeCreative, + BuildCreativeErrorResponse, + BuildCreativeRequest, + BuildCreativeResponse, + BuildCreativeResponse1, + BuildCreativeSubmittedResponse, + BuildCreativeSuccessResponse, + BusinessEntity, + BusinessEntityResponse, + BuyingMode, + ByCatalogItemItem, + ByPackageItem, + CalibrateContentErrorResponse, + CalibrateContentRequest, + CalibrateContentResponse, + CalibrateContentResponse1, + CalibrateContentSuccessResponse, + CanonicalAssetSource, + CanonicalCompositionModel, + CanonicalFormatAgentPlacement, + CanonicalFormatBase, + CanonicalFormatDaastAudio, + CanonicalFormatDisplayTag, + CanonicalFormatHostedAudio, + CanonicalFormatHostedVideo, + CanonicalFormatHtml5Banner, + CanonicalFormatImage, + CanonicalFormatImageCarousel, + CanonicalFormatKind, + CanonicalFormatNativeInFeed, + CanonicalFormatResponsiveCreative, + CanonicalFormatSponsoredPlacement, + CanonicalFormatVastVideo, + CanonicalProjectionReference, + CanonicalSlotOverride, + CapabilitiesAccount, + CapabilitiesCreative, + CapabilitiesMediaBuy, + Capability, + Catalog, + CatalogAction, + CatalogFieldBinding, + CatalogFieldBinding1, + CatalogFieldMapping, + CatalogFormatAsset, + CatalogGroupBinding, + CatalogItemStatus, + CatalogRequirements, + CatalogType, + CheckGovernanceRequest, + CheckGovernanceResponse, + CoBranding, + CoBrandingRequirement, + CollectionList, + CollectionListChangedWebhook, + CollectionListFilters, + Colors, + ComplyErrorResponse, + ComplyListScenariosResponse, + ComplySimulationResponse, + ComplyStateTransitionResponse, + ComplyTestControllerRequest, + ComplyTestControllerResponse, + ComplyTestControllerResponse1, + ConsentBasis, + Contact, + ContentIdType, + ContentStandards, + ContextMatchRequest, + ContextMatchResponse, + ContextObject, + CoreAccount, + CoreCreditLimit, + CoreGovernanceAgent, + CoreMediaBuy, + CoreSetup, + Country, + CpaPricingOption, + CpcPricingOption, + CpcvPricingOption, + CpmAuctionPricingOption, + CpmFixedRatePricingOption, + CpmPricingOption, + CppPricingOption, + CpvPricingOption, + CreateCollectionListRequest, + CreateCollectionListResponse, + CreateContentStandardsErrorResponse, + CreateContentStandardsRequest, + CreateContentStandardsResponse, + CreateContentStandardsResponse1, + CreateContentStandardsSuccessResponse, + CreateMediaBuyAuthentication, + CreateMediaBuyErrorResponse, + CreateMediaBuyRequest, + CreateMediaBuyResponse, + CreateMediaBuyResponse1, + CreateMediaBuySubmittedResponse, + CreateMediaBuySuccessResponse, + CreatePropertyListRequest, + CreatePropertyListResponse, + Creative, + CreativeAction, + CreativeAgent, + CreativeAgentCapability, + CreativeApproval, + CreativeApprovalStatus, + CreativeAsset, + CreativeAssignment, + CreativeFilters, + CreativeManifest, + CreativePolicy, + CreativeStatus, + CreativeVariant, + CreditLimit, + CssContent, + CssFormatAsset, + CssFormatGroupAsset, + DaastFormatAsset, + DaastFormatGroupAsset, + DaastTrackingEvent, + DaastVersion, + DailyBreakdownItem, + DateRange, + DatetimeRange, + DayOfWeek, + DaypartTarget, + DeleteCollectionListRequest, + DeleteCollectionListResponse, + DeletePropertyListRequest, + DeletePropertyListResponse, + DeliveryCreative, + DeliveryForecast, + DeliveryMeasurement, + DeliveryMetrics, + DeliveryStatus, + DeliveryType, + DemographicSystem, + Deployment, + Destination, + DevicePlatform, + DeviceType, + Dimensions, + DimensionUnit, + Disclaimer, + DoohMetrics, + DownstreamConnectionRequirement, + Duration, + DurationUnit, + Error, + ErrorCode, + EventType, + ExtensionObject, + FeedbackSource, + FeedFormat, + FieldModel, + FlatRatePricingOption, + Fonts, + ForecastableMetric, + ForecastMethod, + ForecastPoint, + ForecastRange, + ForecastRangeUnit, + Format, + FormatAssetUnion, + FormatCard, + FormatCardDetailed, + FormatId, + FormatIdParameter, + FormatOptionReference, + FormatReferenceStructuredObject, + FrequencyCap, + FrequencyCapScope, + GeneratedTaskStatus, + GeoCountry, + GeoMetro, + GeoRegion, + GetAccountFinancialsErrorResponse, + GetAccountFinancialsRequest, + GetAccountFinancialsResponse, + GetAccountFinancialsResponse1, + GetAccountFinancialsSuccessResponse, + GetAdcpCapabilitiesRequest, + GetAdcpCapabilitiesResponse, + GetBrandIdentityErrorResponse, + GetBrandIdentityField, + GetBrandIdentityRequest, + GetBrandIdentityResponse, + GetBrandIdentityResponse1, + GetBrandIdentitySuccessResponse, + GetCollectionListRequest, + GetCollectionListResponse, + GetContentStandardsErrorResponse, + GetContentStandardsRequest, + GetContentStandardsResponse, + GetContentStandardsResponse1, + GetContentStandardsSuccessResponse, + GetCreativeDeliveryByBuyerRefRequest, + GetCreativeDeliveryByCreativeRequest, + GetCreativeDeliveryByMediaBuyRequest, + GetCreativeDeliveryRequest, + GetCreativeDeliveryResponse, + GetCreativeFeaturesErrorResponse, + GetCreativeFeaturesRequest, + GetCreativeFeaturesResponse, + GetCreativeFeaturesResponse1, + GetCreativeFeaturesSuccessResponse, + GetMediaBuyArtifactsErrorResponse, + GetMediaBuyArtifactsRequest, + GetMediaBuyArtifactsResponse, + GetMediaBuyArtifactsResponse1, + GetMediaBuyArtifactsSuccessResponse, + GetMediaBuyDeliveryRequest, + GetMediaBuyDeliveryResponse, + GetMediaBuysMediaBuy, + GetMediaBuysRequest, + GetMediaBuysResponse, + GetPlanAuditLogsRequest, + GetPlanAuditLogsResponse, + GetProductsBriefRequest, + GetProductsField, + GetProductsInputRequiredResponse, + GetProductsRefineRequest, + GetProductsRequest, + GetProductsResponse, + GetProductsResponseUnion, + GetProductsSubmittedResponse, + GetProductsSuccessResponse, + GetProductsWholesaleRequest, + GetProductsWorkingResponse, + GetPropertyListRequest, + GetPropertyListResponse, + GetRightsErrorResponse, + GetRightsRequest, + GetRightsResponse, + GetRightsResponse1, + GetRightsSuccessResponse, + GetSignalsDiscoveryRequest, + GetSignalsLookupRequest, + GetSignalsRequest, + GetSignalsResponse, + GetSignalsResponseUnion, + GetSignalsSignal, + GetSignalsSubmittedResponse, + GetSignalsSuccessResponse, + GetSignalsWorkingResponse, + GetTaskStatusRequest, + GetTaskStatusResponse, + GovernanceAgent, + GovernanceAuthentication, + GroupFormatAssetUnion, + Gtin, + HtmlContent, + HtmlFormatAsset, + HtmlFormatGroupAsset, + HtmlPreviewRender, + HttpMethod, + Identifier, + IdentityMatchRequest, + IdentityMatchResponse, + ImageContent, + ImageFormatAsset, + ImageFormatGroupAsset, + InlineDaastAsset, + InlineVastAsset, + Input, + JavascriptContent, + JavascriptFormatAsset, + JavascriptFormatGroupAsset, + JavascriptModuleType, + KellerType, + KeyValueActivationKey, + LandingPage, + LandingPageRequirement, + ListAccountsRequest, + ListAccountsResponse, + ListCollectionListsRequest, + ListCollectionListsResponse, + ListContentStandardsErrorResponse, + ListContentStandardsRequest, + ListContentStandardsResponse, + ListContentStandardsResponse1, + ListContentStandardsSuccessResponse, + ListCreativeFormatsRequest, + ListCreativeFormatsResponse, + ListCreativesCreative, + ListCreativesField, + ListCreativesRequest, + ListCreativesResponse, + ListCreativesSort, + ListPropertyListsRequest, + ListPropertyListsResponse, + ListTasksRequest, + ListTasksResponse, + ListTasksSort, + ListTransformersRequest, + ListTransformersResponse, + LogEventErrorResponse, + LogEventRequest, + LogEventResponse, + LogEventResponse1, + LogEventSuccessResponse, + Logo, + MarkdownFlavor, + MarkdownFormatAsset, + MarkdownFormatGroupAsset, + McpWebhookPayload, + MeasurementPeriod, + MediaBuy, + MediaBuyDelivery, + MediaBuyDeliveryStatus, + MediaBuyDeliveryWebhookResult, + MediaBuyFeatures, + MediaBuyPackage, + MediaBuyStatus, + MediaChannel, + MediaSubAsset, + Member, + Metadata, + Method, + MetricType, + ModuleType, + NotificationAuthentication, + NotificationConfig, + NotificationType, + Offering, + OfferingAssetConstraint, + OfferingAssetGroup, + OfferPrice, + OptimizationGoal, + OutcomeMeasurement, + OutputFormat, + Overlay, + OverlayUnit, + Pacing, + Package, + PackageRequest, + PackageSignalTargeting, + PackageSignalTargetingGroup, + PackageSignalTargetingGroups, + PackageUpdate, + Pagination, + PaginationRequest, + PaginationResponse, + Parameters, + PaymentTerms, + Performance, + PerformanceFeedback, + PixelTrackerAsset, + PixelTrackerEvent, + PixelTrackerMethod, + Placement, + PlacementReference, + PlatformDeployment, + PlatformDestination, + Policy, + PolicyExemplar, + PolicyExemplars, + PolicyHistory, + PolicyRevision, + PolicySummary, + PostalArea, + Preview, + PreviewCreativeBatchResponse, + PreviewCreativeInteractiveResponse, + PreviewCreativeRequest, + PreviewCreativeResponse, + PreviewCreativeResponse1, + PreviewCreativeSingleResponse, + PreviewCreativeStaticResponse, + PreviewCreativeVariantResponse, + PreviewOutputFormat, + PreviewRender, + PriceGuidance, + PricingCurrency, + PricingModel, + PricingOption, + PrimaryCountry, + Product, + ProductCard, + ProductCardDetailed, + ProductCatalog, + ProductFilters, + ProductFormatDeclaration, + ProductFormatSellerPreference, + ProductSignalTargetingOption, + Property, + PropertyId, + PropertyIdActivationKey, + PropertyIdentifierTypes, + PropertyList, + PropertyListChangedWebhook, + PropertyListFilters, + PropertyListReference, + PropertyTag, + PropertyTagActivationKey, + PropertyType, + Proposal, + Protocol, + ProtocolEnvelope, + ProtocolResponse, + ProvenanceDeclaredBy, + ProvidePerformanceFeedbackByBuyerRefRequest, + ProvidePerformanceFeedbackByMediaBuyRequest, + ProvidePerformanceFeedbackErrorResponse, + ProvidePerformanceFeedbackRequest, + ProvidePerformanceFeedbackResponse, + ProvidePerformanceFeedbackResponse1, + ProvidePerformanceFeedbackSuccessResponse, + PublisherDomain, + PublisherIdentifierTypes, + PublisherProperties, + PublisherPropertiesAll, + PublisherPropertiesById, + PublisherPropertiesByTag, + PushNotificationAuthentication, + PushNotificationConfig, + QuartileData, + QuerySummary, + ReachUnit, + RealEstateUnit, + Recovery, + Refine, + RefinementApplied, + RefinementApplied1, + RefinementApplied2, + RefinementApplied3, + Renders, + RepeatableAssetGroup, + ReportingBucket, + ReportingCapabilities, + ReportingFrequency, + ReportingPeriod, + ReportingWebhook, + ReportingWebhookAuthentication, + ReportPlanOutcomeRequest, + ReportPlanOutcomeResponse, + ReportUsageRequest, + ReportUsageResponse, + Request, + ResolvedBrand, + ResolvedProperty, + Response, + ResponsePayloadJwsEnvelope, + ResponseType, + Responsive, + Results, + RightsPricingOption, + RightsTerms, + SchemaVariant, + Scheme, + Security, + SegmentIdActivationKey, + SellerAgentReference, + Setup, + SiCapabilities, + SiGetOfferingRequest, + SiGetOfferingResponse, + Signal, + SignalAvailabilityType, + SignalCatalogType, + SignalDefinitionEnrichment, + SignalFilters, + SignalListing, + SignalPricingOption, + SignalRef, + SignalTargeting, + SignalTargetingExpression, + SignalTargetingRules, + SignalType, + SiIdentity, + SiInitiateSessionRequest, + SiInitiateSessionResponse, + SiSendActionResponseRequest, + SiSendMessageRequest, + SiSendMessageResponse, + SiSendTextMessageRequest, + SiSponsoredContextDeclaredBy, + SiTerminateSessionRequest, + SiTerminateSessionResponse, + SiUiElement, + Snapshot, + SnapshotUnavailableReason, + Sort, + SortApplied, + SortDirection, + Source, + Status, + StatusSummary, + SyncAccountsAccount, + SyncAccountsCreditLimit, + SyncAccountsErrorResponse, + SyncAccountsRequest, + SyncAccountsResponse, + SyncAccountsResponse1, + SyncAccountsSetup, + SyncAccountsSuccessResponse, + SyncAudiencesAudience, + SyncAudiencesErrorResponse, + SyncAudiencesRequest, + SyncAudiencesResponse, + SyncAudiencesResponse1, + SyncAudiencesSubmittedResponse, + SyncAudiencesSuccessResponse, + SyncCatalogResult, + SyncCatalogsErrorResponse, + SyncCatalogsInputRequired, + SyncCatalogsRequest, + SyncCatalogsResponse, + SyncCatalogsResponse1, + SyncCatalogsSubmitted, + SyncCatalogsSubmittedResponse, + SyncCatalogsSuccessResponse, + SyncCatalogsWorking, + SyncCreativeResult, + SyncCreativesCreative, + SyncCreativesErrorResponse, + SyncCreativesRequest, + SyncCreativesResponse, + SyncCreativesResponse1, + SyncCreativesResponse3, + SyncCreativesSubmittedResponse, + SyncCreativesSuccessResponse, + SyncEventSourcesErrorResponse, + SyncEventSourcesRequest, + SyncEventSourcesResponse, + SyncEventSourcesResponse1, + SyncEventSourcesSetup, + SyncEventSourcesSuccessResponse, + SyncGovernanceAccount, + SyncGovernanceGovernanceAgent, + SyncGovernanceRequest, + SyncGovernanceResponse, + SyncPlansRequest, + SyncPlansResponse, + Tags, + TargetingOverlay, + TaskResult, + TasksListSort, + TaskType, + TextContent, + TextFormatAsset, + TextFormatGroupAsset, + TextSubAsset, + TimeBasedPricingOption, + TimeUnit, + TmpError, + TmpOffer, + Totals, + TrackingEvent, + Transform, + Unit, + UnknownFormatAsset, + UnknownGroupAsset, + UpdateCollectionListRequest, + UpdateCollectionListResponse, + UpdateContentStandardsErrorResponse, + UpdateContentStandardsRequest, + UpdateContentStandardsResponse, + UpdateContentStandardsResponse1, + UpdateContentStandardsSuccessResponse, + UpdateFrequency, + UpdateMediaBuyErrorResponse, + UpdateMediaBuyPackagesRequest, + UpdateMediaBuyPropertiesRequest, + UpdateMediaBuyRequest, + UpdateMediaBuyResponse, + UpdateMediaBuyResponse1, + UpdateMediaBuyResponse3, + UpdateMediaBuySubmittedResponse, + UpdateMediaBuySuccessResponse, + UpdatePropertyListRequest, + UpdatePropertyListResponse, + UpdateRightsRequest, + UpdateRightsResponse, + UrlAssetType, + UrlContent, + UrlDaastAsset, + UrlFormatAsset, + UrlFormatGroupAsset, + UrlPreviewRender, + UrlType, + UrlVastAsset, + V1CanonicalDimensions, + V1CanonicalGlobPattern, + V1CanonicalMapping, + V1CanonicalStructural, + V1CanonicalStructuralPattern, + V1CanonicalV2Projection, + V1V2CanonicalFormatMappingRegistry, + ValidateContentDeliveryErrorResponse, + ValidateContentDeliveryRequest, + ValidateContentDeliveryResponse, + ValidateContentDeliveryResponse1, + ValidateContentDeliverySuccessResponse, + ValidateInputRequest, + ValidateInputResponse, + ValidationMode, + VastFormatAsset, + VastFormatGroupAsset, + VastTrackingEvent, + VastVersion, + VcpmAuctionPricingOption, + VcpmFixedRatePricingOption, + VcpmPricingOption, + VehicleUnit, + VenueBreakdownItem, + VerifyBrandClaimPayload, + VerifyBrandClaimRequest, + VerifyBrandClaimResponse, + VerifyBrandClaimsErrorResponse, + VerifyBrandClaimSignedResponse, + VerifyBrandClaimSignedSuccessPayload, + VerifyBrandClaimsPayload, + VerifyBrandClaimsRequest, + VerifyBrandClaimsRequestBulk, + VerifyBrandClaimsResponse, + VerifyBrandClaimsResponseBulk, + VerifyBrandClaimsSignedResponse, + VerifyBrandClaimsSignedSuccessPayload, + VideoContent, + VideoFormatAsset, + VideoFormatGroupAsset, + ViewThreshold, + WcagLevel, + WebhookChallenge, + WebhookChallengeResponse, + WebhookContent, + WebhookFormatAsset, + WebhookFormatGroupAsset, + WebhookMetadata, + WebhookResponseType, + WholesaleFeedEvent, + WholesaleFeedSignal, + WholesaleFeedWebhook, + project_geo_postal_areas, + to_account_response, + ) + from adcp.types._eager import ( + Field1 as Field1, + ) + from adcp.types._eager import ( + Measurement as Measurement, + ) + from adcp.types._eager import ( + is_activate_signal_error as is_activate_signal_error, + ) + from adcp.types._eager import ( + is_activate_signal_success as is_activate_signal_success, + ) + from adcp.types._eager import ( + is_adcp_error as is_adcp_error, + ) + from adcp.types._eager import ( + is_adcp_success as is_adcp_success, + ) + from adcp.types._eager import ( + is_build_creative_error as is_build_creative_error, + ) + from adcp.types._eager import ( + is_build_creative_submitted as is_build_creative_submitted, + ) + from adcp.types._eager import ( + is_build_creative_success as is_build_creative_success, + ) + from adcp.types._eager import ( + is_calibrate_content_success as is_calibrate_content_success, + ) + from adcp.types._eager import ( + is_create_media_buy_error as is_create_media_buy_error, + ) + from adcp.types._eager import ( + is_create_media_buy_success as is_create_media_buy_success, + ) + from adcp.types._eager import ( + is_get_account_financials_error as is_get_account_financials_error, + ) + from adcp.types._eager import ( + is_get_account_financials_success as is_get_account_financials_success, + ) + from adcp.types._eager import ( + is_get_creative_features_success as is_get_creative_features_success, + ) + from adcp.types._eager import ( + is_log_event_error as is_log_event_error, + ) + from adcp.types._eager import ( + is_log_event_success as is_log_event_success, + ) + from adcp.types._eager import ( + is_performance_feedback_error as is_performance_feedback_error, + ) + from adcp.types._eager import ( + is_performance_feedback_success as is_performance_feedback_success, + ) + from adcp.types._eager import ( + is_sync_accounts_error as is_sync_accounts_error, + ) + from adcp.types._eager import ( + is_sync_accounts_success as is_sync_accounts_success, + ) + from adcp.types._eager import ( + is_sync_catalogs_error as is_sync_catalogs_error, + ) + from adcp.types._eager import ( + is_sync_catalogs_submitted as is_sync_catalogs_submitted, + ) + from adcp.types._eager import ( + is_sync_catalogs_success as is_sync_catalogs_success, + ) + from adcp.types._eager import ( + is_sync_creatives_error as is_sync_creatives_error, + ) + from adcp.types._eager import ( + is_sync_creatives_submitted as is_sync_creatives_submitted, + ) + from adcp.types._eager import ( + is_sync_creatives_success as is_sync_creatives_success, + ) + from adcp.types._eager import ( + is_update_media_buy_error as is_update_media_buy_error, + ) + from adcp.types._eager import ( + is_update_media_buy_success as is_update_media_buy_success, + ) + from adcp.types._eager import ( + is_validate_content_delivery_success as is_validate_content_delivery_success, + ) + from adcp.types._eager import ( + unwrap_enum_value as unwrap_enum_value, + ) diff --git a/src/adcp/types/_eager.py b/src/adcp/types/_eager.py new file mode 100644 index 00000000..6152e6bb --- /dev/null +++ b/src/adcp/types/_eager.py @@ -0,0 +1,1615 @@ +"""Eager realization of the AdCP type surface. + +This module binds every public name exported by :mod:`adcp.types` and runs +the import-time Pydantic patching (``_ergonomic`` coercion + +``_forward_compat`` open-union ``Format.assets``). It is imported on demand +by :mod:`adcp.types`'s lazy ``__getattr__`` the first time any type symbol is +accessed, so ``import adcp.types`` itself stays cheap. + +Do not import this module directly — import from :mod:`adcp.types` (or +:mod:`adcp`). The name set here is mirrored by ``adcp.types.__all__``; the +``tests/test_lazy_types.py`` guard fails if the two drift. +""" + +from __future__ import annotations + +import importlib + +# Run the import-time patchers as a side effect, before binding the generated +# types below (must come first — see the original "must be imported before +# other types" note): ``_ergonomic`` applies BeforeValidator coercion and +# ``_forward_compat`` opens ``Format.assets`` / ``RepeatableAssetGroup.assets``. +# Imported via ``import_module`` — a call, not a name binding — so they read as +# the intentional side-effect imports they are rather than tripping +# unused-import analysers. (The removed ``format_category`` submodule has a real +# shim at ``generated_poc/enums/format_category.py``, restored after codegen by +# ``scripts/post_generate_fixes.py``.) +importlib.import_module("adcp.types._ergonomic") +importlib.import_module("adcp.types._forward_compat") + +# Re-exported submodules (part of the public surface via ``__all__`` below). +from adcp.types import _generated as generated # noqa: F401 +from adcp.types import aliases # noqa: F401 + +# Import all types from generated code +# V3 Protocol Discovery types +# V3 Content Standards types +# V3 Sponsored Intelligence types +# V3 Governance (Property Lists) types +# Re-export webhook payload type for webhook handling +from adcp.types._generated import ( + A2UiComponent, + A2UiSurface, + Account, + AccountAuthorization, + AccountReference, + AccountScope, + AccountWithAuthorization, + AcquireRightsRequest, + AcquireRightsResponse, + ActivateSignalRequest, + ActivateSignalResponse, + AdcpProtocol, + AdvertiserIndustry, + AggregatedTotals, + AiTool, + Artifact, + ArtifactWebhookPayload, + AssetContentType, + AssignedPackage, + Assignments, + AudienceSource, + Authentication, + AuthenticationScheme, + AuthorizationRequiredDetails, + AuthorizedAgents, + AvailableMetric, + AvailablePackage, + BrandReference, + BuildCreativeRequest, + BuildCreativeResponse, + BusinessEntity, + BuyingMode, + ByPackageItem, + CalibrateContentRequest, + CalibrateContentResponse, + Catalog, + CatalogAction, + CatalogFieldBinding, + CatalogFieldBinding1, + CatalogFieldMapping, + CatalogItemStatus, + CatalogRequirements, + CatalogType, + CheckGovernanceRequest, + CheckGovernanceResponse, + CoBrandingRequirement, + CollectionList, + CollectionListChangedWebhook, + CollectionListFilters, + Colors, + ComplyTestControllerRequest, + ComplyTestControllerResponse, + Contact, + ContentIdType, + ContentStandards, + ContextMatchRequest, + ContextMatchResponse, + ContextObject, + Country, + CpaPricingOption, + CpcPricingOption, + CpcvPricingOption, + CpmPricingOption, + CppPricingOption, + CpvPricingOption, + CreateCollectionListRequest, + CreateCollectionListResponse, + CreateContentStandardsRequest, + CreateContentStandardsResponse, + CreateMediaBuyRequest, + CreateMediaBuyResponse, + CreatePropertyListRequest, + CreatePropertyListResponse, + Creative, + CreativeAction, + CreativeAgent, + CreativeAgentCapability, + CreativeApproval, + CreativeApprovalStatus, + CreativeAsset, + CreativeAssignment, + CreativeFilters, + CreativeManifest, + CreativePolicy, + CreativeStatus, + CreativeVariant, + CreditLimit, + DaastTrackingEvent, + DaastVersion, + DailyBreakdownItem, + DateRange, + DatetimeRange, + DayOfWeek, + DaypartTarget, + DeleteCollectionListRequest, + DeleteCollectionListResponse, + DeletePropertyListRequest, + DeletePropertyListResponse, + DeliveryForecast, + DeliveryMeasurement, + DeliveryMetrics, + DeliveryStatus, + DeliveryType, + DemographicSystem, + DevicePlatform, + DeviceType, + Dimensions, + DimensionUnit, + DoohMetrics, + DownstreamConnectionRequirement, + Duration, + ErrorCode, + EventType, + ExtensionObject, + FeedbackSource, + FeedFormat, + Field1, + FieldModel, + FlatRatePricingOption, + ForecastableMetric, + ForecastMethod, + ForecastPoint, + ForecastRange, + ForecastRangeUnit, + Format, + FormatCard, + FormatCardDetailed, + FormatIdParameter, + FormatOptionReference, + FormatReferenceStructuredObject, + FrequencyCap, + FrequencyCapScope, + GeoCountry, + GeoMetro, + GeoRegion, + GetAccountFinancialsRequest, + GetAccountFinancialsResponse, + GetAdcpCapabilitiesRequest, + GetAdcpCapabilitiesResponse, + GetBrandIdentityRequest, + GetBrandIdentityResponse, + GetCollectionListRequest, + GetCollectionListResponse, + GetContentStandardsRequest, + GetContentStandardsResponse, + GetCreativeDeliveryRequest, + GetCreativeDeliveryResponse, + GetCreativeFeaturesRequest, + GetCreativeFeaturesResponse, + GetMediaBuyArtifactsRequest, + GetMediaBuyArtifactsResponse, + GetMediaBuyDeliveryRequest, + GetMediaBuyDeliveryResponse, + GetMediaBuysRequest, + GetMediaBuysResponse, + GetPlanAuditLogsRequest, + GetPlanAuditLogsResponse, + GetProductsRequest, + GetProductsResponse, + GetPropertyListRequest, + GetPropertyListResponse, + GetRightsRequest, + GetRightsResponse, + GetSignalsRequest, + GetSignalsResponse, + GetTaskStatusRequest, + GetTaskStatusResponse, + GovernanceAgent, + Gtin, + HttpMethod, + Identifier, + IdentityMatchRequest, + IdentityMatchResponse, + Input, + JavascriptModuleType, + KellerType, + LandingPageRequirement, + ListAccountsRequest, + ListAccountsResponse, + ListCollectionListsRequest, + ListCollectionListsResponse, + ListContentStandardsRequest, + ListContentStandardsResponse, + ListCreativeFormatsRequest, + ListCreativeFormatsResponse, + ListCreativesRequest, + ListCreativesResponse, + ListPropertyListsRequest, + ListPropertyListsResponse, + ListTasksRequest, + ListTasksResponse, + LogEventRequest, + LogEventResponse, + Logo, + MarkdownFlavor, + McpWebhookPayload, + MeasurementPeriod, + MediaBuy, + MediaBuyDelivery, + MediaBuyDeliveryWebhookResult, + MediaBuyFeatures, + MediaBuyPackage, + MediaBuyStatus, + MediaChannel, + Metadata, + NotificationConfig, + NotificationType, + Offering, + OfferingAssetConstraint, + OfferingAssetGroup, + OfferPrice, + OptimizationGoal, + Overlay, + Pacing, + PackageRequest, + PackageSignalTargeting, + PackageSignalTargetingGroup, + PackageSignalTargetingGroups, + PackageUpdate, + Pagination, + PaginationRequest, + PaginationResponse, + Parameters, + PaymentTerms, + PerformanceFeedback, + Placement, + PlacementReference, + PostalArea, + PreviewCreativeRequest, + PreviewCreativeResponse, + PreviewOutputFormat, + PreviewRender, + PriceGuidance, + PricingCurrency, + PricingModel, + PrimaryCountry, + Product, + ProductCard, + ProductCardDetailed, + ProductFilters, + ProductSignalTargetingOption, + Property, + PropertyIdentifierTypes, + PropertyList, + PropertyListChangedWebhook, + PropertyListFilters, + PropertyListReference, + PropertyType, + Proposal, + ProtocolEnvelope, + ProtocolResponse, + ProvidePerformanceFeedbackRequest, + ProvidePerformanceFeedbackResponse, + PublisherDomain, + PublisherIdentifierTypes, + PushNotificationConfig, + QuartileData, + QuerySummary, + ReachUnit, + Refine, + RefinementApplied, + RefinementApplied1, + RefinementApplied2, + RefinementApplied3, + Renders, + ReportingBucket, + ReportingCapabilities, + ReportingFrequency, + ReportingPeriod, + ReportingWebhook, + ReportPlanOutcomeRequest, + ReportPlanOutcomeResponse, + ReportUsageRequest, + ReportUsageResponse, + Request, + Response, + ResponsePayloadJwsEnvelope, + Responsive, + RightsPricingOption, + RightsTerms, + Security, + SellerAgentReference, + Setup, + SiCapabilities, + SiGetOfferingRequest, + SiGetOfferingResponse, + Signal, + SignalAvailabilityType, + SignalCatalogType, + SignalDefinitionEnrichment, + SignalFilters, + SignalListing, + SignalPricingOption, + SignalRef, + SignalTargeting, + SignalTargetingExpression, + SignalTargetingRules, + SiIdentity, + SiInitiateSessionRequest, + SiInitiateSessionResponse, + SiSendMessageRequest, + SiSendMessageResponse, + SiTerminateSessionRequest, + SiTerminateSessionResponse, + SiUiElement, + Snapshot, + SnapshotUnavailableReason, + Sort, + SortApplied, + SortDirection, + StatusSummary, + SyncAccountsRequest, + SyncAccountsResponse, + SyncAudiencesRequest, + SyncAudiencesResponse, + SyncCatalogsInputRequired, + SyncCatalogsRequest, + SyncCatalogsResponse, + SyncCatalogsSubmitted, + SyncCatalogsWorking, + SyncCreativesRequest, + SyncCreativesResponse, + SyncEventSourcesRequest, + SyncEventSourcesResponse, + SyncGovernanceRequest, + SyncGovernanceResponse, + SyncPlansRequest, + SyncPlansResponse, + Tags, + TargetingOverlay, + TaskType, + TimeBasedPricingOption, + TimeUnit, + TmpError, + Totals, + Transform, + UpdateCollectionListRequest, + UpdateCollectionListResponse, + UpdateContentStandardsRequest, + UpdateContentStandardsResponse, + UpdateFrequency, + UpdateMediaBuyRequest, + UpdateMediaBuyResponse, + UpdatePropertyListRequest, + UpdatePropertyListResponse, + UpdateRightsRequest, + UpdateRightsResponse, + UrlAssetType, + ValidateContentDeliveryRequest, + ValidateContentDeliveryResponse, + ValidateInputRequest, + ValidateInputResponse, + ValidationMode, + VastTrackingEvent, + VastVersion, + VcpmPricingOption, + VenueBreakdownItem, + VerifyBrandClaimPayload, + VerifyBrandClaimRequest, + VerifyBrandClaimResponse, + VerifyBrandClaimsErrorResponse, + VerifyBrandClaimSignedResponse, + VerifyBrandClaimSignedSuccessPayload, + VerifyBrandClaimsPayload, + VerifyBrandClaimsRequest, + VerifyBrandClaimsRequestBulk, + VerifyBrandClaimsResponse, + VerifyBrandClaimsResponseBulk, + VerifyBrandClaimsSignedResponse, + VerifyBrandClaimsSignedSuccessPayload, + ViewThreshold, + WcagLevel, + WebhookChallenge, + WebhookChallengeResponse, + WebhookResponseType, + WholesaleFeedEvent, + WholesaleFeedWebhook, +) +from adcp.types._generated import ( + AudioAsset as AudioContent, +) +from adcp.types._generated import ( + CssAsset as CssContent, +) +from adcp.types._generated import ( + HtmlAsset as HtmlContent, +) +from adcp.types._generated import ( + ImageAsset as ImageContent, +) +from adcp.types._generated import ( + JavascriptAsset as JavascriptContent, +) +from adcp.types._generated import ( + ListTransformersRequestCreativeAgent as ListTransformersRequest, +) +from adcp.types._generated import ( + ListTransformersResponseCreativeAgent as ListTransformersResponse, +) +from adcp.types._generated import ( + Offer as TmpOffer, +) +from adcp.types._generated import TaskStatus as GeneratedTaskStatus +from adcp.types._generated import ( + TextAsset as TextContent, +) +from adcp.types._generated import ( + UrlAsset as UrlContent, +) +from adcp.types._generated import ( + VideoAsset as VideoContent, +) +from adcp.types._generated import ( + WebhookAsset as WebhookContent, +) +from adcp.types._generated import _ErrorFromError as Error +from adcp.types._generated import _PackageFromPackage as Package + +# Import semantic aliases for discriminated unions +from adcp.types.aliases import ( + AccountReferenceById, + AccountReferenceByNaturalKey, + AcquireRightsAcquiredResponse, + AcquireRightsErrorResponse, + AcquireRightsPendingResponse, + AcquireRightsRejectedResponse, + AcquireRightsResponse1, + ActivateSignalErrorResponse, + ActivateSignalResponse1, + ActivateSignalSuccessResponse, + AgentDeployment, + AgentDestination, + AudioFormatAsset, + AudioFormatGroupAsset, + AuthorizedAgent, + AuthorizedAgentsByInlineProperties, + AuthorizedAgentsByPropertyId, + AuthorizedAgentsByPropertyTag, + AuthorizedAgentsByPublisherProperties, + AuthorizedAgentsBySignalId, + AuthorizedAgentsBySignalTag, + BothPreviewRender, + BriefFormatAsset, + # Cross-module name collision aliases (#911, Step 2) + BuildCreativeCreative, + BuildCreativeErrorResponse, + BuildCreativeResponse1, + BuildCreativeSubmittedResponse, + BuildCreativeSuccessResponse, + CalibrateContentErrorResponse, + CalibrateContentResponse1, + CalibrateContentSuccessResponse, + CanonicalAssetSource, + CanonicalCompositionModel, + CanonicalFormatAgentPlacement, + CanonicalFormatBase, + CanonicalFormatDaastAudio, + CanonicalFormatDisplayTag, + CanonicalFormatHostedAudio, + CanonicalFormatHostedVideo, + CanonicalFormatHtml5Banner, + CanonicalFormatImage, + CanonicalFormatImageCarousel, + CanonicalFormatKind, + CanonicalFormatNativeInFeed, + CanonicalFormatResponsiveCreative, + CanonicalFormatSponsoredPlacement, + CanonicalFormatVastVideo, + CanonicalProjectionReference, + CanonicalSlotOverride, + CapabilitiesAccount, + CapabilitiesCreative, + CapabilitiesMediaBuy, + CatalogFormatAsset, + CatalogGroupBinding, + ComplyErrorResponse, + ComplyListScenariosResponse, + ComplySimulationResponse, + ComplyStateTransitionResponse, + ComplyTestControllerResponse1, + ConsentBasis, + CoreAccount, + CoreCreditLimit, + CoreGovernanceAgent, + CoreMediaBuy, + CoreSetup, + CreateContentStandardsErrorResponse, + CreateContentStandardsResponse1, + CreateContentStandardsSuccessResponse, + CreateMediaBuyAuthentication, + CreateMediaBuyErrorResponse, + CreateMediaBuyResponse1, + CreateMediaBuySubmittedResponse, + CreateMediaBuySuccessResponse, + CssFormatAsset, + CssFormatGroupAsset, + DaastFormatAsset, + DaastFormatGroupAsset, + DeliveryCreative, + Deployment, + Destination, + DurationUnit, + FormatAssetUnion, + FormatId, + GetAccountFinancialsErrorResponse, + GetAccountFinancialsResponse1, + GetAccountFinancialsSuccessResponse, + GetBrandIdentityErrorResponse, + GetBrandIdentityField, + GetBrandIdentityResponse1, + GetBrandIdentitySuccessResponse, + GetContentStandardsErrorResponse, + GetContentStandardsResponse1, + GetContentStandardsSuccessResponse, + GetCreativeDeliveryByBuyerRefRequest, + GetCreativeDeliveryByCreativeRequest, + GetCreativeDeliveryByMediaBuyRequest, + GetCreativeFeaturesErrorResponse, + GetCreativeFeaturesResponse1, + GetCreativeFeaturesSuccessResponse, + GetMediaBuyArtifactsErrorResponse, + GetMediaBuyArtifactsResponse1, + GetMediaBuyArtifactsSuccessResponse, + GetMediaBuysMediaBuy, + GetProductsBriefRequest, + GetProductsField, + GetProductsInputRequiredResponse, + GetProductsRefineRequest, + GetProductsResponseUnion, + GetProductsSubmittedResponse, + GetProductsSuccessResponse, + GetProductsWholesaleRequest, + GetProductsWorkingResponse, + GetRightsErrorResponse, + GetRightsResponse1, + GetRightsSuccessResponse, + GetSignalsDiscoveryRequest, + GetSignalsLookupRequest, + GetSignalsResponseUnion, + GetSignalsSignal, + GetSignalsSubmittedResponse, + GetSignalsSuccessResponse, + GetSignalsWorkingResponse, + GovernanceAuthentication, + GroupFormatAssetUnion, + HtmlFormatAsset, + HtmlFormatGroupAsset, + HtmlPreviewRender, + ImageFormatAsset, + ImageFormatGroupAsset, + InlineDaastAsset, + InlineVastAsset, + JavascriptFormatAsset, + JavascriptFormatGroupAsset, + KeyValueActivationKey, + ListContentStandardsErrorResponse, + ListContentStandardsResponse1, + ListContentStandardsSuccessResponse, + ListCreativesCreative, + ListCreativesSort, + ListTasksSort, + LogEventErrorResponse, + LogEventResponse1, + LogEventSuccessResponse, + MarkdownFormatAsset, + MarkdownFormatGroupAsset, + MediaBuyDeliveryStatus, + NotificationAuthentication, + OverlayUnit, + PixelTrackerAsset, + PixelTrackerEvent, + PixelTrackerMethod, + PlatformDeployment, + PlatformDestination, + PreviewCreativeBatchResponse, + PreviewCreativeResponse1, + PreviewCreativeSingleResponse, + PreviewCreativeVariantResponse, + PricingOption, + ProductFormatDeclaration, + ProductFormatSellerPreference, + PropertyId, + PropertyTag, + ProvenanceDeclaredBy, + ProvidePerformanceFeedbackByBuyerRefRequest, + ProvidePerformanceFeedbackByMediaBuyRequest, + ProvidePerformanceFeedbackErrorResponse, + ProvidePerformanceFeedbackResponse1, + ProvidePerformanceFeedbackSuccessResponse, + PublisherProperties, + PublisherPropertiesAll, + PublisherPropertiesById, + PublisherPropertiesByTag, + PushNotificationAuthentication, + RealEstateUnit, + Recovery, + RepeatableAssetGroup, + ReportingWebhookAuthentication, + SegmentIdActivationKey, + SiSendActionResponseRequest, + SiSendTextMessageRequest, + SiSponsoredContextDeclaredBy, + Source, + SyncAccountsAccount, + SyncAccountsCreditLimit, + SyncAccountsErrorResponse, + SyncAccountsResponse1, + SyncAccountsSetup, + SyncAccountsSuccessResponse, + SyncAudiencesAudience, + SyncAudiencesErrorResponse, + SyncAudiencesResponse1, + SyncAudiencesSubmittedResponse, + SyncAudiencesSuccessResponse, + SyncCatalogResult, + SyncCatalogsErrorResponse, + SyncCatalogsResponse1, + SyncCatalogsSubmittedResponse, + SyncCatalogsSuccessResponse, + SyncCreativeResult, + SyncCreativesCreative, + SyncCreativesErrorResponse, + SyncCreativesResponse1, + SyncCreativesResponse3, + SyncCreativesSubmittedResponse, + SyncCreativesSuccessResponse, + SyncEventSourcesErrorResponse, + SyncEventSourcesResponse1, + SyncEventSourcesSetup, + SyncEventSourcesSuccessResponse, + SyncGovernanceAccount, + SyncGovernanceGovernanceAgent, + TasksListSort, + TextFormatAsset, + TextFormatGroupAsset, + UnknownFormatAsset, + UnknownGroupAsset, + UpdateContentStandardsErrorResponse, + UpdateContentStandardsResponse1, + UpdateContentStandardsSuccessResponse, + UpdateMediaBuyErrorResponse, + UpdateMediaBuyPackagesRequest, + UpdateMediaBuyPropertiesRequest, + UpdateMediaBuyResponse1, + UpdateMediaBuyResponse3, + UpdateMediaBuySubmittedResponse, + UpdateMediaBuySuccessResponse, + UrlDaastAsset, + UrlFormatAsset, + UrlFormatGroupAsset, + UrlPreviewRender, + UrlVastAsset, + V1CanonicalDimensions, + V1CanonicalGlobPattern, + V1CanonicalMapping, + V1CanonicalStructural, + V1CanonicalStructuralPattern, + V1CanonicalV2Projection, + V1V2CanonicalFormatMappingRegistry, + ValidateContentDeliveryErrorResponse, + ValidateContentDeliveryResponse1, + ValidateContentDeliverySuccessResponse, + VastFormatAsset, + VastFormatGroupAsset, + VehicleUnit, + VideoFormatAsset, + VideoFormatGroupAsset, + WebhookFormatAsset, + WebhookFormatGroupAsset, + WholesaleFeedSignal, +) + +# Re-export core types (not in generated, but part of public API) +# Note: We don't import TaskStatus here to avoid shadowing GeneratedTaskStatus +# Users should import TaskStatus from adcp.types.core directly if they need the core enum +from adcp.types.core import ( + AgentConfig, + Member, + Policy, + PolicyExemplar, + PolicyExemplars, + PolicyHistory, + PolicyRevision, + PolicySummary, + Protocol, + ResolvedBrand, + ResolvedProperty, + TaskResult, + WebhookMetadata, +) + +# Deprecated: types removed from _generated.py but classes still exist in generated_poc +from adcp.types.generated_poc.brand import Asset, Disclaimer, Fonts, ProductCatalog +from adcp.types.generated_poc.core.catalog_item_delivery_metrics import ( + CatalogItemDeliveryMetrics as ByCatalogItemItem, +) +from adcp.types.generated_poc.core.outcome_measurement import ( + OutcomeMeasurementDeprecated as OutcomeMeasurement, +) +from adcp.types.generated_poc.enums.metric_type import MetricTypeDeprecated as MetricType + +# Status: _generated picks invoice status (get_account_financials_response) due to +# alphabetical module sort. Import the delivery status variant directly for backward compat. +from adcp.types.generated_poc.media_buy.get_media_buy_delivery_response import ( # noqa: E501 + Status, +) + +# Re-export type guards for discriminated union response handling +from adcp.types.guards import ( # noqa: F401 + is_activate_signal_error, + is_activate_signal_success, + is_adcp_error, + is_adcp_success, + is_build_creative_error, + is_build_creative_submitted, + is_build_creative_success, + is_calibrate_content_success, + is_create_media_buy_error, + is_create_media_buy_success, + is_get_account_financials_error, + is_get_account_financials_success, + is_get_creative_features_success, + is_log_event_error, + is_log_event_success, + is_performance_feedback_error, + is_performance_feedback_success, + is_sync_accounts_error, + is_sync_accounts_success, + is_sync_catalogs_error, + is_sync_catalogs_submitted, + is_sync_catalogs_success, + is_sync_creatives_error, + is_sync_creatives_submitted, + is_sync_creatives_success, + is_update_media_buy_error, + is_update_media_buy_success, + is_validate_content_delivery_success, +) +from adcp.types.projections import ( + AccountResponse, + BusinessEntityResponse, + project_geo_postal_areas, + to_account_response, +) +from adcp.types.registry import BrandSource + +# Schema-variant marker for cross-class entity overrides (#710). Adopters +# annotate Pydantic field overrides with ``SchemaVariant[T]`` instead of +# ``# type: ignore[assignment]`` when substituting a sibling class for the +# parent's declared type. Activate the mypy plugin via +# ``[tool.mypy] plugins = ["adcp.types.mypy_plugin"]`` to suppress the +# override-compat check on those fields. +from adcp.types.variants import SchemaVariant + +# Semantic aliases for auto-generated field enum names +ListCreativesField = Field1 + +# FieldModel: _generated picks brand.get_brand_identity_request.FieldModel due to +# alphabetical module sort. Override to preserve backward compat with the original +# get_products_request variant (which the generator renamed to Field1 in that module). +FieldModel = GetProductsField # type: ignore[misc,assignment] # noqa: F811 + +# Backward compatibility aliases +AssetType = AssetContentType # Use AssetContentType instead +Measurement = OutcomeMeasurement # Renamed upstream to OutcomeMeasurement +Preview = PreviewCreativeResponse +Results = GetMediaBuyDeliveryResponse + +# Pricing type renames: upstream merged auction/fixed variants into single types +CpmAuctionPricingOption = CpmPricingOption +CpmFixedRatePricingOption = CpmPricingOption +VcpmAuctionPricingOption = VcpmPricingOption +VcpmFixedRatePricingOption = VcpmPricingOption + +# Activation key schema change: property_id/property_tag → segment_id/key_value +PropertyIdActivationKey = SegmentIdActivationKey +PropertyTagActivationKey = KeyValueActivationKey + +# Deprecated: types removed from upstream schemas entirely +# Performance was removed; PerformanceFeedback is the replacement +Performance = PerformanceFeedback + +# MediaSubAsset (SubAsset1) and TextSubAsset (SubAsset2) were removed from the +# upstream schema with no replacement. These stubs exist only to provide a clear +# error message for code that still references them. + + +class MediaSubAsset: + """Removed from ADCP schema. Previously SubAsset with asset_kind='media'.""" + + def __init__(self, *args: object, **kwargs: object) -> None: + raise TypeError( + "MediaSubAsset was removed from the ADCP schema. " "There is no direct replacement." + ) + + +class TextSubAsset: + """Removed from ADCP schema. Previously SubAsset with asset_kind='text'.""" + + def __init__(self, *args: object, **kwargs: object) -> None: + raise TypeError( + "TextSubAsset was removed from the ADCP schema. " "There is no direct replacement." + ) + + +# Preview response rename aliases (per-mode Request variants were removed when +# PreviewCreativeRequest collapsed to a single class with a request_type enum). +PreviewCreativeStaticResponse = PreviewCreativeSingleResponse +PreviewCreativeInteractiveResponse = PreviewCreativeBatchResponse + +# Schema renames from filter ref split (v1.0.0) +Action = CreativeAction +Capability = CreativeAgentCapability +CoBranding = CoBrandingRequirement +LandingPage = LandingPageRequirement +Method = HttpMethod +ModuleType = JavascriptModuleType +TrackingEvent = VastTrackingEvent # Split into DaastTrackingEvent and VastTrackingEvent +Unit = DimensionUnit +OutputFormat = PreviewOutputFormat +ResponseType = WebhookResponseType +Scheme = AuthenticationScheme +SignalType = SignalCatalogType +UrlType = UrlAssetType +AvailableReportingFrequency = ReportingFrequency + +# Internal normalization helpers used by generated response models and server +# envelope handling. Keep these importable through ``adcp.types`` for the +# repo's generated-type layering rule, but leave them out of ``__all__`` so they +# do not become part of the documented public API. +from adcp.types.media_buy_status_helpers import ( # noqa: E402 + MEDIA_BUY_LEGACY_STATUS_VALUES as MEDIA_BUY_LEGACY_STATUS_VALUES, +) +from adcp.types.media_buy_status_helpers import ( + unwrap_enum_value as unwrap_enum_value, +) + +# Public surface re-exported by :mod:`adcp.types`. Defining ``__all__`` here +# lets the type-checking ``from adcp.types._eager import (...)`` block in +# ``__init__`` re-export these names under mypy --strict (--no-implicit-reexport). +# This is the full importable surface (documented types + internal re-export +# helpers like the guard functions); the documented public list is +# ``adcp.types.__all__``. +__all__ = [ + "A2UiComponent", + "A2UiSurface", + "Account", + "AccountAuthorization", + "AccountReference", + "AccountReferenceById", + "AccountReferenceByNaturalKey", + "AccountResponse", + "AccountScope", + "AccountWithAuthorization", + "AcquireRightsAcquiredResponse", + "AcquireRightsErrorResponse", + "AcquireRightsPendingResponse", + "AcquireRightsRejectedResponse", + "AcquireRightsRequest", + "AcquireRightsResponse", + "AcquireRightsResponse1", + "Action", + "ActivateSignalErrorResponse", + "ActivateSignalRequest", + "ActivateSignalResponse", + "ActivateSignalResponse1", + "ActivateSignalSuccessResponse", + "AdcpProtocol", + "AdvertiserIndustry", + "AgentConfig", + "AgentDeployment", + "AgentDestination", + "AggregatedTotals", + "AiTool", + "Artifact", + "ArtifactWebhookPayload", + "Asset", + "AssetContentType", + "AssetType", + "AssignedPackage", + "Assignments", + "AudienceSource", + "AudioContent", + "AudioFormatAsset", + "AudioFormatGroupAsset", + "Authentication", + "AuthenticationScheme", + "AuthorizationRequiredDetails", + "AuthorizedAgent", + "AuthorizedAgents", + "AuthorizedAgentsByInlineProperties", + "AuthorizedAgentsByPropertyId", + "AuthorizedAgentsByPropertyTag", + "AuthorizedAgentsByPublisherProperties", + "AuthorizedAgentsBySignalId", + "AuthorizedAgentsBySignalTag", + "AvailableMetric", + "AvailablePackage", + "AvailableReportingFrequency", + "BothPreviewRender", + "BrandReference", + "BrandSource", + "BriefFormatAsset", + "BuildCreativeCreative", + "BuildCreativeErrorResponse", + "BuildCreativeRequest", + "BuildCreativeResponse", + "BuildCreativeResponse1", + "BuildCreativeSubmittedResponse", + "BuildCreativeSuccessResponse", + "BusinessEntity", + "BusinessEntityResponse", + "BuyingMode", + "ByCatalogItemItem", + "ByPackageItem", + "CalibrateContentErrorResponse", + "CalibrateContentRequest", + "CalibrateContentResponse", + "CalibrateContentResponse1", + "CalibrateContentSuccessResponse", + "CanonicalAssetSource", + "CanonicalCompositionModel", + "CanonicalFormatAgentPlacement", + "CanonicalFormatBase", + "CanonicalFormatDaastAudio", + "CanonicalFormatDisplayTag", + "CanonicalFormatHostedAudio", + "CanonicalFormatHostedVideo", + "CanonicalFormatHtml5Banner", + "CanonicalFormatImage", + "CanonicalFormatImageCarousel", + "CanonicalFormatKind", + "CanonicalFormatNativeInFeed", + "CanonicalFormatResponsiveCreative", + "CanonicalFormatSponsoredPlacement", + "CanonicalFormatVastVideo", + "CanonicalProjectionReference", + "CanonicalSlotOverride", + "CapabilitiesAccount", + "CapabilitiesCreative", + "CapabilitiesMediaBuy", + "Capability", + "Catalog", + "CatalogAction", + "CatalogFieldBinding", + "CatalogFieldBinding1", + "CatalogFieldMapping", + "CatalogFormatAsset", + "CatalogGroupBinding", + "CatalogItemStatus", + "CatalogRequirements", + "CatalogType", + "CheckGovernanceRequest", + "CheckGovernanceResponse", + "CoBranding", + "CoBrandingRequirement", + "CollectionList", + "CollectionListChangedWebhook", + "CollectionListFilters", + "Colors", + "ComplyErrorResponse", + "ComplyListScenariosResponse", + "ComplySimulationResponse", + "ComplyStateTransitionResponse", + "ComplyTestControllerRequest", + "ComplyTestControllerResponse", + "ComplyTestControllerResponse1", + "ConsentBasis", + "Contact", + "ContentIdType", + "ContentStandards", + "ContextMatchRequest", + "ContextMatchResponse", + "ContextObject", + "CoreAccount", + "CoreCreditLimit", + "CoreGovernanceAgent", + "CoreMediaBuy", + "CoreSetup", + "Country", + "CpaPricingOption", + "CpcPricingOption", + "CpcvPricingOption", + "CpmAuctionPricingOption", + "CpmFixedRatePricingOption", + "CpmPricingOption", + "CppPricingOption", + "CpvPricingOption", + "CreateCollectionListRequest", + "CreateCollectionListResponse", + "CreateContentStandardsErrorResponse", + "CreateContentStandardsRequest", + "CreateContentStandardsResponse", + "CreateContentStandardsResponse1", + "CreateContentStandardsSuccessResponse", + "CreateMediaBuyAuthentication", + "CreateMediaBuyErrorResponse", + "CreateMediaBuyRequest", + "CreateMediaBuyResponse", + "CreateMediaBuyResponse1", + "CreateMediaBuySubmittedResponse", + "CreateMediaBuySuccessResponse", + "CreatePropertyListRequest", + "CreatePropertyListResponse", + "Creative", + "CreativeAction", + "CreativeAgent", + "CreativeAgentCapability", + "CreativeApproval", + "CreativeApprovalStatus", + "CreativeAsset", + "CreativeAssignment", + "CreativeFilters", + "CreativeManifest", + "CreativePolicy", + "CreativeStatus", + "CreativeVariant", + "CreditLimit", + "CssContent", + "CssFormatAsset", + "CssFormatGroupAsset", + "DaastFormatAsset", + "DaastFormatGroupAsset", + "DaastTrackingEvent", + "DaastVersion", + "DailyBreakdownItem", + "DateRange", + "DatetimeRange", + "DayOfWeek", + "DaypartTarget", + "DeleteCollectionListRequest", + "DeleteCollectionListResponse", + "DeletePropertyListRequest", + "DeletePropertyListResponse", + "DeliveryCreative", + "DeliveryForecast", + "DeliveryMeasurement", + "DeliveryMetrics", + "DeliveryStatus", + "DeliveryType", + "DemographicSystem", + "Deployment", + "Destination", + "DevicePlatform", + "DeviceType", + "DimensionUnit", + "Dimensions", + "Disclaimer", + "DoohMetrics", + "DownstreamConnectionRequirement", + "Duration", + "DurationUnit", + "Error", + "ErrorCode", + "EventType", + "ExtensionObject", + "FeedFormat", + "FeedbackSource", + "Field1", + "FieldModel", + "FlatRatePricingOption", + "Fonts", + "ForecastMethod", + "ForecastPoint", + "ForecastRange", + "ForecastRangeUnit", + "ForecastableMetric", + "Format", + "FormatAssetUnion", + "FormatCard", + "FormatCardDetailed", + "FormatId", + "FormatIdParameter", + "FormatOptionReference", + "FormatReferenceStructuredObject", + "FrequencyCap", + "FrequencyCapScope", + "GeneratedTaskStatus", + "GeoCountry", + "GeoMetro", + "GeoRegion", + "GetAccountFinancialsErrorResponse", + "GetAccountFinancialsRequest", + "GetAccountFinancialsResponse", + "GetAccountFinancialsResponse1", + "GetAccountFinancialsSuccessResponse", + "GetAdcpCapabilitiesRequest", + "GetAdcpCapabilitiesResponse", + "GetBrandIdentityErrorResponse", + "GetBrandIdentityField", + "GetBrandIdentityRequest", + "GetBrandIdentityResponse", + "GetBrandIdentityResponse1", + "GetBrandIdentitySuccessResponse", + "GetCollectionListRequest", + "GetCollectionListResponse", + "GetContentStandardsErrorResponse", + "GetContentStandardsRequest", + "GetContentStandardsResponse", + "GetContentStandardsResponse1", + "GetContentStandardsSuccessResponse", + "GetCreativeDeliveryByBuyerRefRequest", + "GetCreativeDeliveryByCreativeRequest", + "GetCreativeDeliveryByMediaBuyRequest", + "GetCreativeDeliveryRequest", + "GetCreativeDeliveryResponse", + "GetCreativeFeaturesErrorResponse", + "GetCreativeFeaturesRequest", + "GetCreativeFeaturesResponse", + "GetCreativeFeaturesResponse1", + "GetCreativeFeaturesSuccessResponse", + "GetMediaBuyArtifactsErrorResponse", + "GetMediaBuyArtifactsRequest", + "GetMediaBuyArtifactsResponse", + "GetMediaBuyArtifactsResponse1", + "GetMediaBuyArtifactsSuccessResponse", + "GetMediaBuyDeliveryRequest", + "GetMediaBuyDeliveryResponse", + "GetMediaBuysMediaBuy", + "GetMediaBuysRequest", + "GetMediaBuysResponse", + "GetPlanAuditLogsRequest", + "GetPlanAuditLogsResponse", + "GetProductsBriefRequest", + "GetProductsField", + "GetProductsInputRequiredResponse", + "GetProductsRefineRequest", + "GetProductsRequest", + "GetProductsResponse", + "GetProductsResponseUnion", + "GetProductsSubmittedResponse", + "GetProductsSuccessResponse", + "GetProductsWholesaleRequest", + "GetProductsWorkingResponse", + "GetPropertyListRequest", + "GetPropertyListResponse", + "GetRightsErrorResponse", + "GetRightsRequest", + "GetRightsResponse", + "GetRightsResponse1", + "GetRightsSuccessResponse", + "GetSignalsDiscoveryRequest", + "GetSignalsLookupRequest", + "GetSignalsRequest", + "GetSignalsResponse", + "GetSignalsResponseUnion", + "GetSignalsSignal", + "GetSignalsSubmittedResponse", + "GetSignalsSuccessResponse", + "GetSignalsWorkingResponse", + "GetTaskStatusRequest", + "GetTaskStatusResponse", + "GovernanceAgent", + "GovernanceAuthentication", + "GroupFormatAssetUnion", + "Gtin", + "HtmlContent", + "HtmlFormatAsset", + "HtmlFormatGroupAsset", + "HtmlPreviewRender", + "HttpMethod", + "Identifier", + "IdentityMatchRequest", + "IdentityMatchResponse", + "ImageContent", + "ImageFormatAsset", + "ImageFormatGroupAsset", + "InlineDaastAsset", + "InlineVastAsset", + "Input", + "JavascriptContent", + "JavascriptFormatAsset", + "JavascriptFormatGroupAsset", + "JavascriptModuleType", + "KellerType", + "KeyValueActivationKey", + "LandingPage", + "LandingPageRequirement", + "ListAccountsRequest", + "ListAccountsResponse", + "ListCollectionListsRequest", + "ListCollectionListsResponse", + "ListContentStandardsErrorResponse", + "ListContentStandardsRequest", + "ListContentStandardsResponse", + "ListContentStandardsResponse1", + "ListContentStandardsSuccessResponse", + "ListCreativeFormatsRequest", + "ListCreativeFormatsResponse", + "ListCreativesCreative", + "ListCreativesField", + "ListCreativesRequest", + "ListCreativesResponse", + "ListCreativesSort", + "ListPropertyListsRequest", + "ListPropertyListsResponse", + "ListTasksRequest", + "ListTasksResponse", + "ListTasksSort", + "ListTransformersRequest", + "ListTransformersResponse", + "LogEventErrorResponse", + "LogEventRequest", + "LogEventResponse", + "LogEventResponse1", + "LogEventSuccessResponse", + "Logo", + "MEDIA_BUY_LEGACY_STATUS_VALUES", + "MarkdownFlavor", + "MarkdownFormatAsset", + "MarkdownFormatGroupAsset", + "McpWebhookPayload", + "Measurement", + "MeasurementPeriod", + "MediaBuy", + "MediaBuyDelivery", + "MediaBuyDeliveryStatus", + "MediaBuyDeliveryWebhookResult", + "MediaBuyFeatures", + "MediaBuyPackage", + "MediaBuyStatus", + "MediaChannel", + "MediaSubAsset", + "Member", + "Metadata", + "Method", + "MetricType", + "ModuleType", + "NotificationAuthentication", + "NotificationConfig", + "NotificationType", + "OfferPrice", + "Offering", + "OfferingAssetConstraint", + "OfferingAssetGroup", + "OptimizationGoal", + "OutcomeMeasurement", + "OutputFormat", + "Overlay", + "OverlayUnit", + "Pacing", + "Package", + "PackageRequest", + "PackageSignalTargeting", + "PackageSignalTargetingGroup", + "PackageSignalTargetingGroups", + "PackageUpdate", + "Pagination", + "PaginationRequest", + "PaginationResponse", + "Parameters", + "PaymentTerms", + "Performance", + "PerformanceFeedback", + "PixelTrackerAsset", + "PixelTrackerEvent", + "PixelTrackerMethod", + "Placement", + "PlacementReference", + "PlatformDeployment", + "PlatformDestination", + "Policy", + "PolicyExemplar", + "PolicyExemplars", + "PolicyHistory", + "PolicyRevision", + "PolicySummary", + "PostalArea", + "Preview", + "PreviewCreativeBatchResponse", + "PreviewCreativeInteractiveResponse", + "PreviewCreativeRequest", + "PreviewCreativeResponse", + "PreviewCreativeResponse1", + "PreviewCreativeSingleResponse", + "PreviewCreativeStaticResponse", + "PreviewCreativeVariantResponse", + "PreviewOutputFormat", + "PreviewRender", + "PriceGuidance", + "PricingCurrency", + "PricingModel", + "PricingOption", + "PrimaryCountry", + "Product", + "ProductCard", + "ProductCardDetailed", + "ProductCatalog", + "ProductFilters", + "ProductFormatDeclaration", + "ProductFormatSellerPreference", + "ProductSignalTargetingOption", + "Property", + "PropertyId", + "PropertyIdActivationKey", + "PropertyIdentifierTypes", + "PropertyList", + "PropertyListChangedWebhook", + "PropertyListFilters", + "PropertyListReference", + "PropertyTag", + "PropertyTagActivationKey", + "PropertyType", + "Proposal", + "Protocol", + "ProtocolEnvelope", + "ProtocolResponse", + "ProvenanceDeclaredBy", + "ProvidePerformanceFeedbackByBuyerRefRequest", + "ProvidePerformanceFeedbackByMediaBuyRequest", + "ProvidePerformanceFeedbackErrorResponse", + "ProvidePerformanceFeedbackRequest", + "ProvidePerformanceFeedbackResponse", + "ProvidePerformanceFeedbackResponse1", + "ProvidePerformanceFeedbackSuccessResponse", + "PublisherDomain", + "PublisherIdentifierTypes", + "PublisherProperties", + "PublisherPropertiesAll", + "PublisherPropertiesById", + "PublisherPropertiesByTag", + "PushNotificationAuthentication", + "PushNotificationConfig", + "QuartileData", + "QuerySummary", + "ReachUnit", + "RealEstateUnit", + "Recovery", + "Refine", + "RefinementApplied", + "RefinementApplied1", + "RefinementApplied2", + "RefinementApplied3", + "Renders", + "RepeatableAssetGroup", + "ReportPlanOutcomeRequest", + "ReportPlanOutcomeResponse", + "ReportUsageRequest", + "ReportUsageResponse", + "ReportingBucket", + "ReportingCapabilities", + "ReportingFrequency", + "ReportingPeriod", + "ReportingWebhook", + "ReportingWebhookAuthentication", + "Request", + "ResolvedBrand", + "ResolvedProperty", + "Response", + "ResponsePayloadJwsEnvelope", + "ResponseType", + "Responsive", + "Results", + "RightsPricingOption", + "RightsTerms", + "SchemaVariant", + "Scheme", + "Security", + "SegmentIdActivationKey", + "SellerAgentReference", + "Setup", + "SiCapabilities", + "SiGetOfferingRequest", + "SiGetOfferingResponse", + "SiIdentity", + "SiInitiateSessionRequest", + "SiInitiateSessionResponse", + "SiSendActionResponseRequest", + "SiSendMessageRequest", + "SiSendMessageResponse", + "SiSendTextMessageRequest", + "SiSponsoredContextDeclaredBy", + "SiTerminateSessionRequest", + "SiTerminateSessionResponse", + "SiUiElement", + "Signal", + "SignalAvailabilityType", + "SignalCatalogType", + "SignalDefinitionEnrichment", + "SignalFilters", + "SignalListing", + "SignalPricingOption", + "SignalRef", + "SignalTargeting", + "SignalTargetingExpression", + "SignalTargetingRules", + "SignalType", + "Snapshot", + "SnapshotUnavailableReason", + "Sort", + "SortApplied", + "SortDirection", + "Source", + "Status", + "StatusSummary", + "SyncAccountsAccount", + "SyncAccountsCreditLimit", + "SyncAccountsErrorResponse", + "SyncAccountsRequest", + "SyncAccountsResponse", + "SyncAccountsResponse1", + "SyncAccountsSetup", + "SyncAccountsSuccessResponse", + "SyncAudiencesAudience", + "SyncAudiencesErrorResponse", + "SyncAudiencesRequest", + "SyncAudiencesResponse", + "SyncAudiencesResponse1", + "SyncAudiencesSubmittedResponse", + "SyncAudiencesSuccessResponse", + "SyncCatalogResult", + "SyncCatalogsErrorResponse", + "SyncCatalogsInputRequired", + "SyncCatalogsRequest", + "SyncCatalogsResponse", + "SyncCatalogsResponse1", + "SyncCatalogsSubmitted", + "SyncCatalogsSubmittedResponse", + "SyncCatalogsSuccessResponse", + "SyncCatalogsWorking", + "SyncCreativeResult", + "SyncCreativesCreative", + "SyncCreativesErrorResponse", + "SyncCreativesRequest", + "SyncCreativesResponse", + "SyncCreativesResponse1", + "SyncCreativesResponse3", + "SyncCreativesSubmittedResponse", + "SyncCreativesSuccessResponse", + "SyncEventSourcesErrorResponse", + "SyncEventSourcesRequest", + "SyncEventSourcesResponse", + "SyncEventSourcesResponse1", + "SyncEventSourcesSetup", + "SyncEventSourcesSuccessResponse", + "SyncGovernanceAccount", + "SyncGovernanceGovernanceAgent", + "SyncGovernanceRequest", + "SyncGovernanceResponse", + "SyncPlansRequest", + "SyncPlansResponse", + "Tags", + "TargetingOverlay", + "TaskResult", + "TaskType", + "TasksListSort", + "TextContent", + "TextFormatAsset", + "TextFormatGroupAsset", + "TextSubAsset", + "TimeBasedPricingOption", + "TimeUnit", + "TmpError", + "TmpOffer", + "Totals", + "TrackingEvent", + "Transform", + "Unit", + "UnknownFormatAsset", + "UnknownGroupAsset", + "UpdateCollectionListRequest", + "UpdateCollectionListResponse", + "UpdateContentStandardsErrorResponse", + "UpdateContentStandardsRequest", + "UpdateContentStandardsResponse", + "UpdateContentStandardsResponse1", + "UpdateContentStandardsSuccessResponse", + "UpdateFrequency", + "UpdateMediaBuyErrorResponse", + "UpdateMediaBuyPackagesRequest", + "UpdateMediaBuyPropertiesRequest", + "UpdateMediaBuyRequest", + "UpdateMediaBuyResponse", + "UpdateMediaBuyResponse1", + "UpdateMediaBuyResponse3", + "UpdateMediaBuySubmittedResponse", + "UpdateMediaBuySuccessResponse", + "UpdatePropertyListRequest", + "UpdatePropertyListResponse", + "UpdateRightsRequest", + "UpdateRightsResponse", + "UrlAssetType", + "UrlContent", + "UrlDaastAsset", + "UrlFormatAsset", + "UrlFormatGroupAsset", + "UrlPreviewRender", + "UrlType", + "UrlVastAsset", + "V1CanonicalDimensions", + "V1CanonicalGlobPattern", + "V1CanonicalMapping", + "V1CanonicalStructural", + "V1CanonicalStructuralPattern", + "V1CanonicalV2Projection", + "V1V2CanonicalFormatMappingRegistry", + "ValidateContentDeliveryErrorResponse", + "ValidateContentDeliveryRequest", + "ValidateContentDeliveryResponse", + "ValidateContentDeliveryResponse1", + "ValidateContentDeliverySuccessResponse", + "ValidateInputRequest", + "ValidateInputResponse", + "ValidationMode", + "VastFormatAsset", + "VastFormatGroupAsset", + "VastTrackingEvent", + "VastVersion", + "VcpmAuctionPricingOption", + "VcpmFixedRatePricingOption", + "VcpmPricingOption", + "VehicleUnit", + "VenueBreakdownItem", + "VerifyBrandClaimPayload", + "VerifyBrandClaimRequest", + "VerifyBrandClaimResponse", + "VerifyBrandClaimSignedResponse", + "VerifyBrandClaimSignedSuccessPayload", + "VerifyBrandClaimsErrorResponse", + "VerifyBrandClaimsPayload", + "VerifyBrandClaimsRequest", + "VerifyBrandClaimsRequestBulk", + "VerifyBrandClaimsResponse", + "VerifyBrandClaimsResponseBulk", + "VerifyBrandClaimsSignedResponse", + "VerifyBrandClaimsSignedSuccessPayload", + "VideoContent", + "VideoFormatAsset", + "VideoFormatGroupAsset", + "ViewThreshold", + "WcagLevel", + "WebhookChallenge", + "WebhookChallengeResponse", + "WebhookContent", + "WebhookFormatAsset", + "WebhookFormatGroupAsset", + "WebhookMetadata", + "WebhookResponseType", + "WholesaleFeedEvent", + "WholesaleFeedSignal", + "WholesaleFeedWebhook", + "aliases", + "generated", + "is_activate_signal_error", + "is_activate_signal_success", + "is_adcp_error", + "is_adcp_success", + "is_build_creative_error", + "is_build_creative_submitted", + "is_build_creative_success", + "is_calibrate_content_success", + "is_create_media_buy_error", + "is_create_media_buy_success", + "is_get_account_financials_error", + "is_get_account_financials_success", + "is_get_creative_features_success", + "is_log_event_error", + "is_log_event_success", + "is_performance_feedback_error", + "is_performance_feedback_success", + "is_sync_accounts_error", + "is_sync_accounts_success", + "is_sync_catalogs_error", + "is_sync_catalogs_submitted", + "is_sync_catalogs_success", + "is_sync_creatives_error", + "is_sync_creatives_submitted", + "is_sync_creatives_success", + "is_update_media_buy_error", + "is_update_media_buy_success", + "is_validate_content_delivery_success", + "project_geo_postal_areas", + "to_account_response", + "unwrap_enum_value", +] diff --git a/src/adcp/types/_partial.py b/src/adcp/types/_partial.py new file mode 100644 index 00000000..329d323c --- /dev/null +++ b/src/adcp/types/_partial.py @@ -0,0 +1,48 @@ +"""Shared lazy-facade machinery for the curated partial type modules. + +Each curated partial module (:mod:`adcp.types.media_buy`, ``creative``, ...) is +a thin, lazy re-export of a domain-grouped subset of :mod:`adcp.types`. They all +need the same runtime behaviour — resolve a name through ``adcp.types`` on first +access and cache it — so that behaviour lives here once rather than being copied +into each module (where it would drift). + +The partial modules call this from a ``if not TYPE_CHECKING`` block so type +checkers never see a module-level ``__getattr__`` (which would silence +missing-attribute errors); they get the surface from each module's explicit +``TYPE_CHECKING`` re-export block instead. +""" + +from __future__ import annotations + +from collections.abc import Callable + + +def lazy_partial_surface( + module_name: str, + all_names: list[str], + module_globals: dict[str, object], +) -> tuple[Callable[[str], object], Callable[[], list[str]]]: + """Build the ``(__getattr__, __dir__)`` pair for a curated partial module. + + Names in ``all_names`` resolve through :mod:`adcp.types` (the single source + of truth) and are cached into ``module_globals`` so each fires at most once; + anything else raises :class:`AttributeError`. + """ + resolvable = frozenset(all_names) + + # Inner functions are named without dunders (N807) and bound to the + # module's ``__getattr__`` / ``__dir__`` at the call site; PEP 562 only + # cares about the bound names, not the functions' own ``__name__``. + def module_getattr(name: str) -> object: + if name in resolvable: + import adcp.types + + value = getattr(adcp.types, name) + module_globals[name] = value # cache: fires once per name + return value + raise AttributeError(f"module {module_name!r} has no attribute {name!r}") + + def module_dir() -> list[str]: + return sorted(all_names) + + return module_getattr, module_dir diff --git a/src/adcp/types/buyer.py b/src/adcp/types/buyer.py new file mode 100644 index 00000000..9230d670 --- /dev/null +++ b/src/adcp/types/buyer.py @@ -0,0 +1,126 @@ +"""AdCP buyer types — curated partial surface. + +Buy-side (DSP / agency) surface — product discovery, briefs / refine, +pricing, media buys the buyer sends, performance feedback, brand rights. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a buyer integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.buyer import GetProductsRequest +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "GetProductsRequest", + "GetProductsResponse", + "GetProductsResponseUnion", + "GetProductsSuccessResponse", + "GetProductsWorkingResponse", + "GetProductsSubmittedResponse", + "GetProductsInputRequiredResponse", + "GetProductsBriefRequest", + "GetProductsRefineRequest", + "GetProductsWholesaleRequest", + "Product", + "ProductCard", + "ProductCardDetailed", + "ProductFilters", + "Refine", + "RefinementApplied", + "CreateMediaBuyRequest", + "UpdateMediaBuyRequest", + "PackageRequest", + "TargetingOverlay", + "ProvidePerformanceFeedbackRequest", + "ProvidePerformanceFeedbackResponse", + "ProvidePerformanceFeedbackByMediaBuyRequest", + "ProvidePerformanceFeedbackByBuyerRefRequest", + "PerformanceFeedback", + "FeedbackSource", + "PricingOption", + "PriceGuidance", + "PricingModel", + "PricingCurrency", + "CpmPricingOption", + "CpcPricingOption", + "CpaPricingOption", + "FlatRatePricingOption", + "AcquireRightsRequest", + "GetRightsRequest", + "GetBrandIdentityRequest", + "VerifyBrandClaimsRequest", + "BrandReference", + "BrandSource", + "RightsTerms", + "RightsPricingOption", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + AcquireRightsRequest, + BrandReference, + BrandSource, + CpaPricingOption, + CpcPricingOption, + CpmPricingOption, + CreateMediaBuyRequest, + FeedbackSource, + FlatRatePricingOption, + GetBrandIdentityRequest, + GetProductsBriefRequest, + GetProductsInputRequiredResponse, + GetProductsRefineRequest, + GetProductsRequest, + GetProductsResponse, + GetProductsResponseUnion, + GetProductsSubmittedResponse, + GetProductsSuccessResponse, + GetProductsWholesaleRequest, + GetProductsWorkingResponse, + GetRightsRequest, + PackageRequest, + PerformanceFeedback, + PriceGuidance, + PricingCurrency, + PricingModel, + PricingOption, + Product, + ProductCard, + ProductCardDetailed, + ProductFilters, + ProvidePerformanceFeedbackByBuyerRefRequest, + ProvidePerformanceFeedbackByMediaBuyRequest, + ProvidePerformanceFeedbackRequest, + ProvidePerformanceFeedbackResponse, + Refine, + RefinementApplied, + RightsPricingOption, + RightsTerms, + TargetingOverlay, + UpdateMediaBuyRequest, + VerifyBrandClaimsRequest, + ) diff --git a/src/adcp/types/creative.py b/src/adcp/types/creative.py new file mode 100644 index 00000000..5b439bb8 --- /dev/null +++ b/src/adcp/types/creative.py @@ -0,0 +1,144 @@ +"""AdCP creative types — curated partial surface. + +Creative + format types — sync / build / preview creatives, creative status +and approval, formats, and the open creative-asset union. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a creative integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.creative import SyncCreativesRequest +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "SyncCreativesRequest", + "SyncCreativesResponse", + "SyncCreativesSuccessResponse", + "SyncCreativesSubmittedResponse", + "SyncCreativesErrorResponse", + "BuildCreativeRequest", + "BuildCreativeResponse", + "BuildCreativeSuccessResponse", + "BuildCreativeSubmittedResponse", + "BuildCreativeErrorResponse", + "PreviewCreativeRequest", + "PreviewCreativeResponse", + "PreviewCreativeSingleResponse", + "PreviewCreativeBatchResponse", + "PreviewCreativeVariantResponse", + "PreviewRender", + "Renders", + "ListCreativesRequest", + "ListCreativesResponse", + "ListCreativeFormatsRequest", + "ListCreativeFormatsResponse", + "Creative", + "CreativeAsset", + "CreativeManifest", + "CreativeVariant", + "CreativeAssignment", + "CreativeApproval", + "CreativeApprovalStatus", + "CreativeStatus", + "CreativePolicy", + "CreativeFilters", + "CreativeAgent", + "Format", + "FormatId", + "FormatCard", + "FormatCardDetailed", + "FormatAssetUnion", + "GroupFormatAssetUnion", + "RepeatableAssetGroup", + "Asset", + "AssetContentType", + "ImageContent", + "VideoContent", + "AudioContent", + "HtmlContent", + "TextContent", + "UrlContent", + "Dimensions", + "Responsive", + "GetCreativeFeaturesRequest", + "GetCreativeFeaturesResponse", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + Asset, + AssetContentType, + AudioContent, + BuildCreativeErrorResponse, + BuildCreativeRequest, + BuildCreativeResponse, + BuildCreativeSubmittedResponse, + BuildCreativeSuccessResponse, + Creative, + CreativeAgent, + CreativeApproval, + CreativeApprovalStatus, + CreativeAsset, + CreativeAssignment, + CreativeFilters, + CreativeManifest, + CreativePolicy, + CreativeStatus, + CreativeVariant, + Dimensions, + Format, + FormatAssetUnion, + FormatCard, + FormatCardDetailed, + FormatId, + GetCreativeFeaturesRequest, + GetCreativeFeaturesResponse, + GroupFormatAssetUnion, + HtmlContent, + ImageContent, + ListCreativeFormatsRequest, + ListCreativeFormatsResponse, + ListCreativesRequest, + ListCreativesResponse, + PreviewCreativeBatchResponse, + PreviewCreativeRequest, + PreviewCreativeResponse, + PreviewCreativeSingleResponse, + PreviewCreativeVariantResponse, + PreviewRender, + Renders, + RepeatableAssetGroup, + Responsive, + SyncCreativesErrorResponse, + SyncCreativesRequest, + SyncCreativesResponse, + SyncCreativesSubmittedResponse, + SyncCreativesSuccessResponse, + TextContent, + UrlContent, + VideoContent, + ) diff --git a/src/adcp/types/media_buy.py b/src/adcp/types/media_buy.py new file mode 100644 index 00000000..83efd04b --- /dev/null +++ b/src/adcp/types/media_buy.py @@ -0,0 +1,130 @@ +"""AdCP media buy types — curated partial surface. + +Media-buy lifecycle types — create / update / get media buys, packages, +delivery, pacing, budget, targeting overlays, and media-buy status. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a media buy integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.media_buy import CreateMediaBuyRequest +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "CreateMediaBuyRequest", + "CreateMediaBuyResponse", + "CreateMediaBuySuccessResponse", + "CreateMediaBuySubmittedResponse", + "CreateMediaBuyErrorResponse", + "UpdateMediaBuyRequest", + "UpdateMediaBuyResponse", + "UpdateMediaBuySuccessResponse", + "UpdateMediaBuySubmittedResponse", + "UpdateMediaBuyErrorResponse", + "UpdateMediaBuyPackagesRequest", + "UpdateMediaBuyPropertiesRequest", + "GetMediaBuysRequest", + "GetMediaBuysResponse", + "GetMediaBuyDeliveryRequest", + "GetMediaBuyDeliveryResponse", + "GetMediaBuyArtifactsRequest", + "GetMediaBuyArtifactsResponse", + "MediaBuy", + "MediaBuyPackage", + "MediaBuyDelivery", + "MediaBuyDeliveryStatus", + "MediaBuyStatus", + "MediaBuyFeatures", + "Package", + "PackageRequest", + "PackageUpdate", + "AssignedPackage", + "Pacing", + "Overlay", + "TargetingOverlay", + "FrequencyCap", + "FrequencyCapScope", + "DaypartTarget", + "OptimizationGoal", + "DeliveryMetrics", + "DeliveryStatus", + "DeliveryType", + "DailyBreakdownItem", + "ByPackageItem", + "Totals", + "AggregatedTotals", + "Proposal", + "Results", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + AggregatedTotals, + AssignedPackage, + ByPackageItem, + CreateMediaBuyErrorResponse, + CreateMediaBuyRequest, + CreateMediaBuyResponse, + CreateMediaBuySubmittedResponse, + CreateMediaBuySuccessResponse, + DailyBreakdownItem, + DaypartTarget, + DeliveryMetrics, + DeliveryStatus, + DeliveryType, + FrequencyCap, + FrequencyCapScope, + GetMediaBuyArtifactsRequest, + GetMediaBuyArtifactsResponse, + GetMediaBuyDeliveryRequest, + GetMediaBuyDeliveryResponse, + GetMediaBuysRequest, + GetMediaBuysResponse, + MediaBuy, + MediaBuyDelivery, + MediaBuyDeliveryStatus, + MediaBuyFeatures, + MediaBuyPackage, + MediaBuyStatus, + OptimizationGoal, + Overlay, + Pacing, + Package, + PackageRequest, + PackageUpdate, + Proposal, + Results, + TargetingOverlay, + Totals, + UpdateMediaBuyErrorResponse, + UpdateMediaBuyPackagesRequest, + UpdateMediaBuyPropertiesRequest, + UpdateMediaBuyRequest, + UpdateMediaBuyResponse, + UpdateMediaBuySubmittedResponse, + UpdateMediaBuySuccessResponse, + ) diff --git a/src/adcp/types/protocol.py b/src/adcp/types/protocol.py new file mode 100644 index 00000000..5ab51caf --- /dev/null +++ b/src/adcp/types/protocol.py @@ -0,0 +1,124 @@ +"""AdCP protocol types — curated partial surface. + +Cross-cutting protocol types — request / response envelopes, errors, +pagination, task status, capabilities, and webhook challenge handshakes. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a protocol integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.protocol import Request +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "Request", + "Response", + "ProtocolEnvelope", + "ProtocolResponse", + "AdcpProtocol", + "Protocol", + "Error", + "ErrorCode", + "AuthorizationRequiredDetails", + "Metadata", + "ContextObject", + "ExtensionObject", + "Pagination", + "PaginationRequest", + "PaginationResponse", + "Sort", + "SortDirection", + "SortApplied", + "QuerySummary", + "StatusSummary", + "GetTaskStatusRequest", + "GetTaskStatusResponse", + "ListTasksRequest", + "ListTasksResponse", + "TaskType", + "TaskResult", + "GeneratedTaskStatus", + "GetAdcpCapabilitiesRequest", + "GetAdcpCapabilitiesResponse", + "WebhookChallenge", + "WebhookChallengeResponse", + "WebhookResponseType", + "WebhookMetadata", + "McpWebhookPayload", + "ResponsePayloadJwsEnvelope", + "NotificationConfig", + "NotificationType", + "PushNotificationConfig", + "Authentication", + "AuthenticationScheme", + "Security", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + AdcpProtocol, + Authentication, + AuthenticationScheme, + AuthorizationRequiredDetails, + ContextObject, + Error, + ErrorCode, + ExtensionObject, + GeneratedTaskStatus, + GetAdcpCapabilitiesRequest, + GetAdcpCapabilitiesResponse, + GetTaskStatusRequest, + GetTaskStatusResponse, + ListTasksRequest, + ListTasksResponse, + McpWebhookPayload, + Metadata, + NotificationConfig, + NotificationType, + Pagination, + PaginationRequest, + PaginationResponse, + Protocol, + ProtocolEnvelope, + ProtocolResponse, + PushNotificationConfig, + QuerySummary, + Request, + Response, + ResponsePayloadJwsEnvelope, + Security, + Sort, + SortApplied, + SortDirection, + StatusSummary, + TaskResult, + TaskType, + WebhookChallenge, + WebhookChallengeResponse, + WebhookMetadata, + WebhookResponseType, + ) diff --git a/src/adcp/types/seller.py b/src/adcp/types/seller.py new file mode 100644 index 00000000..03b40eb0 --- /dev/null +++ b/src/adcp/types/seller.py @@ -0,0 +1,138 @@ +"""AdCP seller types — curated partial surface. + +Sell-side (SSP / publisher) surface — products / offerings, properties and +property lists, content standards, governance, catalog sync, account financials. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a seller integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.seller import Product +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "Product", + "Offering", + "OfferingAssetGroup", + "OfferingAssetConstraint", + "Property", + "PropertyType", + "PropertyList", + "PropertyListReference", + "PropertyListFilters", + "CreatePropertyListRequest", + "CreatePropertyListResponse", + "GetPropertyListRequest", + "GetPropertyListResponse", + "ListPropertyListsRequest", + "ListPropertyListsResponse", + "UpdatePropertyListRequest", + "DeletePropertyListRequest", + "AuthorizedAgents", + "AuthorizedAgent", + "PublisherProperties", + "ContentStandards", + "CreateContentStandardsRequest", + "GetContentStandardsRequest", + "ListContentStandardsRequest", + "UpdateContentStandardsRequest", + "ValidateContentDeliveryRequest", + "GovernanceAgent", + "CheckGovernanceRequest", + "CheckGovernanceResponse", + "SyncGovernanceRequest", + "ReportPlanOutcomeRequest", + "GetPlanAuditLogsRequest", + "Catalog", + "CatalogType", + "CatalogRequirements", + "SyncCatalogsRequest", + "SyncCatalogsResponse", + "SyncCatalogResult", + "Account", + "GetAccountFinancialsRequest", + "GetAccountFinancialsResponse", + "CreditLimit", + "PaymentTerms", + "Setup", + "ReportingCapabilities", + "SellerAgentReference", + "ListAccountsRequest", + "SyncAccountsRequest", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + Account, + AuthorizedAgent, + AuthorizedAgents, + Catalog, + CatalogRequirements, + CatalogType, + CheckGovernanceRequest, + CheckGovernanceResponse, + ContentStandards, + CreateContentStandardsRequest, + CreatePropertyListRequest, + CreatePropertyListResponse, + CreditLimit, + DeletePropertyListRequest, + GetAccountFinancialsRequest, + GetAccountFinancialsResponse, + GetContentStandardsRequest, + GetPlanAuditLogsRequest, + GetPropertyListRequest, + GetPropertyListResponse, + GovernanceAgent, + ListAccountsRequest, + ListContentStandardsRequest, + ListPropertyListsRequest, + ListPropertyListsResponse, + Offering, + OfferingAssetConstraint, + OfferingAssetGroup, + PaymentTerms, + Product, + Property, + PropertyList, + PropertyListFilters, + PropertyListReference, + PropertyType, + PublisherProperties, + ReportingCapabilities, + ReportPlanOutcomeRequest, + SellerAgentReference, + Setup, + SyncAccountsRequest, + SyncCatalogResult, + SyncCatalogsRequest, + SyncCatalogsResponse, + SyncGovernanceRequest, + UpdateContentStandardsRequest, + UpdatePropertyListRequest, + ValidateContentDeliveryRequest, + ) diff --git a/src/adcp/types/signals.py b/src/adcp/types/signals.py new file mode 100644 index 00000000..44663bd6 --- /dev/null +++ b/src/adcp/types/signals.py @@ -0,0 +1,115 @@ +"""AdCP signals types — curated partial surface. + +Signal types — discovery / activation, signal targeting, and audiences. + +A stable, narrow alternative to importing the whole :mod:`adcp.types` +namespace. Every name here is also exported from :mod:`adcp.types`; this +module simply groups the ones a signals integration reaches for, and never +exposes the internal generated layer. + +This module is for curation and discoverability, not a separate +performance tier: importing it is cheap, but the first access to *any* AdCP +type (here or via :mod:`adcp.types` / :mod:`adcp`) realizes the full generated +Pydantic graph — there is no per-domain graph. Use it for a smaller, focused +import surface. + + from adcp.types.signals import GetSignalsRequest +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +__all__ = [ + "GetSignalsRequest", + "GetSignalsResponse", + "GetSignalsResponseUnion", + "GetSignalsSuccessResponse", + "GetSignalsWorkingResponse", + "GetSignalsSubmittedResponse", + "GetSignalsDiscoveryRequest", + "GetSignalsLookupRequest", + "GetSignalsSignal", + "ActivateSignalRequest", + "ActivateSignalResponse", + "ActivateSignalSuccessResponse", + "ActivateSignalErrorResponse", + "Signal", + "SignalListing", + "SignalRef", + "SignalFilters", + "SignalDefinitionEnrichment", + "SignalTargeting", + "SignalTargetingExpression", + "SignalTargetingRules", + "SignalPricingOption", + "SignalAvailabilityType", + "SignalCatalogType", + "PackageSignalTargeting", + "PackageSignalTargetingGroup", + "PackageSignalTargetingGroups", + "ProductSignalTargetingOption", + "SegmentIdActivationKey", + "KeyValueActivationKey", + "AudienceSource", + "SyncAudiencesRequest", + "SyncAudiencesResponse", + "SyncAudiencesSuccessResponse", + "SyncAudiencesSubmittedResponse", + "SyncAudiencesErrorResponse", + "SyncAudiencesAudience", +] + + +if not TYPE_CHECKING: + # Lazy runtime resolution (shared with the other partial modules). Defined + # under ``not TYPE_CHECKING`` so type checkers see the surface only via the + # explicit ``TYPE_CHECKING`` re-export block below — a typo'd import is + # flagged rather than silently typed as ``object``. + from adcp.types._partial import lazy_partial_surface + + __getattr__, __dir__ = lazy_partial_surface(__name__, __all__, globals()) + + +if TYPE_CHECKING: + # Eager re-export so type checkers and IDEs see the surface; resolved + # lazily through ``__getattr__`` at runtime. + from adcp.types import ( # noqa: F401 + ActivateSignalErrorResponse, + ActivateSignalRequest, + ActivateSignalResponse, + ActivateSignalSuccessResponse, + AudienceSource, + GetSignalsDiscoveryRequest, + GetSignalsLookupRequest, + GetSignalsRequest, + GetSignalsResponse, + GetSignalsResponseUnion, + GetSignalsSignal, + GetSignalsSubmittedResponse, + GetSignalsSuccessResponse, + GetSignalsWorkingResponse, + KeyValueActivationKey, + PackageSignalTargeting, + PackageSignalTargetingGroup, + PackageSignalTargetingGroups, + ProductSignalTargetingOption, + SegmentIdActivationKey, + Signal, + SignalAvailabilityType, + SignalCatalogType, + SignalDefinitionEnrichment, + SignalFilters, + SignalListing, + SignalPricingOption, + SignalRef, + SignalTargeting, + SignalTargetingExpression, + SignalTargetingRules, + SyncAudiencesAudience, + SyncAudiencesErrorResponse, + SyncAudiencesRequest, + SyncAudiencesResponse, + SyncAudiencesSubmittedResponse, + SyncAudiencesSuccessResponse, + ) diff --git a/src/adcp/webhook_sender.py b/src/adcp/webhook_sender.py index 74e4c94b..ce468797 100644 --- a/src/adcp/webhook_sender.py +++ b/src/adcp/webhook_sender.py @@ -72,12 +72,14 @@ TransportHook, apply_hooks, ) -from adcp.webhooks import ( - create_mcp_webhook_payload, - create_webhook_challenge_payload, - generate_webhook_idempotency_key, - to_wire_dict, -) + +# NOTE: ``from adcp.webhooks import (...)`` is deliberately at the BOTTOM of this +# module (after WebhookSender / WebhookDeliveryResult are defined) to resolve the +# webhooks <-> webhook_sender import cycle regardless of which module is imported +# first. The payload-builder functions are only used inside methods (call time), +# so binding them at module end is sufficient. See the matching note in +# webhooks.py. Importing here at the top breaks when webhook_sender is imported +# before webhooks (e.g. ``from adcp.webhook_sender import WebhookSender``). # The signer emits a signature valid for 300 seconds; anything beyond that # requires a fresh signing call. Senders that retry past this window just @@ -1031,6 +1033,16 @@ async def _send_bytes( ) +# Payload-builder functions used by the send_* methods above. Imported at the +# bottom (after the classes are defined) to break the webhooks <-> webhook_sender +# cycle — see the note next to the removed top-level import. +from adcp.webhooks import ( # noqa: E402 + create_mcp_webhook_payload, + create_webhook_challenge_payload, + generate_webhook_idempotency_key, + to_wire_dict, +) + __all__ = [ "DockerLocalhostRewrite", "TransportHook", diff --git a/tests/fixtures/public_api_snapshot.json b/tests/fixtures/public_api_snapshot.json index c8d3b5e0..0b852823 100644 --- a/tests/fixtures/public_api_snapshot.json +++ b/tests/fixtures/public_api_snapshot.json @@ -921,9 +921,7 @@ "PostalArea", "Preview", "PreviewCreativeBatchResponse", - "PreviewCreativeFormatRequest", "PreviewCreativeInteractiveResponse", - "PreviewCreativeManifestRequest", "PreviewCreativeRequest", "PreviewCreativeResponse", "PreviewCreativeResponse1", @@ -1197,8 +1195,14 @@ "WholesaleFeedWebhook", "WholesaleFeedWebhook", "aliases", + "buyer", + "creative", "generated", + "media_buy", "project_geo_postal_areas", + "protocol", + "seller", + "signals", "to_account_response" ] } diff --git a/tests/test_import_layering.py b/tests/test_import_layering.py index d89ccad5..101eae4a 100644 --- a/tests/test_import_layering.py +++ b/tests/test_import_layering.py @@ -34,6 +34,12 @@ SRC_ROOT / "types" / "_ergonomic.py", SRC_ROOT / "types" / "_generated.py", SRC_ROOT / "types" / "__init__.py", + # ``_eager.py`` holds the eager realization of the public type surface + # (the former ``__init__.py`` body): it binds every exported name from + # ``_generated`` / ``generated_poc`` and runs the import-time patchers. + # ``__init__.py`` is now a thin lazy facade that imports ``_eager`` on + # first attribute access, so the same direct generated-layer access applies. + SRC_ROOT / "types" / "_eager.py", # ``capabilities.py`` is a re-export layer for the bundled # ``get_adcp_capabilities_response`` sub-models — it disambiguates # the ``Account`` / ``MediaBuy`` / ``Creative`` name collisions diff --git a/tests/test_lazy_types.py b/tests/test_lazy_types.py new file mode 100644 index 00000000..e945f90f --- /dev/null +++ b/tests/test_lazy_types.py @@ -0,0 +1,387 @@ +"""Guards for the lazy type surface. + +``adcp`` and ``adcp.types`` are lazy (PEP 562 ``__getattr__``): + +- ``import adcp`` does not build the generated Pydantic schema graph or import + the client / server / a2a stack. +- ``import adcp.types`` does not build the schema graph either; the graph + (``adcp.types._eager``) is realized on first access to a type symbol. +- ``from adcp import ADCPError`` (a non-schema symbol) stays light; importing + a schema symbol (``Product``) triggers the build. +- The curated partial modules (``adcp.types.media_buy`` etc.) are lazy facades + over ``adcp.types`` that never touch the internal generated layer. + +These tests run import-cost assertions in fresh subprocesses so a prior import +elsewhere in the suite can't mask a regression. +""" + +from __future__ import annotations + +import ast +import subprocess +import sys +from pathlib import Path + +import pytest + +SRC_TYPES = Path(__file__).parent.parent / "src" / "adcp" / "types" +PARTIAL_MODULES = ("media_buy", "creative", "signals", "protocol", "buyer", "seller") + + +def _run(code: str) -> str: + """Run ``code`` in a fresh interpreter; return stdout (asserts exit 0).""" + result = subprocess.run( + [sys.executable, "-c", code], + capture_output=True, + text=True, + check=False, + ) + assert result.returncode == 0, f"subprocess failed:\n{result.stderr}" + return result.stdout.strip() + + +# --------------------------------------------------------------------------- # +# Laziness (fresh-interpreter import cost) +# --------------------------------------------------------------------------- # + + +def test_import_adcp_does_not_build_schema_graph() -> None: + """``import adcp`` must not import the generated schema graph or a2a stack.""" + out = _run( + "import sys, adcp;" + "heavy = [m for m in ('adcp.types._eager','adcp.types._generated'," + "'adcp.client','adcp.testing','adcp.server','adcp.decisioning') if m in sys.modules];" + "a2a = [m for m in sys.modules if m.startswith('a2a')];" + "print(repr(heavy)); print(len(a2a))" + ) + heavy, a2a_count = out.splitlines() + assert heavy == "[]", f"import adcp eagerly loaded heavy modules: {heavy}" + assert a2a_count == "0", "import adcp eagerly loaded the a2a stack" + + +def test_import_adcp_does_not_load_importlib_metadata() -> None: + """``import adcp`` must defer ``importlib.metadata`` (the version lookup). + + ``importlib.metadata`` pulls in a sizable stdlib subtree (~15ms); the + version is resolved lazily on first ``adcp.__version__`` access instead. + """ + out = _run("import sys, adcp; print('importlib.metadata' in sys.modules)") + assert out == "False", "import adcp eagerly imported importlib.metadata" + + +def test_version_resolves_lazily() -> None: + """``adcp.__version__`` resolves on demand and only then loads the metadata API.""" + out = _run( + "import sys, adcp;" + "before = 'importlib.metadata' in sys.modules;" + "v = adcp.__version__;" + "print(before); print(isinstance(v, str) and len(v) > 0);" + "print('importlib.metadata' in sys.modules)" + ) + before, is_str, after = out.splitlines() + assert before == "False", "metadata loaded before __version__ was accessed" + assert is_str == "True", "__version__ should be a non-empty string" + assert after == "True", "accessing __version__ should resolve via importlib.metadata" + + +def test_version_not_clobbered_by_version_submodule() -> None: + """``adcp.__version__`` stays a string even after importing ``adcp._version``. + + Guards against the version cache being named ``_version`` (which collides + with the ``adcp._version`` submodule and would make ``__version__`` resolve + to the module object). + """ + out = _run( + "import adcp, adcp._version;" # importing the submodule sets adcp._version + "v = adcp.__version__;" + "print(type(v).__name__); print(v)" + ) + type_name, value = out.splitlines() + assert type_name == "str", f"adcp.__version__ resolved to {type_name}, not str" + assert value and value != "MISSING" + + +# Modules that cross-import other ``adcp`` modules and are realistically +# imported on their own (before ``adcp`` or each other). The eager ``import +# adcp`` used to mask import-order cycles by loading everything in a fixed +# order; under the lazy facade each must import standalone. Guards the +# webhooks <-> webhook_sender cycle (and any sibling) from regressing. +_STANDALONE_FIRST_IMPORT = [ + "adcp.webhook_sender", + "adcp.webhooks", + "adcp.webhook_supervisor", + "adcp.webhook_supervisor_pg", + "adcp.webhook_receiver", + "adcp.simple", + "adcp.feed_mirror", + "adcp.client", + "adcp.registry", + "adcp.adagents", + "adcp.server", +] + + +@pytest.mark.parametrize("module", _STANDALONE_FIRST_IMPORT) +def test_submodule_imports_standalone(module: str) -> None: + """Each cross-importing submodule must import first in a fresh interpreter. + + A circular import only manifests when the module is imported *before* the + module it cycles with, so each runs in its own subprocess. + """ + result = subprocess.run( + [sys.executable, "-c", f"import {module}"], + capture_output=True, + text=True, + check=False, + ) + assert result.returncode == 0, f"`import {module}` failed standalone:\n{result.stderr}" + + +def test_import_adcp_types_does_not_build_schema_graph() -> None: + """``import adcp.types`` must not realize the eager graph.""" + out = _run( + "import sys, adcp.types;" + "print('adcp.types._eager' in sys.modules);" + "print('adcp.types._generated' in sys.modules)" + ) + eager, generated = out.splitlines() + assert eager == "False" and generated == "False", out + + +def test_importing_a_partial_module_is_lazy() -> None: + """Importing a partial module is cheap; the graph builds on first name access.""" + out = _run( + "import sys, adcp.types.media_buy as mb;" + "before = 'adcp.types._eager' in sys.modules;" + "x = mb.CreateMediaBuyRequest;" + "after = 'adcp.types._eager' in sys.modules;" + "print(before); print(after)" + ) + before, after = out.splitlines() + assert before == "False", "importing the partial module eagerly built the graph" + assert after == "True", "accessing a name did not trigger the graph build" + + +def test_non_schema_symbol_stays_light() -> None: + """``from adcp import ADCPError`` must not build the schema graph.""" + out = _run( + "import sys; from adcp import ADCPError;" + "print('adcp.types._generated' in sys.modules);" + "print('adcp.client' in sys.modules)" + ) + assert out.splitlines() == ["False", "False"], out + + +def test_schema_symbol_triggers_build() -> None: + """Accessing a schema symbol realizes the graph — 'asking for schema symbols'.""" + out = _run( + "import sys; from adcp import Product;" "print('adcp.types._generated' in sys.modules)" + ) + assert out == "True" + + +# --------------------------------------------------------------------------- # +# Surface equivalence (lazy facade == eager realization) +# --------------------------------------------------------------------------- # + + +def test_lazy_types_surface_matches_eager() -> None: + """Every ``adcp.types.__all__`` name resolves to the same object as ``_eager``. + + The lazy facade must be behaviourally identical to the eager realization: + each advertised name resolves (no dead entries) and to the *same object*. + """ + import adcp.types + from adcp.types import _eager + + submodules = set(adcp.types._PARTIAL_MODULES) | {"generated", "aliases"} + mismatches = [] + for name in adcp.types.__all__: + if name in submodules: + continue # submodule re-exports, checked separately + if getattr(adcp.types, name) is not getattr(_eager, name): + mismatches.append(name) + assert not mismatches, f"lazy/eager surface diverged for: {mismatches}" + + +def test_eager_only_extras_matches_eager_namespace() -> None: + """``_EAGER_ONLY_EXTRAS`` must list exactly the importable helpers not in __all__. + + These are re-exported for back-compat (response guards + a few helpers) but + kept out of the documented ``__all__``. The fast-fail in ``__getattr__`` + relies on this set being complete; if codegen adds/removes one, this fails + loudly so the constant gets updated. + """ + import types as _types + + import adcp.types + from adcp.types import _eager + + actual = { + name + for name, value in vars(_eager).items() + if not name.startswith("_") + and name != "annotations" + and not isinstance(value, _types.ModuleType) + and name not in set(adcp.types.__all__) + } + assert adcp.types._EAGER_ONLY_EXTRAS == actual, ( + "adcp.types._EAGER_ONLY_EXTRAS drifted from _eager's namespace; " + f"only in constant: {adcp.types._EAGER_ONLY_EXTRAS - actual}; " + f"only in _eager: {actual - adcp.types._EAGER_ONLY_EXTRAS}" + ) + + +def test_unknown_attribute_fails_fast_without_building_graph() -> None: + """A missing/typo'd name raises AttributeError without realizing the graph.""" + out = _run( + "import sys, adcp.types;" + "import pytest;" + "exc=None;\n" + "try:\n" + " adcp.types.NoSuchTypeXYZ\n" + "except AttributeError as e:\n" + " exc=e\n" + "print(exc is not None);" + "print('adcp.types._eager' in sys.modules)" + ) + raised, eager_loaded = out.splitlines() + assert raised == "True", "expected AttributeError for unknown name" + assert eager_loaded == "False", "unknown name should not build the eager graph" + + +def test_star_import_from_adcp_types_resolves_all() -> None: + """``from adcp.types import *`` resolves every advertised name (no dead entries).""" + import adcp.types + + ns: dict[str, object] = {} + exec("from adcp.types import *", ns) # noqa: S102 + missing = [n for n in adcp.types.__all__ if n not in ns] + assert not missing, f"star-import did not resolve: {missing}" + + +def test_partial_module_names_all_resolve_via_adcp_types() -> None: + """Each partial module exposes exactly its ``__all__``, sourced from adcp.types.""" + import importlib + + import adcp.types + + for mod_name in PARTIAL_MODULES: + module = importlib.import_module(f"adcp.types.{mod_name}") + assert module.__all__, f"{mod_name} has empty __all__" + for name in module.__all__: + assert getattr(module, name) is getattr( + adcp.types, name + ), f"adcp.types.{mod_name}.{name} is not the same object as adcp.types.{name}" + assert sorted(dir(module)) == sorted(module.__all__) + + +def test_partial_modules_are_in_types_all() -> None: + """The six partial modules are advertised in ``adcp.types.__all__``.""" + import adcp.types + + for mod_name in PARTIAL_MODULES: + assert mod_name in adcp.types.__all__ + + +@pytest.mark.parametrize("mod_name", PARTIAL_MODULES) +def test_partial_modules_never_import_generated_layer(mod_name: str) -> None: + """Partial modules must not import the internal generated layer (item 4).""" + tree = ast.parse((SRC_TYPES / f"{mod_name}.py").read_text()) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom) and node.module: + assert not node.module.startswith( + ("adcp.types._generated", "adcp.types.generated_poc") + ), f"{mod_name}.py imports the internal generated layer: {node.module}" + + +@pytest.mark.parametrize("mod_name", PARTIAL_MODULES) +def test_partial_modules_avoid_numbered_codegen_names(mod_name: str) -> None: + """Curated partials must not expose codegen-numbered names (e.g. ``*Response1``). + + These trailing-digit names are datamodel-code-generator artifacts that churn + on schema regen; where a name like ``CreateMediaBuyResponse1`` is exposed, the + curated surface should use its semantic alias (``CreateMediaBuySuccessResponse``) + instead. They remain available on the full ``adcp.types`` surface. + """ + import importlib + import re + + module = importlib.import_module(f"adcp.types.{mod_name}") + numbered = [n for n in module.__all__ if re.search(r"[A-Za-z]\d+$", n)] + assert not numbered, ( + f"adcp.types.{mod_name} exposes codegen-numbered names {numbered}; " + "use the semantic alias instead (these churn on schema regen)." + ) + + +# --------------------------------------------------------------------------- # +# Behavior preserved by the lazy facade +# --------------------------------------------------------------------------- # + + +def test_dir_includes_all() -> None: + """``dir()`` covers ``__all__`` for tooling/autocomplete.""" + import adcp + import adcp.types + + assert set(adcp.__all__) <= set(dir(adcp)) + assert set(adcp.types.__all__) <= set(dir(adcp.types)) + + +def test_star_import_from_adcp_resolves_all() -> None: + """``from adcp import *`` resolves every advertised name.""" + import adcp + + ns: dict[str, object] = {} + exec("from adcp import *", ns) # noqa: S102 + missing = [n for n in adcp.__all__ if n not in ns] + assert not missing, f"star-import did not resolve: {missing}" + + +def test_geopostalarea_deprecation_warns_once_then_caches() -> None: + """GeoPostalArea resolves to PostalArea5 and warns once (then is cached). + + The lazy facade caches the resolved alias into the module namespace so the + DeprecationWarning fires on first access only — subsequent accesses hit the + module dict directly and skip ``__getattr__``. + """ + import warnings + + import adcp.types + + # Start uncached so this test observes the first-access warning regardless + # of what ran before it. + adcp.types.__dict__.pop("GeoPostalArea", None) + + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + first = adcp.types.GeoPostalArea + second = adcp.types.GeoPostalArea + third = adcp.types.GeoPostalArea + + assert first.__name__ == "PostalArea5" + assert second is first and third is first + deprecations = [w for w in caught if issubclass(w.category, DeprecationWarning)] + assert len(deprecations) == 1, f"expected one warning, got {len(deprecations)}" + assert "GeoPostalArea is deprecated" in str(deprecations[0].message) + assert "GeoPostalArea" in vars(adcp.types), "alias should be cached after first access" + + +def test_removed_v4_names_take_precedence_over_lazy() -> None: + """Removed-in-4.0 names raise ImportError even though __getattr__ is lazy.""" + import adcp + + removed = ( + "BrandManifest", + "FormatCategory", + "DeliverTo", + "PromotedProducts", + "PromotedOfferings", + "Pricing", + "PackageStatus", + ) + for name in removed: + with pytest.raises(ImportError) as exc: + getattr(adcp, name) + assert "MIGRATION_v3_to_v4.md" in str(exc.value) diff --git a/tests/test_postal_area_compat.py b/tests/test_postal_area_compat.py index 2d59145b..6e82e108 100644 --- a/tests/test_postal_area_compat.py +++ b/tests/test_postal_area_compat.py @@ -36,6 +36,21 @@ ] +@pytest.fixture(autouse=True) +def _reset_geopostalarea_cache(): + """Drop the cached ``GeoPostalArea`` so each test sees a first access. + + The lazy ``adcp.types.__getattr__`` caches ``GeoPostalArea`` after the first + access so the DeprecationWarning fires only once per process. Tests that + assert on the warning must therefore start from an uncached state. + """ + import adcp.types + + adcp.types.__dict__.pop("GeoPostalArea", None) + yield + adcp.types.__dict__.pop("GeoPostalArea", None) + + def _geo_postal_area_cls() -> type: """Access the deprecated alias without raising the DeprecationWarning.""" import adcp.types