Skip to content

feat(migrate+types): v3->v4 codemod, strict-validation flag, version helpers, subclass test#247

Merged
bokelley merged 2 commits intomainfrom
bokelley/migrate-strict-versions
Apr 20, 2026
Merged

feat(migrate+types): v3->v4 codemod, strict-validation flag, version helpers, subclass test#247
bokelley merged 2 commits intomainfrom
bokelley/migrate-strict-versions

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Summary

Third of three PRs on salesagent's feedback. Closes the final 4 items. All additive — no breaking changes.

Item What
#5 python -m adcp.migrate v3-to-v4 — new CLI that rewrites the 9 <Type>Asset → <Type>Content renames and flags usages of removed types (BrandManifest, DeliverTo, Pricing, etc.) + numbered Assets<N> imports + adcp.types.generated_poc imports. Dry-run default, --apply rewrites in place, --json for CI. Exit 1 on flagged findings. No new runtime deps.
#6 ADCP_STRICT_VALIDATION=1 env flag on AdCPBaseModel. Flips extra='forbid' at import time; default stays 'ignore' for forward-compat. Use during spec upgrades to surface silently-dropped renamed fields.
#11 get_adcp_spec_version() + get_adcp_sdk_version() split the ambiguous get_adcp_version() into two named helpers. Old name kept as a spec-version alias.
#4 Subclass passthrough test locks the exclude=True contract through products_response / signals_response / media_buys_response / list_creatives_response so a future _serialize refactor can't silently leak seller internals.

Tested

  • +49 new tests across 4 files:
    • tests/test_migrate_v3_to_v4.py (20): renames, word boundaries, removed-type anchors, numbered-Assets flagging, skip-dirs, CLI exit codes, JSON output, apply-rewrites-and-reports, unreadable-file graceful skip.
    • tests/test_response_builder_subclass.py (5): 4 builders × subclass passthrough + mixed-base-and-subclass.
    • tests/test_strict_validation_env.py (17): all truthy/falsy variants, whitespace handling, unset default, model_config wiring.
    • tests/test_version_helpers.py (4): sdk-matches-dunder, spec non-empty, legacy alias, distinct concepts.
  • Full suite: 2001 passed, 22 skipped locally (1937 → 2001).
  • ruff, mypy clean across 676 source files.

Test plan

  • CI green across Python 3.10–3.13
  • Review: does the migrate CLI's regex + word-boundary approach suffice, or should it use libcst/ast for safer AST-level rewrites? (Tradeoff: new dep vs. false-positive risk — current approach has tests showing MyAudioAsset / AudioAssetExtra stay untouched.)
  • Review: should get_adcp_version emit a DeprecationWarning when called, or is a docstring .. deprecated:: note enough? Current impl is silent-alias to avoid breaking pre-4.1 callers.
  • Review: is ADCP_STRICT_VALIDATION resolved at import time the right policy, or should it be per-model / per-call? Import-time is simpler; per-model adds flexibility at the cost of surprising runtime behavior.

Related

Part of triaging feedback from salesagent (primary downstream of adcp.server).

All 11 feedback items now addressed.

🤖 Generated with Claude Code

bokelley and others added 2 commits April 20, 2026 15:55
…helpers, subclass test

Closes the final 4 items from salesagent feedback (#4, #5, #6, #11).

- python -m adcp.migrate v3-to-v4: new CLI/subpackage. 9 Asset->Content
  renames with word-boundary regex; flags BrandManifest/DeliverTo/
  Pricing/PromotedProducts/PromotedOfferings/FormatCategory/
  PackageStatus, numbered Assets<N> imports, and adcp.types.
  generated_poc imports. Dry-run default; --apply rewrites in place;
  --json for CI; exit 1 on flagged findings.

- ADCP_STRICT_VALIDATION env flag on AdCPBaseModel. Truthy values
  (1/true/yes/on) flip extra='forbid'; default stays 'ignore' for
  forward-compat.

- get_adcp_spec_version() + get_adcp_sdk_version() split the ambiguous
  get_adcp_version() helper. Old name kept as an alias.

- Subclass passthrough test: locks the exclude=True contract through
  products_response / signals_response / media_buys_response /
  list_creatives_response against refactors of _serialize.

+49 tests, 2001 passing (1937 -> 2001), mypy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- migrate/v3_to_v4.py: skip-dirs applied relative to root (repos
  under CI ancestors like /home/ci/build/repo no longer silently skip).
- migrate/v3_to_v4.py: .brand_manifest uses word-boundary regex
  instead of substring (no false-positive on .brand_manifest_v2 etc.).
- migrate/v3_to_v4.py: reads with utf-8-sig + newline="" and writes
  with newline="" — CRLF preserved, UTF-8 BOM files migrate
  correctly. Uses open() (not Path.read_text(newline=) — that kwarg
  is 3.13+).
- migrate/v3_to_v4.py: docstring calls out the regex-vs-AST tradeoff
  (string literals and comments rewrite too).

- adcp/__init__.py: get_adcp_version() now emits DeprecationWarning.
- adcp/__init__.py: tightened get_adcp_sdk_version() docstring.

- types/base.py: explicit warning that ADCP_STRICT_VALIDATION is
  resolved once at module import time.

+7 tests. 2008 passing (2001 → 2008), mypy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley merged commit 0f50d39 into main Apr 20, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant