Skip to content

Commit 5bbc719

Browse files
bokelleyclaude
andcommitted
fix: resolve all mypy type checking errors
- Add missing type definitions (FormatId, PackageRequest, etc.) as type aliases in generated.py - Add type annotations to A2AAdapter.__init__ - Add proper imports to tasks.py from generated.py - Add type casts for json.load/json.loads to satisfy mypy no-any-return checks - Update generator to include missing schema type aliases Fixes all 67 mypy errors across the codebase. All 15 source files now pass type checking. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 8f8a2c7 commit 5bbc719

File tree

6 files changed

+131
-22
lines changed

6 files changed

+131
-22
lines changed

scripts/generate_models_simple.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ def generate_model_for_schema(schema_file: Path) -> str:
7373

7474
# Start with model name
7575
model_name = snake_to_pascal(schema_file.stem)
76+
77+
# Check if this is a simple type alias (enum or primitive type without properties)
78+
if "properties" not in schema:
79+
# This is a type alias, not a model class
80+
python_type = get_python_type(schema)
81+
lines = [f"# Type alias for {schema.get('title', model_name)}"]
82+
if "description" in schema:
83+
desc = escape_string_for_python(schema["description"])
84+
lines.append(f'# {desc}')
85+
lines.append(f"{model_name} = {python_type}")
86+
return "\n".join(lines)
87+
88+
# Regular BaseModel class
7689
lines = [f"class {model_name}(BaseModel):"]
7790

7891
# Add description if available
@@ -85,7 +98,7 @@ def generate_model_for_schema(schema_file: Path) -> str:
8598
lines.append("")
8699

87100
# Add properties
88-
if "properties" not in schema or not schema["properties"]:
101+
if not schema["properties"]:
89102
lines.append(" pass")
90103
return "\n".join(lines)
91104

@@ -244,6 +257,17 @@ def main():
244257
"protocol-envelope.json",
245258
"response.json",
246259
"promoted-products.json",
260+
# Enum types (need type aliases)
261+
"channels.json",
262+
"delivery-type.json",
263+
"pacing.json",
264+
"package-status.json",
265+
"media-buy-status.json",
266+
"task-type.json",
267+
"task-status.json",
268+
"pricing-model.json",
269+
"pricing-option.json",
270+
"standard-format-ids.json",
247271
]
248272

249273
# Find all schemas
@@ -276,6 +300,18 @@ def main():
276300
"",
277301
"",
278302
"# ============================================================================",
303+
"# MISSING SCHEMA TYPES (referenced but not provided by upstream)",
304+
"# ============================================================================",
305+
"",
306+
"# These types are referenced in schemas but don't have schema files",
307+
"# Defining them as type aliases to maintain type safety",
308+
"FormatId = str",
309+
"PackageRequest = dict[str, Any]",
310+
"PushNotificationConfig = dict[str, Any]",
311+
"ReportingCapabilities = dict[str, Any]",
312+
"",
313+
"",
314+
"# ============================================================================",
279315
"# CORE DOMAIN TYPES",
280316
"# ============================================================================",
281317
"",

src/adcp/__main__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import json
99
import sys
1010
from pathlib import Path
11-
from typing import Any
11+
from typing import Any, cast
1212

