adcp 2.12.2__py3-none-any.whl → 2.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
adcp/__init__.py CHANGED
@@ -179,7 +179,7 @@ from adcp.validation import (
179
179
  validate_publisher_properties_item,
180
180
  )
181
181
 
182
- __version__ = "2.12.2"
182
+ __version__ = "2.13.0"
183
183
 
184
184
 
185
185
  def get_adcp_version() -> str:
adcp/types/base.py CHANGED
@@ -2,10 +2,189 @@ from __future__ import annotations
2
2
 
3
3
  """Base model for AdCP types with spec-compliant serialization."""
4
4
 
5
+ from collections.abc import Callable
5
6
  from typing import Any
6
7
 
7
8
  from pydantic import BaseModel
8
9
 
10
+ # Type alias to shorten long type annotations
11
+ MessageFormatter = Callable[[Any], str]
12
+
13
+
14
+ def _pluralize(count: int, singular: str, plural: str | None = None) -> str:
15
+ """Return singular or plural form based on count."""
16
+ if count == 1:
17
+ return singular
18
+ return plural if plural else f"{singular}s"
19
+
20
+
21
+ # Registry of human-readable message formatters for response types.
22
+ # Key is the class name, value is a callable that takes the instance and returns a message.
23
+ _RESPONSE_MESSAGE_REGISTRY: dict[str, MessageFormatter] = {}
24
+
25
+
26
+ def _register_response_message(cls_name: str) -> Callable[[MessageFormatter], MessageFormatter]:
27
+ """Decorator to register a message formatter for a response type."""
28
+
29
+ def decorator(func: MessageFormatter) -> MessageFormatter:
30
+ _RESPONSE_MESSAGE_REGISTRY[cls_name] = func
31
+ return func
32
+
33
+ return decorator
34
+
35
+
36
+ # Response message formatters
37
+ @_register_response_message("GetProductsResponse")
38
+ def _get_products_message(self: Any) -> str:
39
+ products = getattr(self, "products", None)
40
+ if products is None or len(products) == 0:
41
+ return "No products matched your requirements."
42
+ count = len(products)
43
+ return f"Found {count} {_pluralize(count, 'product')} matching your requirements."
44
+
45
+
46
+ @_register_response_message("ListCreativeFormatsResponse")
47
+ def _list_creative_formats_message(self: Any) -> str:
48
+ formats = getattr(self, "formats", None)
49
+ if formats is None:
50
+ return "No creative formats found."
51
+ count = len(formats)
52
+ return f"Found {count} supported creative {_pluralize(count, 'format')}."
53
+
54
+
55
+ @_register_response_message("GetSignalsResponse")
56
+ def _get_signals_message(self: Any) -> str:
57
+ signals = getattr(self, "signals", None)
58
+ if signals is None:
59
+ return "No signals found."
60
+ count = len(signals)
61
+ return f"Found {count} {_pluralize(count, 'signal')} available for targeting."
62
+
63
+
64
+ @_register_response_message("ListAuthorizedPropertiesResponse")
65
+ def _list_authorized_properties_message(self: Any) -> str:
66
+ domains = getattr(self, "publisher_domains", None)
67
+ if domains is None:
68
+ return "No authorized properties found."
69
+ count = len(domains)
70
+ return f"Authorized to represent {count} publisher {_pluralize(count, 'domain')}."
71
+
72
+
73
+ @_register_response_message("ListCreativesResponse")
74
+ def _list_creatives_message(self: Any) -> str:
75
+ creatives = getattr(self, "creatives", None)
76
+ if creatives is None:
77
+ return "No creatives found."
78
+ count = len(creatives)
79
+ return f"Found {count} {_pluralize(count, 'creative')} in the system."
80
+
81
+
82
+ @_register_response_message("CreateMediaBuyResponse1")
83
+ def _create_media_buy_success_message(self: Any) -> str:
84
+ media_buy_id = getattr(self, "media_buy_id", None)
85
+ packages = getattr(self, "packages", None)
86
+ package_count = len(packages) if packages else 0
87
+ return (
88
+ f"Media buy {media_buy_id} created with "
89
+ f"{package_count} {_pluralize(package_count, 'package')}."
90
+ )
91
+
92
+
93
+ @_register_response_message("CreateMediaBuyResponse2")
94
+ def _create_media_buy_error_message(self: Any) -> str:
95
+ errors = getattr(self, "errors", None)
96
+ error_count = len(errors) if errors else 0
97
+ return f"Media buy creation failed with {error_count} {_pluralize(error_count, 'error')}."
98
+
99
+
100
+ @_register_response_message("UpdateMediaBuyResponse1")
101
+ def _update_media_buy_success_message(self: Any) -> str:
102
+ media_buy_id = getattr(self, "media_buy_id", None)
103
+ return f"Media buy {media_buy_id} updated successfully."
104
+
105
+
106
+ @_register_response_message("UpdateMediaBuyResponse2")
107
+ def _update_media_buy_error_message(self: Any) -> str:
108
+ errors = getattr(self, "errors", None)
109
+ error_count = len(errors) if errors else 0
110
+ return f"Media buy update failed with {error_count} {_pluralize(error_count, 'error')}."
111
+
112
+
113
+ @_register_response_message("SyncCreativesResponse1")
114
+ def _sync_creatives_success_message(self: Any) -> str:
115
+ creatives = getattr(self, "creatives", None)
116
+ creative_count = len(creatives) if creatives else 0
117
+ return f"Synced {creative_count} {_pluralize(creative_count, 'creative')} successfully."
118
+
119
+
120
+ @_register_response_message("SyncCreativesResponse2")
121
+ def _sync_creatives_error_message(self: Any) -> str:
122
+ errors = getattr(self, "errors", None)
123
+ error_count = len(errors) if errors else 0
124
+ return f"Creative sync failed with {error_count} {_pluralize(error_count, 'error')}."
125
+
126
+
127
+ @_register_response_message("ActivateSignalResponse1")
128
+ def _activate_signal_success_message(self: Any) -> str:
129
+ return "Signal activated successfully."
130
+
131
+
132
+ @_register_response_message("ActivateSignalResponse2")
133
+ def _activate_signal_error_message(self: Any) -> str:
134
+ errors = getattr(self, "errors", None)
135
+ error_count = len(errors) if errors else 0
136
+ return f"Signal activation failed with {error_count} {_pluralize(error_count, 'error')}."
137
+
138
+
139
+ @_register_response_message("PreviewCreativeResponse1")
140
+ def _preview_creative_single_message(self: Any) -> str:
141
+ previews = getattr(self, "previews", None)
142
+ preview_count = len(previews) if previews else 0
143
+ return f"Generated {preview_count} {_pluralize(preview_count, 'preview')}."
144
+
145
+
146
+ @_register_response_message("PreviewCreativeResponse2")
147
+ def _preview_creative_batch_message(self: Any) -> str:
148
+ results = getattr(self, "results", None)
149
+ result_count = len(results) if results else 0
150
+ return f"Generated previews for {result_count} {_pluralize(result_count, 'manifest')}."
151
+
152
+
153
+ @_register_response_message("BuildCreativeResponse1")
154
+ def _build_creative_success_message(self: Any) -> str:
155
+ return "Creative built successfully."
156
+
157
+
158
+ @_register_response_message("BuildCreativeResponse2")
159
+ def _build_creative_error_message(self: Any) -> str:
160
+ errors = getattr(self, "errors", None)
161
+ error_count = len(errors) if errors else 0
162
+ return f"Creative build failed with {error_count} {_pluralize(error_count, 'error')}."
163
+
164
+
165
+ @_register_response_message("GetMediaBuyDeliveryResponse")
166
+ def _get_media_buy_delivery_message(self: Any) -> str:
167
+ deliveries = getattr(self, "media_buy_deliveries", None)
168
+ if deliveries is None:
169
+ return "No delivery data available."
170
+ count = len(deliveries)
171
+ return f"Retrieved delivery data for {count} media {_pluralize(count, 'buy', 'buys')}."
172
+
173
+
174
+ @_register_response_message("ProvidePerformanceFeedbackResponse1")
175
+ def _provide_performance_feedback_success_message(self: Any) -> str:
176
+ return "Performance feedback recorded successfully."
177
+
178
+
179
+ @_register_response_message("ProvidePerformanceFeedbackResponse2")
180
+ def _provide_performance_feedback_error_message(self: Any) -> str:
181
+ errors = getattr(self, "errors", None)
182
+ error_count = len(errors) if errors else 0
183
+ return (
184
+ f"Performance feedback recording failed with "
185
+ f"{error_count} {_pluralize(error_count, 'error')}."
186
+ )
187
+
9
188
 
