You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
types: ergonomics after the RootModel change (cached union validation, list roots, alias names) #1437
Three small type ergonomics we hit moving the Embedded Sales Agent from 8.0.0 to 9.0.0b1. docs/types-9-migration.md covers the semantics; these are about day-to-day use.
Validating a union root needs a hand-rolled cached TypeAdapter. The guide says to use TypeAdapter(X).validate_python(...) for unions such as WholesaleFeedEvent or VendorPricingOptionUnion. Building a TypeAdapter per call is expensive, so every adopter ends up writing the same functools.cache wrapper (we added validate_adcp_union(union, payload)). A public helper (for example adcp.types.validate_union(X, payload) with a cached adapter), or a module-level X_ADAPTER exported beside each union alias, would remove that.
List roots are still RootModel. Scalar roots became str/int subclasses, but list-valued roots still need .root. Two we hit: the delivery status_filter (RootModel[list[MediaBuyStatus]]) and the signal forecast point's dimensions. Code now mixes "read it directly" and "unwrap .root" depending on the root's JSON type. Converting list roots too (as list subclasses or plain list[...] aliases), or listing which roots stay RootModel in the types guide, would make the rule predictable. Related to codegen: a $ref into another file's properties generates a RootModel wrapper, so 27 of TargetingOverlayInput's 37 fields disagree with TargetingOverlay #1362.
Union alias naming is inconsistent between import paths.adcp.types exports VendorPricingOptionUnion, while the generated module calls the same union VendorPricingOption, and adcp.types has no VendorPricingOption. Pick one name, or export both.
dx-expert: All three items are real; item 3 is the highest-return fix (one line, live broken import); item 1 removes a recurring support tax; item 2's list-root conversion is a genuine ergonomics regression but needs design work.
code-reviewer: Items 1 and 3 are non-breaking and touch no generated code; item 2's docs-only path is also non-breaking; the list-root conversion path is breaking and requires codegen template changes across 30+ files.
My take: Items 1 and 3, plus a migration-guide update for item 2, are all ready to implement together in one PR. The list-root conversion (item 2, breaking path) should target a future breaking release alongside #1362.
Implementation brief:
Item 3 — alias gap (bug, 3 lines): In src/adcp/types/aliases.py line 156, add VendorPricingOption = VendorPricingOptionUnion; ensure _eager.py re-exports it; add "VendorPricingOption" to __all__ in __init__.py. The generated module already defines it; this is an omitted re-export.
Item 1 — cached adapter: Add validate_union(T, payload) (or adcp.types.coerce) backed by functools.lru_cache on a TypeAdapter factory. Precedent: base.py's deferred_adapter. Expose from adcp.types. No generated-code changes.
Required checks: pytest, mypy src/, ruff check ., black --check .; snapshot test in tests/fixtures/public_api_snapshot.json must be updated for new export.
Activity
bokelley commentedon Oct 7, 2026
Triage
Classification: Enhancement / Bug (item 3)
Bucket(s): docs, enhancement
Status: ready-to-implement
What the experts said:
My take: Items 1 and 3, plus a migration-guide update for item 2, are all ready to implement together in one PR. The list-root conversion (item 2, breaking path) should target a future breaking release alongside #1362.
Implementation brief:
src/adcp/types/aliases.pyline 156, addVendorPricingOption = VendorPricingOptionUnion; ensure_eager.pyre-exports it; add"VendorPricingOption"to__all__in__init__.py. The generated module already defines it; this is an omitted re-export.validate_union(T, payload)(oradcp.types.coerce) backed byfunctools.lru_cacheon aTypeAdapterfactory. Precedent:base.py'sdeferred_adapter. Expose fromadcp.types. No generated-code changes.docs/types-9-migration.mdlisting the 21 remainingRootModel[list[...]]types (e.g.StatusFilter,ForecastPointDimensions,ChangedFields) and stating that the list-root conversion is deferred to the next breaking release. Reference codegen: a$refinto another file'spropertiesgenerates aRootModelwrapper, so 27 ofTargetingOverlayInput's 37 fields disagree withTargetingOverlay#1362.$refinto another file'spropertiesgenerates aRootModelwrapper, so 27 ofTargetingOverlayInput's 37 fields disagree withTargetingOverlay#1362.pytest,mypy src/,ruff check .,black --check .; snapshot test intests/fixtures/public_api_snapshot.jsonmust be updated for new export.Triaged by Claude Code. Session: https://claude.ai/code/session_0195DYZXWYo6HunQnQ6z2t3k
Generated by Claude Code