Skip to content

Commit 6f8f8e8

Browse files
bokelleyclaude
andcommitted
fix(testing): update webhook type-check for typed McpWebhookPayload return
create_mcp_webhook_payload was changed in #632 to return McpWebhookPayload (typed Pydantic model) instead of dict[str, Any]. The type-check test still demonstrated the dict + cast() pattern, which no longer typechecks. Update to demonstrate the new zero-ignore adopter pattern: typed attribute access (payload.task_id) for reads, to_wire_dict(payload) for HTTP serialization. Use TaskType.create_media_buy (a real async task type — get_products is sync-only and not in the TaskType enum). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5e300a2 commit 6f8f8e8

1 file changed

Lines changed: 22 additions & 17 deletions

File tree

tests/type_checks/webhook_payload_construction.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,44 @@
1-
"""Adopter pattern: create_mcp_webhook_payload usage with cast() for field access.
1+
"""Adopter pattern: create_mcp_webhook_payload usage with typed attribute access.
22
3-
create_mcp_webhook_payload returns dict[str, Any]. The zero-ignore pattern
4-
for extracting typed values is cast() — explicit, visible, and does not
5-
require # type: ignore.
3+
create_mcp_webhook_payload returns a typed McpWebhookPayload Pydantic model.
4+
The zero-ignore adopter pattern is direct attribute access for typed reads
5+
and to_wire_dict() for HTTP serialization — no cast() needed.
66
"""
7+
78
from __future__ import annotations
89

910
import json
10-
from typing import Any, cast
11+
from typing import Any
1112

12-
from adcp.types import GeneratedTaskStatus
13-
from adcp.webhooks import create_mcp_webhook_payload
13+
from adcp.types import GeneratedTaskStatus, McpWebhookPayload, TaskType
14+
from adcp.webhooks import create_mcp_webhook_payload, to_wire_dict
1415

1516

16-
def build_completed_payload(task_id: str, products: list[dict[str, Any]]) -> dict[str, Any]:
17+
def build_completed_payload(task_id: str, media_buy_id: str) -> McpWebhookPayload:
1718
return create_mcp_webhook_payload(
1819
task_id=task_id,
19-
task_type="get_products",
20+
task_type=TaskType.create_media_buy,
2021
status=GeneratedTaskStatus.completed,
21-
result={"products": products},
22-
message=f"Found {len(products)} products",
22+
result={"media_buy_id": media_buy_id, "status": "active"},
23+
message=f"Media buy {media_buy_id} activated",
2324
)
2425

2526

26-
def extract_task_id(payload: dict[str, Any]) -> str:
27-
return cast(str, payload["task_id"])
27+
def extract_task_id(payload: McpWebhookPayload) -> str:
28+
return payload.task_id
29+
30+
31+
def extract_status(payload: McpWebhookPayload) -> str:
32+
return payload.status
2833

2934

30-
def extract_status(payload: dict[str, Any]) -> str:
31-
return cast(str, payload["status"])
35+
def serialize_for_http(payload: McpWebhookPayload) -> dict[str, Any]:
36+
return to_wire_dict(payload)
3237

3338

34-
payload = build_completed_payload("task_123", [{"product_id": "p1"}])
39+
payload = build_completed_payload("task_123", "mb_abc")
3540

36-
serialized = json.dumps(payload)
41+
serialized = json.dumps(serialize_for_http(payload))
3742
assert isinstance(serialized, str)
3843

3944
task_id = extract_task_id(payload)

0 commit comments

Comments
 (0)