Skip to content

Commit c845a76

Browse files
committed
Merge remote-tracking branch 'origin/main' into pdoc-api-docs
2 parents 317580b + 574ec90 commit c845a76

File tree

138 files changed

+2338
-1322
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+2338
-1322
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,13 @@ jobs:
118118
- name: Validate generated code syntax
119119
run: |
120120
echo "Validating generated code can be parsed..."
121-
python -m py_compile src/adcp/types/generated.py
121+
python -m py_compile src/adcp/types/_generated.py
122122
echo "✓ Syntax validation passed"
123123
124124
- name: Validate generated code imports
125125
run: |
126126
echo "Validating generated code can be imported..."
127-
python -c "from adcp.types import generated; print(f'✓ Successfully imported {len(dir(generated))} symbols')"
127+
python -c "from adcp.types import _generated as generated; print(f'✓ Successfully imported {len(dir(generated))} symbols')"
128128
129129
- name: Run code generation tests
130130
run: |
@@ -133,11 +133,14 @@ jobs:
133133
134134
- name: Check for schema drift
135135
run: |
136-
if git diff --exit-code src/adcp/types/generated.py schemas/cache/; then
137-
echo "✓ Schemas are up-to-date"
138-
else
139-
echo "✗ Schemas are out of date!"
140-
echo "Run: make regenerate-schemas"
141-
git diff src/adcp/types/generated.py
142-
exit 1
136+
# Check if only generation timestamp changed (expected when CI regenerates)
137+
if git diff --exit-code src/adcp/types/_generated.py schemas/cache/ | grep -v "^[-+]Generation date:"; then
138+
# Real changes detected (not just timestamp)
139+
if git diff src/adcp/types/_generated.py | grep -v "^[-+]Generation date:" | grep "^[-+]" | grep -v "^[-+][-+][-+]" | grep -v "^[-+]@@" > /dev/null; then
140+
echo "✗ Schemas are out of date!"
141+
echo "Run: make regenerate-schemas"
142+
git diff src/adcp/types/_generated.py
143+
exit 1
144+
fi
143145
fi
146+
echo "✓ Schemas are up-to-date"

CLAUDE.md

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,32 @@ FormatId = str
1717
PackageRequest = dict[str, Any]
1818
```
1919

20+
**Stable Public API Layer**
21+
22+
**CRITICAL**: The `generated_poc` directory is internal implementation. **Never import directly from it**.
23+
24+
Generated types in `src/adcp/types/generated_poc/` may have:
25+
- Numbered suffixes (e.g., `BrandManifest1`, `BrandManifest2`) due to schema evolution
26+
- Structural changes between minor versions
27+
- Files added/removed as schemas evolve
28+
29+
**Always use the stable API:**
30+
```python
31+
# ✅ CORRECT - Stable public API
32+
from adcp.types import BrandManifest, Product, CpmFixedRatePricingOption
33+
from adcp.types.stable import BrandManifest, Product
34+
35+
# ❌ WRONG - Internal generated types (will break)
36+
from adcp.types.generated_poc.brand_manifest import BrandManifest1
37+
from adcp.types._generated import BrandManifest1
38+
```
39+
40+
The stable API (`src/adcp/types/stable.py`) provides:
41+
1. **Clean names** - `BrandManifest` not `BrandManifest1`
42+
2. **Stability** - Aliases are updated when schemas evolve
43+
3. **Versioning** - Breaking changes require major version bumps
44+
4. **Deprecation warnings** - Direct `generated_poc` imports trigger warnings
45+
2046
**NEVER Modify Generated Files Directly**
2147

2248
Files in `src/adcp/types/generated_poc/` and `src/adcp/types/generated.py` are auto-generated by `scripts/generate_types.py`. Any manual edits will be lost on regeneration.
@@ -27,6 +53,14 @@ Files in `src/adcp/types/generated_poc/` and `src/adcp/types/generated.py` are a
2753

2854
We use `scripts/post_generate_fixes.py` which runs automatically after type generation to apply necessary modifications that can't be generated.
2955

56+
**Preventing Stale Files:**
57+
58+
The generation script (`scripts/generate_types.py`) **deletes the entire output directory** before regenerating types. This prevents stale files from persisting when schemas are renamed or removed. Without this, old generated files could remain checked in indefinitely, causing import errors and confusion about which types are actually current.
59+
60+
**Avoiding Noisy Commits:**
61+
62+
After generation, the script automatically restores files where only the timestamp changed (e.g., `# timestamp: 2025-11-18T03:32:03+00:00`). This prevents commits with 100+ file changes where the only difference is the generation timestamp, making actual changes easier to review.
63+
3064
**Type Name Collisions:**
3165

