Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,100 @@ jobs:
echo ""
echo "✅ All commits follow Conventional Commits format"

downstream-imports:
name: Downstream import smoke (representative consumer symbols)
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Build and install wheel
run: |
python -m pip install --upgrade pip build
python -m build --wheel --outdir dist/
pip install dist/*.whl

# Proxy for real downstream import sites (salesagent, creative agents,
# signals agents). Any ImportError here means we broke the public API
# surface without a migration pointer — failing CI is the goal.
- name: Import representative public-API symbols
run: |
python - <<'PY'
from adcp import (
ADCPClient,
AgentConfig,
BrandReference,
CpmPricingOption,
CreateMediaBuyRequest,
Error,
GetProductsRequest,
ListCreativesRequest,
MediaBuyStatus,
Package,
PackageRequest,
PublisherPropertiesAll,
SyncCatalogsRequest,
)
from adcp.types import (
AudioFormatAsset,
BriefFormatAsset,
CatalogFormatAsset,
ContextObject,
CreativeAsset,
CssFormatAsset,
DaastFormatAsset,
HtmlFormatAsset,
ImageFormatAsset,
JavascriptFormatAsset,
MarkdownFormatAsset,
RepeatableAssetGroup,
TargetingOverlay,
TextFormatAsset,
UrlFormatAsset,
VastFormatAsset,
VideoFormatAsset,
WebhookFormatAsset,
)

# Removed-type shims: old import paths must raise a guided
# ImportError pointing at the migration guide.
import adcp
for name in ("BrandManifest", "FormatCategory", "DeliverTo"):
try:
getattr(adcp, name)
except ImportError as exc:
assert "MIGRATION_v3_to_v4" in str(exc), (
f"{name} deprecation shim dropped migration pointer: {exc}"
)
else:
raise AssertionError(
f"{name} import should raise ImportError with migration pointer"
)

# The deep submodule path (some older import sites reach this far)
# must also surface the migration pointer, not a bare ModuleNotFoundError.
try:
from adcp.types.generated_poc.enums.format_category import FormatCategory # noqa: F401
except ImportError as exc:
assert "MIGRATION_v3_to_v4" in str(exc), exc
else:
raise AssertionError(
"format_category submodule should raise ImportError with migration pointer"
)

assert adcp.__version__ and adcp.__version__ != "3.12.0", (
f"adcp.__version__={adcp.__version__!r} — expected real pkg metadata"
)
assert adcp.get_adcp_version(), "ADCP_VERSION file is empty"

print(f"OK — adcp=={adcp.__version__}, spec={adcp.get_adcp_version()}")
PY

schema-check:
name: Validate schemas are up-to-date
runs-on: ubuntu-latest
Expand Down
50 changes: 50 additions & 0 deletions MIGRATION_v3_to_v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,56 @@ Aliases for all discriminated-union success/error variants live in
`adcp/types/aliases.py`. If a variant you need isn't aliased, file an issue —
aliasing is the supported path; direct `Assets*` imports aren't.

### Creative format asset slots: `<Type>FormatAsset` aliases

Format definitions enumerate asset slots with a discriminated union on
`asset_type`. These are the classes salesagent hit when `Assets5`/`Assets14`
renumbered to `Assets57`/`Assets149`. The stable names are:

| Generated class | Semantic alias | `asset_type` |
|--------------------|-------------------------------|--------------------|
| `Assets` (base) | `ImageFormatAsset` | `image` |
| `Assets81` | `VideoFormatAsset` | `video` |
| `Assets82` | `AudioFormatAsset` | `audio` |
| `Assets83` | `TextFormatAsset` | `text` |
| `Assets84` | `MarkdownFormatAsset` | `markdown` |
| `Assets85` | `HtmlFormatAsset` | `html` |
| `Assets86` | `CssFormatAsset` | `css` |
| `Assets87` | `JavascriptFormatAsset` | `javascript` |
| `Assets88` | `VastFormatAsset` | `vast` |
| `Assets89` | `DaastFormatAsset` | `daast` |
| `Assets90` | `UrlFormatAsset` | `url` |
| `Assets91` | `WebhookFormatAsset` | `webhook` |
| `Assets92` | `BriefFormatAsset` | `brief` |
| `Assets93` | `CatalogFormatAsset` | `catalog` |
| `Assets94` | `RepeatableAssetGroup` | `repeatable_group` |
| `Assets95…Assets106` | `ImageFormatGroupAsset` etc.| (same type inside a group) |

The `Format` prefix disambiguates these *format-slot* types from the
separate *asset-content* types (`VideoAsset`, `HtmlAsset`, `ImageAsset`,
etc. in `adcp.types`), which describe the actual asset payload (codec,
duration, file URL) delivered by creative sync — a distinct concept.

`tests/test_asset_aliases_stable.py` pins each alias to its expected
`asset_type` discriminator default. When upstream renumbers, that test
fails and points at the specific alias that drifted — fix the numbered
import in `src/adcp/types/aliases.py`, not your call sites.

### Deep-submodule `format_category` shim

Some older import sites reach into the raw generated path:

```python
from adcp.types.generated_poc.enums.format_category import FormatCategory
```

4.0 registers a ``sys.modules`` shim for this path so the import raises
an ``ImportError`` with the same migration pointer as the top-level
``from adcp import FormatCategory``, instead of a bare
``ModuleNotFoundError``. If you're seeing the deep path in your code,
switch to the migration above — the shim is a safety net, not a
permanent export.

## Public vs. internal imports

`adcp.types.generated_poc.*` is internal. Generated module paths and class
Expand Down
Loading
Loading