10
189
  class AdCPBaseModel(BaseModel):
11
190
  """Base model for AdCP types with spec-compliant serialization.
@@ -24,3 +203,17 @@ class AdCPBaseModel(BaseModel):
24
203
  if "exclude_none" not in kwargs:
25
204
  kwargs["exclude_none"] = True
26
205
  return super().model_dump_json(**kwargs)
206
+
207
+ def summary(self) -> str:
208
+ """Human-readable summary for protocol responses.
209
+
210
+ Returns a standardized human-readable message suitable for MCP tool
211
+ results, A2A task communications, and REST API responses.
212
+
213
+ For types without a registered formatter, returns a generic message
214
+ with the class name.
215
+ """
216
+ formatter = _RESPONSE_MESSAGE_REGISTRY.get(self.__class__.__name__)
217
+ if formatter:
218
+ return formatter(self)
219
+ return f"{self.__class__.__name__} response"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adcp
3
- Version: 2.12.2
3
+ Version: 2.13.0
4
4
  Summary: Official Python client for the Ad Context Protocol (AdCP)
5
5
  Author-email: AdCP Community <maintainers@adcontextprotocol.org>
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  adcp/ADCP_VERSION,sha256=cy9k2HT5B4jAGZsMGb_Zs7ZDbhQBFOU-RigyUy10xhw,6
2
- adcp/__init__.py,sha256=tcd4sU6uHaJWAWmnfsNLhQEQF7FW7uNK1bdd-xKzaKQ,9933
2
+ adcp/__init__.py,sha256=bc6VcbIXmZzfjXFmMV13x-5-5F9rFkir6B51hQsj34U,9933
3
3
  adcp/__main__.py,sha256=8v-j_W9IIWDIcvhaR1yuZAhBCDRfehUyN0tusstzyfQ,15139
4
4
  adcp/adagents.py,sha256=o-vTBmdZvu9aER-TAlLLL3s-WGYY8N67jnrAH24lST8,22333
5
5
  adcp/client.py,sha256=PQsmfpL-j2msTbWZkOcH0ZFGzPP9hh0QOPZ2fFrm8Q8,37149
@@ -17,7 +17,7 @@ adcp/testing/test_helpers.py,sha256=-UKuxxyKQald5EvXxguQH34b3J0JdsxKH_nRT6GTjkQ,
17
17
  adcp/types/__init__.py,sha256=bTEGjtbSbcCDYM2Y2f8bXdfJWS47FIw9UJJL5T7-wn4,13563
18
18
  adcp/types/_generated.py,sha256=eJg4J0TLOuFKrl32vI-fNFZ6vEhB2gBP6753VlA1PRE,20816
19
19
  adcp/types/aliases.py,sha256=PPBaWr-UMzfqVbg-592btdaqF1ATJWljtu8iiyV3RYQ,25142
20
- adcp/types/base.py,sha256=QoEuVfI4yzefup0dc2KN11AcJTbcGxRep7xOw5hXfs8,837
20
+ adcp/types/base.py,sha256=Xr0cwbjG4tRPLbDTX9lucGty6_Y_S0a5C_ve0n7umc8,8227
21
21
  adcp/types/core.py,sha256=RXkKCWCXS9BVJTNpe3Opm5O1I_LaQPMUuVwa-ipvS1Q,4839
22
22
  adcp/types/generated_poc/__init__.py,sha256=bgFFvPK1-e04eOnyw0qmtVMzoA2V7GeAMPDVrx-VIwA,103
23
23
  adcp/types/generated_poc/adagents.py,sha256=lftHANcpBRj83vZn1wHUUO7zJjkXhWpWZ32CjlwbtnI,16438
@@ -168,9 +168,9 @@ adcp/utils/__init__.py,sha256=uetvSJB19CjQbtwEYZiTnumJG11GsafQmXm5eR3hL7E,153
168
168
  adcp/utils/operation_id.py,sha256=wQX9Bb5epXzRq23xoeYPTqzu5yLuhshg7lKJZihcM2k,294
169
169
  adcp/utils/preview_cache.py,sha256=rZTZfrN2MOvIWsvyyiNhrc2iVxoaFV_QaB1DlfsUH-Y,18668
170
170
  adcp/utils/response_parser.py,sha256=uPk2vIH-RYZmq7y3i8lC4HTMQ3FfKdlgXKTjgJ1955M,6253
171
- adcp-2.12.2.dist-info/licenses/LICENSE,sha256=PF39NR3Ae8PLgBhg3Uxw6ju7iGVIf8hfv9LRWQdii_U,629
172
- adcp-2.12.2.dist-info/METADATA,sha256=gzsbziBYljfvRI4Ol6fIvW8E8eKS7c7D_50oNkiFqWo,31358
173
- adcp-2.12.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
174
- adcp-2.12.2.dist-info/entry_points.txt,sha256=DQKpcGsJX8DtVI_SGApQ7tNvqUB4zkTLaTAEpFgmi3U,44
175
- adcp-2.12.2.dist-info/top_level.txt,sha256=T1_NF0GefncFU9v_k56oDwKSJREyCqIM8lAwNZf0EOs,5
176
- adcp-2.12.2.dist-info/RECORD,,
171
+ adcp-2.13.0.dist-info/licenses/LICENSE,sha256=PF39NR3Ae8PLgBhg3Uxw6ju7iGVIf8hfv9LRWQdii_U,629
172
+ adcp-2.13.0.dist-info/METADATA,sha256=eiKsacoPkxO4J41f0-smMmz9CIkAXIRx7oYwzcjbxvg,31358
173
+ adcp-2.13.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
174
+ adcp-2.13.0.dist-info/entry_points.txt,sha256=DQKpcGsJX8DtVI_SGApQ7tNvqUB4zkTLaTAEpFgmi3U,44
175
+ adcp-2.13.0.dist-info/top_level.txt,sha256=T1_NF0GefncFU9v_k56oDwKSJREyCqIM8lAwNZf0EOs,5
176
+ adcp-2.13.0.dist-info/RECORD,,
File without changes