3266
The upstream AdCP schemas define multiple types with the same name (e.g., `Contact`, `Asset`, `Status`) in different schema files. These are **genuinely different types** with different fields, not duplicates.
@@ -35,7 +69,7 @@ When consolidating exports in `generated.py`, we use a "first wins" strategy (al
3569

3670
```python
3771
# Access the "winning" version
38-
from adcp.types.generated import Asset
72+
from adcp.types._generated import Asset
3973

4074
# Access specific versions
4175
from adcp.types.generated_poc.brand_manifest import Asset as BrandAsset
@@ -48,17 +82,24 @@ from adcp.types.generated_poc.format import Asset as FormatAsset
4882
- Using discriminated unions where appropriate
4983

5084
**Current fixes applied:**
51-
1. **Model validators** - Injects `@model_validator` decorators into:
52-
- `PublisherProperty.validate_mutual_exclusivity()` - enforces property_ids/property_tags mutual exclusivity
53-
- `Product.validate_publisher_properties_items()` - validates all publisher_properties items
5485

55-
2. **Self-referential types** - Fixes `preview_render.py` if it contains module-qualified self-references
86+
1. **Self-referential types** - Fixes `preview_render.py` if it contains module-qualified self-references
5687

57-
3. **Forward references** - Fixes BrandManifest imports in:
88+
2. **Forward references** - Fixes BrandManifest imports in:
5889
- `promoted_offerings.py`
5990
- `create_media_buy_request.py`
6091
- `get_products_request.py`
6192

93+
3. **~~Publisher properties validation~~ (DEPRECATED)** - After PR #213 added explicit discriminator to `publisher_properties` schema, Pydantic now generates proper discriminated union variants (`PublisherProperties`, `PublisherProperties4`, `PublisherProperties5`) with automatic validation. Manual validator injection is no longer needed.
94+
95+
**Note on Pricing Options:**
96+
97+
The code generator creates individual files for each pricing option (e.g., `cpm_fixed_option.py`, `cpm_auction_option.py`) with the `is_fixed` discriminator field already included:
98+
- Fixed-rate options: `is_fixed: Annotated[Literal[True], ...]`
99+
- Auction options: `is_fixed: Annotated[Literal[False], ...]`
100+
101+
These are used via union types in `Product.pricing_options`. No post-generation fix is needed for pricing options.
102+
62103
**To add new post-generation fixes:**
63104
Edit `scripts/post_generate_fixes.py` and add a new function. The script:
64105
- Runs automatically via `generate_types.py`
@@ -79,7 +120,7 @@ Edit `scripts/post_generate_fixes.py` and add a new function. The script:
79120
3. **Create semantic aliases in `aliases.py`**:
80121
```python
81122
# Import the generated types
82-
from adcp.types.generated import PreviewRender1, PreviewRender2, PreviewRender3
123+
from adcp.types._generated import PreviewRender1, PreviewRender2, PreviewRender3
83124

84125
# Create semantic aliases based on discriminator values
85126
UrlPreviewRender = PreviewRender1 # output_format='url'

README.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,16 @@ client = ADCPClient(config)
219219

220220
### Type Safety
221221

222-
Full type hints with Pydantic validation and auto-generated types from the AdCP spec:
222+
Full type hints with Pydantic validation and auto-generated types from the AdCP spec. All commonly-used types are exported from the main `adcp` package for convenience:
223223

224224
```python
225-
from adcp import GetProductsRequest
225+
from adcp import (
226+
GetProductsRequest,
227+
BrandManifest,
228+
Package,
229+
CpmFixedRatePricingOption,
230+
MediaBuyStatus,
231+
)
226232

227233
# All methods require typed request objects
228234
request = GetProductsRequest(brief="Coffee brands", max_results=10)
@@ -232,8 +238,27 @@ result = await agent.get_products(request)
232238
if result.success:
233239
for product in result.data.products:
234240
print(product.name, product.pricing_options) # Full IDE autocomplete!
241+
242+
# Type-safe pricing with discriminators
243+
pricing = CpmFixedRatePricingOption(
244+
pricing_option_id="cpm_usd",
245+
pricing_model="cpm",
246+
is_fixed=True, # Literal[True] - type checked!
247+
currency="USD",
248+
rate=5.0
249+
)
250+
251+
# Type-safe status enums
252+
if media_buy.status == MediaBuyStatus.active:
253+
print("Media buy is active")
235254
```
236255

256+
**Exported from main package:**
257+
- **Core domain types**: `BrandManifest`, `Creative`, `CreativeManifest`, `MediaBuy`, `Package`
258+
- **Status enums**: `CreativeStatus`, `MediaBuyStatus`, `PackageStatus`, `PricingModel`
259+
- **All 9 pricing options**: `CpcPricingOption`, `CpmFixedRatePricingOption`, `VcpmAuctionPricingOption`, etc.
260+
- **Request/Response types**: All 16 operations with full request/response types
261+
237262
#### Semantic Type Aliases
238263

239264
For discriminated union types (success/error responses), use semantic aliases for clearer code:
@@ -264,7 +289,7 @@ See `examples/type_aliases_demo.py` for more examples.
264289
**Import guidelines:**
265290
-**DO**: Import from main package: `from adcp import GetProductsRequest`
266291
-**DO**: Use semantic aliases: `from adcp import CreateMediaBuySuccessResponse`
267-
- ⚠️ **AVOID**: Import from internal modules: `from adcp.types.generated import CreateMediaBuyResponse1`
292+
- ⚠️ **AVOID**: Import from internal modules: `from adcp.types._generated import CreateMediaBuyResponse1`
268293

269294
The main package exports provide a stable API while internal generated types may change.
270295

0 commit comments

Comments
 (0)