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
23 changes: 23 additions & 0 deletions MIGRATION_v3_to_v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,31 @@
removed several types and renamed fields; this guide lists each change with
before/after code.

## Automated migration

Run the bundled codemod against your source tree first — it rewrites the 9
mechanical `<Type>Asset` → `<Type>Content` renames and prints a structured
report of every removed-type usage that still needs a manual replacement:

```bash
# Dry run — see the plan before anything moves.
python -m adcp.migrate v3-to-v4 ./src

# Rewrite in place. Commit first so `git diff` is your review.
python -m adcp.migrate v3-to-v4 ./src --apply

# Structured JSON for CI / editor integrations.
python -m adcp.migrate v3-to-v4 ./src --json
```

The CLI exits 1 when there are manual-review findings (removed types, numbered
`Assets` imports, `adcp.types.generated_poc` imports) — wire it into CI to
gate merges until every flagged usage is addressed.

## Audit your exposure first

If you'd rather stick with grep:

```bash
grep -rnE "BrandManifest|FormatCategory|DeliverTo|PromotedProducts|PromotedOfferings|PackageStatus|from adcp import Pricing|\.brand_manifest|adcp\.types\.generated_poc|(Audio|Css|Html|Image|Javascript|Text|Url|Video|Webhook)Asset\b" src/
```
Expand Down
61 changes: 52 additions & 9 deletions src/adcp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,27 +491,70 @@ def __getattr__(name: str) -> object:
raise AttributeError(f"module 'adcp' has no attribute {name!r}")


def get_adcp_version() -> str:
"""
Get the target AdCP specification version this SDK is built for.
def get_adcp_spec_version() -> str:
"""Get the AdCP specification version this SDK is built against.

Pinned at build time from the ``ADCP_VERSION`` file packaged with
the SDK. The version determines which AdCP schemas
(``adcp.types.generated_poc``) ship with this release.

Use this when you need to surface spec version to clients (agent
cards, capability responses, debug endpoints) or validate
cross-compatibility with a peer agent's advertised spec version.

This version determines which AdCP schemas are used for type generation
and validation. The SDK is designed to work with this specific version
of the AdCP specification.
For the SDK package version (``4.0.0b1``, ``4.1.2``, etc.), use
:func:`get_adcp_sdk_version` or the ``adcp.__version__`` attribute.

Returns:
AdCP specification version (e.g., "2.5.0")
AdCP specification version (e.g., ``"2.5.0"``, ``"latest"``).

Raises:
FileNotFoundError: If ADCP_VERSION file is missing from package
FileNotFoundError: If the packaged ``ADCP_VERSION`` file is
missing — typically an indicator of a corrupt install.
"""
from importlib.resources import files

# Read from ADCP_VERSION file in package
version_file = files("adcp") / "ADCP_VERSION"
return version_file.read_text().strip()


def get_adcp_sdk_version() -> str:
"""Get this SDK's package version (e.g., ``"4.0.0b1"``).

Prefer this function when pairing with :func:`get_adcp_spec_version`
— the symmetric function form makes call sites read unambiguously.
For a single-value import without the spec-vs-SDK context, use
:attr:`adcp.__version__` directly.

Returns:
SDK package version string. Falls back to ``"0.0.0+unknown"``
when running from an uninstalled source tree.
"""
return __version__


def get_adcp_version() -> str:
"""Return the AdCP *spec* version (legacy name).

.. deprecated:: 4.1
Kept for backwards compatibility with pre-4.1 callers. Prefer
:func:`get_adcp_spec_version` (spec version) or
:func:`get_adcp_sdk_version` / :attr:`adcp.__version__` (SDK
package version) — the split disambiguates what the caller
actually wants at the call site.
"""
import warnings

warnings.warn(
"get_adcp_version() is deprecated; use get_adcp_spec_version() "
"for the AdCP spec version or get_adcp_sdk_version() / "
"adcp.__version__ for the SDK package version.",
DeprecationWarning,
stacklevel=2,
)
return get_adcp_spec_version()


__all__ = [
# Version functions
"get_adcp_version",
Expand Down
23 changes: 23 additions & 0 deletions src/adcp/migrate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Migration tooling for the AdCP SDK.

Run via ``python -m adcp.migrate <migration> <path>``.

Migrations are one-shot code rewriters for spec major-version bumps.
They are *not* a runtime compatibility layer — the removed types are
gone. The migrations turn a 2-3 day sed hunt into an afternoon by
doing the mechanical renames automatically and reporting what the
seller still has to fix by hand.

Supported migrations:

* ``v3-to-v4`` — 3.x → 4.0 rename + removal report. Renames the 9
``<Type>Asset`` → ``<Type>Content`` classes and flags usages of
removed types (``BrandManifest``, ``DeliverTo``, ``Pricing``, etc.)
and of numbered ``Assets<N>`` direct imports that aren't stable.
"""

from __future__ import annotations

__all__ = ["v3_to_v4"]

from adcp.migrate import v3_to_v4
46 changes: 46 additions & 0 deletions src/adcp/migrate/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""CLI dispatcher: ``python -m adcp.migrate <migration> <path>``.

Usage::

python -m adcp.migrate v3-to-v4 ./src
python -m adcp.migrate v3-to-v4 ./src --apply
python -m adcp.migrate v3-to-v4 ./src --json

Each migration owns its own argparse surface (see e.g.
:func:`adcp.migrate.v3_to_v4.main`). This dispatcher just routes the
first positional argument.
"""

from __future__ import annotations

import sys


def main() -> int:
argv = sys.argv[1:]
if not argv or argv[0] in {"-h", "--help"}:
print(
"usage: python -m adcp.migrate <migration> <path> [options]\n"
"\n"
"Migrations:\n"
" v3-to-v4 Rewrite <Type>Asset → <Type>Content and flag\n"
" removed-type usages (BrandManifest, DeliverTo, etc).\n"
"\n"
"Run `python -m adcp.migrate <migration> --help` for per-migration options.\n",
file=sys.stderr,
)
return 0 if argv and argv[0] in {"-h", "--help"} else 2

migration = argv[0]
if migration == "v3-to-v4":
from adcp.migrate.v3_to_v4 import main as migrate_main

return migrate_main(argv[1:])

print(f"error: unknown migration {migration!r}", file=sys.stderr)
print("Known: v3-to-v4", file=sys.stderr)
return 2


if __name__ == "__main__":
sys.exit(main())
Loading
Loading