1313
from adcp.client import ADCPClient
1414
from adcp.config import (
@@ -83,7 +83,7 @@ def load_payload(payload_arg: str | None) -> dict[str, Any]:
8383
# Try to read from stdin if available and has data
8484
if not sys.stdin.isatty():
8585
try:
86-
return json.load(sys.stdin)
86+
return cast(dict[str, Any], json.load(sys.stdin))
8787
except (json.JSONDecodeError, ValueError):
8888
pass
8989
return {}
@@ -94,11 +94,11 @@ def load_payload(payload_arg: str | None) -> dict[str, Any]:
9494
if not file_path.exists():
9595
print(f"Error: File not found: {file_path}", file=sys.stderr)
9696
sys.exit(1)
97-
return json.loads(file_path.read_text())
97+
return cast(dict[str, Any], json.loads(file_path.read_text()))
9898

9999
# Parse as JSON
100100
try:
101-
return json.loads(payload_arg)
101+
return cast(dict[str, Any], json.loads(payload_arg))
102102
except json.JSONDecodeError as e:
103103
print(f"Error: Invalid JSON payload: {e}", file=sys.stderr)
104104
sys.exit(1)
@@ -171,7 +171,7 @@ def resolve_agent_config(agent_identifier: str) -> dict[str, Any]:
171171
# Check if it's a JSON config
172172
if agent_identifier.startswith("{"):
173173
try:
174-
return json.loads(agent_identifier)
174+
return cast(dict[str, Any], json.loads(agent_identifier))
175175
except json.JSONDecodeError:
176176
pass
177177

src/adcp/config.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import json
66
from pathlib import Path
7-
from typing import Any
7+
from typing import Any, cast
88

99
CONFIG_DIR = Path.home() / ".adcp"
1010
CONFIG_FILE = CONFIG_DIR / "config.json"
@@ -21,7 +21,7 @@ def load_config() -> dict[str, Any]:
2121
return {"agents": {}}
2222

2323
with open(CONFIG_FILE) as f:
24-
return json.load(f)
24+
return cast(dict[str, Any], json.load(f))
2525

2626

2727
def save_config(config: dict[str, Any]) -> None:
@@ -60,13 +60,14 @@ def save_agent(
6060
def get_agent(alias: str) -> dict[str, Any] | None:
6161
"""Get agent configuration by alias."""
6262
config = load_config()
63-
return config.get("agents", {}).get(alias)
63+
result = config.get("agents", {}).get(alias)
64+
return cast(dict[str, Any], result) if result is not None else None
6465

6566

6667
def list_agents() -> dict[str, Any]:
6768
"""List all saved agents."""
6869
config = load_config()
69-
return config.get("agents", {})
70+
return cast(dict[str, Any], config.get("agents", {}))
7071

7172

7273
def remove_agent(alias: str) -> bool:

src/adcp/protocols/a2a.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
ADCPTimeoutError,
2020
)
2121
from adcp.protocols.base import ProtocolAdapter
22-
from adcp.types.core import DebugInfo, TaskResult, TaskStatus
22+
from adcp.types.core import AgentConfig, DebugInfo, TaskResult, TaskStatus
2323

2424
logger = logging.getLogger(__name__)
2525

2626

2727
class A2AAdapter(ProtocolAdapter):
2828
"""Adapter for A2A protocol following the Agent2Agent specification."""
2929

30-
def __init__(self, agent_config):
30+
def __init__(self, agent_config: AgentConfig):
3131
"""Initialize A2A adapter with reusable HTTP client."""
3232
super().__init__(agent_config)
3333
self._client: httpx.AsyncClient | None = None

src/adcp/types/generated.py

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@
1616
from pydantic import BaseModel, Field
1717

1818

19+
# ============================================================================
20+
# MISSING SCHEMA TYPES (referenced but not provided by upstream)
21+
# ============================================================================
22+
23+
# These types are referenced in schemas but don't have schema files
24+
# Defining them as type aliases to maintain type safety
25+
FormatId = str
26+
PackageRequest = dict[str, Any]
27+
PushNotificationConfig = dict[str, Any]
28+
ReportingCapabilities = dict[str, Any]
29+
30+
1931
# ============================================================================
2032
# CORE DOMAIN TYPES
2133
# ============================================================================
@@ -111,10 +123,9 @@ class BrandManifest(BaseModel):
111123
metadata: dict[str, Any] | None = Field(None, description="Additional brand metadata")
112124

113125

114-
class BrandManifestRef(BaseModel):
115-
"""Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest"""
116-
117-
pass
126+
# Type alias for Brand Manifest Reference
127+
# Brand manifest provided either as an inline object or a URL string pointing to a hosted manifest
128+
BrandManifestRef = Any
118129

119130

120131
class Format(BaseModel):
@@ -240,10 +251,9 @@ class PerformanceFeedback(BaseModel):
240251
applied_at: str | None = Field(None, description="ISO 8601 timestamp when feedback was applied to optimization algorithms")
241252

242253

243-
class StartTiming(BaseModel):
244-
"""Campaign start timing: 'asap' or ISO 8601 date-time"""
245-
246-
pass
254+
# Type alias for Start Timing
255+
# Campaign start timing: 'asap' or ISO 8601 date-time
256+
StartTiming = Any
247257

248258

249259
class SubAsset(BaseModel):
@@ -300,6 +310,56 @@ class PromotedProducts(BaseModel):
300310
manifest_query: str | None = Field(None, description="Natural language query to select products from the brand manifest (e.g., 'all Kraft Heinz pasta sauces', 'organic products under $20')")
301311

302312

313+
# Type alias for Advertising Channels
314+
# Standard advertising channels supported by AdCP
315+
Channels = Literal["display", "video", "audio", "native", "dooh", "ctv", "podcast", "retail", "social"]
316+
317+
318+
# Type alias for Delivery Type
319+
# Type of inventory delivery
320+
DeliveryType = Literal["guaranteed", "non_guaranteed"]
321+
322+
323+
# Type alias for Pacing
324+
# Budget pacing strategy
325+
Pacing = Literal["even", "asap", "front_loaded"]
326+
327+
328+
# Type alias for Package Status
329+
# Status of a package
330+
PackageStatus = Literal["draft", "active", "paused", "completed"]
331+
332+
333+
# Type alias for Media Buy Status
334+
# Status of a media buy
335+
MediaBuyStatus = Literal["pending_activation", "active", "paused", "completed"]
336+
337+
338+
# Type alias for Task Type
339+
# Valid AdCP task types across all domains. These represent the complete set of operations that can be tracked via the task management system.
340+
TaskType = Literal["create_media_buy", "update_media_buy", "sync_creatives", "activate_signal", "get_signals"]
341+
342+
343+
# Type alias for Task Status
344+
# Standardized task status values based on A2A TaskState enum. Indicates the current state of any AdCP operation.
345+
TaskStatus = Literal["submitted", "working", "input-required", "completed", "canceled", "failed", "rejected", "auth-required", "unknown"]
346+
347+
348+
# Type alias for Pricing Model
349+
# Supported pricing models for advertising products
350+
PricingModel = Literal["cpm", "vcpm", "cpc", "cpcv", "cpv", "cpp", "flat_rate"]
351+
352+
353+
# Type alias for Pricing Option
354+
# A pricing model option offered by a publisher for a product. Each pricing model has its own schema with model-specific requirements.
355+
PricingOption = Any
356+
357+
358+
# Type alias for Standard Format IDs
359+
# Enumeration of all standard creative format identifiers in AdCP
360+
StandardFormatIds = Literal["display_300x250", "display_728x90", "display_320x50", "display_160x600", "display_970x250", "display_336x280", "display_expandable_300x250", "display_expandable_728x90", "display_interstitial_320x480", "display_interstitial_desktop", "display_dynamic_300x250", "display_responsive", "native_in_feed", "native_content_recommendation", "native_product", "video_skippable_15s", "video_skippable_30s", "video_non_skippable_15s", "video_non_skippable_30s", "video_outstream_autoplay", "video_vertical_story", "video_rewarded_30s", "video_pause_ad", "video_ctv_non_skippable_30s", "audio_standard_15s", "audio_standard_30s", "audio_podcast_host_read", "audio_programmatic", "universal_carousel", "universal_canvas", "universal_takeover", "universal_gallery", "universal_reveal", "dooh_landscape_static", "dooh_portrait_video"]
361+
362+
303363

304364
# ============================================================================
305365
# TASK REQUEST/RESPONSE TYPES

src/adcp/types/tasks.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,20 @@
1515

1616
from pydantic import BaseModel, Field
1717

18-
# Import core types from adcp.types.core
19-
# (Product, MediaBuy, CreativeAsset, etc.)
18+
# Import all types from generated module
19+
from adcp.types.generated import (
20+
BrandManifestRef,
21+
Channels,
22+
CreativeAsset,
23+
CreativeManifest,
24+
Error,
25+
Format,
26+
FormatId,
27+
PackageRequest,
28+
Product,
29+
PushNotificationConfig,
30+
StartTiming,
31+
)
2032

2133

2234
class ActivateSignalRequest(BaseModel):

0 commit comments

Comments
 (0)