adcp 2.12.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.
Files changed (176) hide show
  1. adcp/__init__.py +364 -0
  2. adcp/__main__.py +440 -0
  3. adcp/adagents.py +642 -0
  4. adcp/client.py +1057 -0
  5. adcp/config.py +82 -0
  6. adcp/exceptions.py +185 -0
  7. adcp/protocols/__init__.py +9 -0
  8. adcp/protocols/a2a.py +484 -0
  9. adcp/protocols/base.py +190 -0
  10. adcp/protocols/mcp.py +440 -0
  11. adcp/py.typed +0 -0
  12. adcp/simple.py +451 -0
  13. adcp/testing/__init__.py +53 -0
  14. adcp/testing/test_helpers.py +311 -0
  15. adcp/types/__init__.py +561 -0
  16. adcp/types/_generated.py +237 -0
  17. adcp/types/aliases.py +748 -0
  18. adcp/types/base.py +26 -0
  19. adcp/types/core.py +174 -0
  20. adcp/types/generated_poc/__init__.py +3 -0
  21. adcp/types/generated_poc/adagents.py +411 -0
  22. adcp/types/generated_poc/core/__init__.py +3 -0
  23. adcp/types/generated_poc/core/activation_key.py +30 -0
  24. adcp/types/generated_poc/core/assets/__init__.py +3 -0
  25. adcp/types/generated_poc/core/assets/audio_asset.py +26 -0
  26. adcp/types/generated_poc/core/assets/css_asset.py +20 -0
  27. adcp/types/generated_poc/core/assets/daast_asset.py +61 -0
  28. adcp/types/generated_poc/core/assets/html_asset.py +18 -0
  29. adcp/types/generated_poc/core/assets/image_asset.py +19 -0
  30. adcp/types/generated_poc/core/assets/javascript_asset.py +23 -0
  31. adcp/types/generated_poc/core/assets/text_asset.py +20 -0
  32. adcp/types/generated_poc/core/assets/url_asset.py +28 -0
  33. adcp/types/generated_poc/core/assets/vast_asset.py +63 -0
  34. adcp/types/generated_poc/core/assets/video_asset.py +24 -0
  35. adcp/types/generated_poc/core/assets/webhook_asset.py +53 -0
  36. adcp/types/generated_poc/core/brand_manifest.py +201 -0
  37. adcp/types/generated_poc/core/context.py +15 -0
  38. adcp/types/generated_poc/core/creative_asset.py +102 -0
  39. adcp/types/generated_poc/core/creative_assignment.py +27 -0
  40. adcp/types/generated_poc/core/creative_filters.py +86 -0
  41. adcp/types/generated_poc/core/creative_manifest.py +68 -0
  42. adcp/types/generated_poc/core/creative_policy.py +28 -0
  43. adcp/types/generated_poc/core/delivery_metrics.py +111 -0
  44. adcp/types/generated_poc/core/deployment.py +78 -0
  45. adcp/types/generated_poc/core/destination.py +43 -0
  46. adcp/types/generated_poc/core/dimensions.py +18 -0
  47. adcp/types/generated_poc/core/error.py +29 -0
  48. adcp/types/generated_poc/core/ext.py +15 -0
  49. adcp/types/generated_poc/core/format.py +260 -0
  50. adcp/types/generated_poc/core/format_id.py +50 -0
  51. adcp/types/generated_poc/core/frequency_cap.py +19 -0
  52. adcp/types/generated_poc/core/measurement.py +40 -0
  53. adcp/types/generated_poc/core/media_buy.py +40 -0
  54. adcp/types/generated_poc/core/package.py +68 -0
  55. adcp/types/generated_poc/core/performance_feedback.py +78 -0
  56. adcp/types/generated_poc/core/placement.py +37 -0
  57. adcp/types/generated_poc/core/product.py +164 -0
  58. adcp/types/generated_poc/core/product_filters.py +97 -0
  59. adcp/types/generated_poc/core/promoted_offerings.py +102 -0
  60. adcp/types/generated_poc/core/promoted_products.py +38 -0
  61. adcp/types/generated_poc/core/property.py +64 -0
  62. adcp/types/generated_poc/core/property_id.py +21 -0
  63. adcp/types/generated_poc/core/property_tag.py +21 -0
  64. adcp/types/generated_poc/core/protocol_envelope.py +61 -0
  65. adcp/types/generated_poc/core/publisher_property_selector.py +75 -0
  66. adcp/types/generated_poc/core/push_notification_config.py +51 -0
  67. adcp/types/generated_poc/core/reporting_capabilities.py +51 -0
  68. adcp/types/generated_poc/core/response.py +24 -0
  69. adcp/types/generated_poc/core/signal_filters.py +29 -0
  70. adcp/types/generated_poc/core/sub_asset.py +55 -0
  71. adcp/types/generated_poc/core/targeting.py +53 -0
  72. adcp/types/generated_poc/core/webhook_payload.py +96 -0
  73. adcp/types/generated_poc/creative/__init__.py +3 -0
  74. adcp/types/generated_poc/creative/list_creative_formats_request.py +88 -0
  75. adcp/types/generated_poc/creative/list_creative_formats_response.py +55 -0
  76. adcp/types/generated_poc/creative/preview_creative_request.py +153 -0
  77. adcp/types/generated_poc/creative/preview_creative_response.py +169 -0
  78. adcp/types/generated_poc/creative/preview_render.py +152 -0
  79. adcp/types/generated_poc/enums/__init__.py +3 -0
  80. adcp/types/generated_poc/enums/adcp_domain.py +12 -0
  81. adcp/types/generated_poc/enums/asset_content_type.py +23 -0
  82. adcp/types/generated_poc/enums/auth_scheme.py +12 -0
  83. adcp/types/generated_poc/enums/available_metric.py +19 -0
  84. adcp/types/generated_poc/enums/channels.py +19 -0
  85. adcp/types/generated_poc/enums/co_branding_requirement.py +13 -0
  86. adcp/types/generated_poc/enums/creative_action.py +15 -0
  87. adcp/types/generated_poc/enums/creative_agent_capability.py +14 -0
  88. adcp/types/generated_poc/enums/creative_sort_field.py +16 -0
  89. adcp/types/generated_poc/enums/creative_status.py +14 -0
  90. adcp/types/generated_poc/enums/daast_tracking_event.py +21 -0
  91. adcp/types/generated_poc/enums/daast_version.py +12 -0
  92. adcp/types/generated_poc/enums/delivery_type.py +12 -0
  93. adcp/types/generated_poc/enums/dimension_unit.py +14 -0
  94. adcp/types/generated_poc/enums/feed_format.py +13 -0
  95. adcp/types/generated_poc/enums/feedback_source.py +14 -0
  96. adcp/types/generated_poc/enums/format_category.py +17 -0
  97. adcp/types/generated_poc/enums/format_id_parameter.py +12 -0
  98. adcp/types/generated_poc/enums/frequency_cap_scope.py +16 -0
  99. adcp/types/generated_poc/enums/history_entry_type.py +12 -0
  100. adcp/types/generated_poc/enums/http_method.py +12 -0
  101. adcp/types/generated_poc/enums/identifier_types.py +29 -0
  102. adcp/types/generated_poc/enums/javascript_module_type.py +13 -0
  103. adcp/types/generated_poc/enums/landing_page_requirement.py +13 -0
  104. adcp/types/generated_poc/enums/markdown_flavor.py +12 -0
  105. adcp/types/generated_poc/enums/media_buy_status.py +14 -0
  106. adcp/types/generated_poc/enums/metric_type.py +18 -0
  107. adcp/types/generated_poc/enums/notification_type.py +14 -0
  108. adcp/types/generated_poc/enums/pacing.py +13 -0
  109. adcp/types/generated_poc/enums/preview_output_format.py +12 -0
  110. adcp/types/generated_poc/enums/pricing_model.py +17 -0
  111. adcp/types/generated_poc/enums/property_type.py +17 -0
  112. adcp/types/generated_poc/enums/publisher_identifier_types.py +15 -0
  113. adcp/types/generated_poc/enums/reporting_frequency.py +13 -0
  114. adcp/types/generated_poc/enums/signal_catalog_type.py +13 -0
  115. adcp/types/generated_poc/enums/sort_direction.py +12 -0
  116. adcp/types/generated_poc/enums/standard_format_ids.py +45 -0
  117. adcp/types/generated_poc/enums/task_status.py +19 -0
  118. adcp/types/generated_poc/enums/task_type.py +15 -0
  119. adcp/types/generated_poc/enums/update_frequency.py +14 -0
  120. adcp/types/generated_poc/enums/url_asset_type.py +13 -0
  121. adcp/types/generated_poc/enums/validation_mode.py +12 -0
  122. adcp/types/generated_poc/enums/vast_tracking_event.py +26 -0
  123. adcp/types/generated_poc/enums/vast_version.py +15 -0
  124. adcp/types/generated_poc/enums/webhook_response_type.py +14 -0
  125. adcp/types/generated_poc/enums/webhook_security_method.py +13 -0
  126. adcp/types/generated_poc/media_buy/__init__.py +3 -0
  127. adcp/types/generated_poc/media_buy/build_creative_request.py +41 -0
  128. adcp/types/generated_poc/media_buy/build_creative_response.py +51 -0
  129. adcp/types/generated_poc/media_buy/create_media_buy_request.py +94 -0
  130. adcp/types/generated_poc/media_buy/create_media_buy_response.py +56 -0
  131. adcp/types/generated_poc/media_buy/get_media_buy_delivery_request.py +47 -0
  132. adcp/types/generated_poc/media_buy/get_media_buy_delivery_response.py +235 -0
  133. adcp/types/generated_poc/media_buy/get_products_request.py +48 -0
  134. adcp/types/generated_poc/media_buy/get_products_response.py +28 -0
  135. adcp/types/generated_poc/media_buy/list_authorized_properties_request.py +38 -0
  136. adcp/types/generated_poc/media_buy/list_authorized_properties_response.py +84 -0
  137. adcp/types/generated_poc/media_buy/list_creative_formats_request.py +74 -0
  138. adcp/types/generated_poc/media_buy/list_creative_formats_response.py +56 -0
  139. adcp/types/generated_poc/media_buy/list_creatives_request.py +76 -0
  140. adcp/types/generated_poc/media_buy/list_creatives_response.py +214 -0
  141. adcp/types/generated_poc/media_buy/package_request.py +63 -0
  142. adcp/types/generated_poc/media_buy/provide_performance_feedback_request.py +125 -0
  143. adcp/types/generated_poc/media_buy/provide_performance_feedback_response.py +53 -0
  144. adcp/types/generated_poc/media_buy/sync_creatives_request.py +63 -0
  145. adcp/types/generated_poc/media_buy/sync_creatives_response.py +105 -0
  146. adcp/types/generated_poc/media_buy/update_media_buy_request.py +195 -0
  147. adcp/types/generated_poc/media_buy/update_media_buy_response.py +55 -0
  148. adcp/types/generated_poc/pricing_options/__init__.py +3 -0
  149. adcp/types/generated_poc/pricing_options/cpc_option.py +43 -0
  150. adcp/types/generated_poc/pricing_options/cpcv_option.py +45 -0
  151. adcp/types/generated_poc/pricing_options/cpm_auction_option.py +58 -0
  152. adcp/types/generated_poc/pricing_options/cpm_fixed_option.py +43 -0
  153. adcp/types/generated_poc/pricing_options/cpp_option.py +64 -0
  154. adcp/types/generated_poc/pricing_options/cpv_option.py +77 -0
  155. adcp/types/generated_poc/pricing_options/flat_rate_option.py +93 -0
  156. adcp/types/generated_poc/pricing_options/vcpm_auction_option.py +61 -0
  157. adcp/types/generated_poc/pricing_options/vcpm_fixed_option.py +47 -0
  158. adcp/types/generated_poc/protocols/__init__.py +3 -0
  159. adcp/types/generated_poc/protocols/adcp_extension.py +37 -0
  160. adcp/types/generated_poc/signals/__init__.py +3 -0
  161. adcp/types/generated_poc/signals/activate_signal_request.py +32 -0
  162. adcp/types/generated_poc/signals/activate_signal_response.py +51 -0
  163. adcp/types/generated_poc/signals/get_signals_request.py +53 -0
  164. adcp/types/generated_poc/signals/get_signals_response.py +59 -0
  165. adcp/utils/__init__.py +7 -0
  166. adcp/utils/operation_id.py +15 -0
  167. adcp/utils/preview_cache.py +491 -0
  168. adcp/utils/response_parser.py +171 -0
  169. adcp/validation.py +172 -0
  170. adcp-2.12.0.data/data/ADCP_VERSION +1 -0
  171. adcp-2.12.0.dist-info/METADATA +992 -0
  172. adcp-2.12.0.dist-info/RECORD +176 -0
  173. adcp-2.12.0.dist-info/WHEEL +5 -0
  174. adcp-2.12.0.dist-info/entry_points.txt +2 -0
  175. adcp-2.12.0.dist-info/licenses/LICENSE +17 -0
  176. adcp-2.12.0.dist-info/top_level.txt +1 -0
adcp/validation.py ADDED
@@ -0,0 +1,172 @@
1
+ """Runtime validation for AdCP data structures.
2
+
3
+ This module provides runtime validation that complements schema validation:
4
+
5
+ 1. **For adagents.json (v2.4.0+)**: Validates discriminated union structure
6
+ - Checks for proper authorization_type discriminator
7
+ - Validates publisher_properties selection_type discriminator
8
+ - These constraints ARE enforced in upstream schemas via oneOf + discriminators
9
+
10
+ 2. **For product.json**: Validates mutual exclusivity constraints
11
+ - publisher_properties must have either property_ids OR property_tags
12
+ - These constraints are NOT yet enforced in upstream schemas (pending fix)
13
+
14
+ Note: When using Pydantic models directly, discriminated union validation happens
15
+ automatically during model construction. This module is for validating raw dict data
16
+ before Pydantic parsing (e.g., in fetch_adagents()).
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from typing import Any
22
+
23
+
24
+ class ValidationError(ValueError):
25
+ """Raised when runtime validation fails."""
26
+
27
+ pass
28
+
29
+
30
+ def validate_publisher_properties_item(item: dict[str, Any]) -> None:
31
+ """Validate publisher_properties item discriminated union.
32
+
33
+ AdCP v2.4.0+ uses discriminated unions with selection_type discriminator:
34
+ - selection_type: "by_id" requires property_ids
35
+ - selection_type: "by_tag" requires property_tags
36
+
37
+ For backward compatibility, also validates the old mutual exclusivity constraint.
38
+
39
+ Args:
40
+ item: A single item from publisher_properties array
41
+
42
+ Raises:
43
+ ValidationError: If discriminator or field constraints are violated
44
+ """
45
+ selection_type = item.get("selection_type")
46
+ has_property_ids = "property_ids" in item and item["property_ids"] is not None
47
+ has_property_tags = "property_tags" in item and item["property_tags"] is not None
48
+
49
+ # If selection_type discriminator is present, validate discriminated union
50
+ if selection_type:
51
+ if selection_type == "by_id" and not has_property_ids:
52
+ raise ValidationError(
53
+ "publisher_properties item with selection_type='by_id' must have property_ids"
54
+ )
55
+ elif selection_type == "by_tag" and not has_property_tags:
56
+ raise ValidationError(
57
+ "publisher_properties item with selection_type='by_tag' must have property_tags"
58
+ )
59
+ elif selection_type not in ("by_id", "by_tag"):
60
+ raise ValidationError(
61
+ f"publisher_properties item has invalid selection_type: {selection_type}"
62
+ )
63
+
64
+ # Validate mutual exclusivity (for both old and new formats)
65
+ if has_property_ids and has_property_tags:
66
+ raise ValidationError(
67
+ "publisher_properties item cannot have both property_ids and property_tags. "
68
+ "These fields are mutually exclusive."
69
+ )
70
+
71
+ if not has_property_ids and not has_property_tags:
72
+ raise ValidationError(
73
+ "publisher_properties item must have either property_ids or property_tags. "
74
+ "At least one is required."
75
+ )
76
+
77
+
78
+ def validate_agent_authorization(agent: dict[str, Any]) -> None:
79
+ """Validate agent authorization discriminated union.
80
+
81
+ AdCP v2.4.0+ uses discriminated unions with authorization_type discriminator:
82
+ - authorization_type: "property_ids" requires property_ids
83
+ - authorization_type: "property_tags" requires property_tags
84
+ - authorization_type: "inline_properties" requires properties
85
+ - authorization_type: "publisher_properties" requires publisher_properties
86
+
87
+ For backward compatibility, also validates the old mutual exclusivity constraint.
88
+
89
+ Args:
90
+ agent: An agent dict from adagents.json
91
+
92
+ Raises:
93
+ ValidationError: If discriminator or field constraints are violated
94
+ """
95
+ authorization_type = agent.get("authorization_type")
96
+ auth_fields = ["properties", "property_ids", "property_tags", "publisher_properties"]
97
+ present_fields = [field for field in auth_fields if field in agent and agent[field] is not None]
98
+
99
+ # If authorization_type discriminator is present, validate discriminated union
100
+ if authorization_type:
101
+ if authorization_type == "property_ids" and "property_ids" not in present_fields:
102
+ raise ValidationError(
103
+ "Agent with authorization_type='property_ids' must have property_ids"
104
+ )
105
+ elif authorization_type == "property_tags" and "property_tags" not in present_fields:
106
+ raise ValidationError(
107
+ "Agent with authorization_type='property_tags' must have property_tags"
108
+ )
109
+ elif authorization_type == "inline_properties" and "properties" not in present_fields:
110
+ raise ValidationError(
111
+ "Agent with authorization_type='inline_properties' must have properties"
112
+ )
113
+ elif (
114
+ authorization_type == "publisher_properties"
115
+ and "publisher_properties" not in present_fields
116
+ ):
117
+ raise ValidationError(
118
+ "Agent with authorization_type='publisher_properties' "
119
+ "must have publisher_properties"
120
+ )
121
+ elif authorization_type not in (
122
+ "property_ids",
123
+ "property_tags",
124
+ "inline_properties",
125
+ "publisher_properties",
126
+ ):
127
+ raise ValidationError(f"Agent has invalid authorization_type: {authorization_type}")
128
+
129
+ # Validate mutual exclusivity (for both old and new formats)
130
+ if len(present_fields) > 1:
131
+ raise ValidationError(
132
+ f"Agent authorization cannot have multiple fields: {', '.join(present_fields)}. "
133
+ f"Only one of {', '.join(auth_fields)} is allowed."
134
+ )
135
+
136
+ if len(present_fields) == 0:
137
+ raise ValidationError(
138
+ f"Agent authorization must have exactly one of: {', '.join(auth_fields)}."
139
+ )
140
+
141
+ # If using publisher_properties, validate each item
142
+ if "publisher_properties" in present_fields:
143
+ for pub_prop in agent["publisher_properties"]:
144
+ validate_publisher_properties_item(pub_prop)
145
+
146
+
147
+ def validate_product(product: dict[str, Any]) -> None:
148
+ """Validate a Product object.
149
+
150
+ Args:
151
+ product: Product dict
152
+
153
+ Raises:
154
+ ValidationError: If validation fails
155
+ """
156
+ if "publisher_properties" in product and product["publisher_properties"]:
157
+ for item in product["publisher_properties"]:
158
+ validate_publisher_properties_item(item)
159
+
160
+
161
+ def validate_adagents(adagents: dict[str, Any]) -> None:
162
+ """Validate an adagents.json structure.
163
+
164
+ Args:
165
+ adagents: The adagents.json dict
166
+
167
+ Raises:
168
+ ValidationError: If validation fails
169
+ """
170
+ if "agents" in adagents:
171
+ for agent in adagents["agents"]:
172
+ validate_agent_authorization(agent)
@@ -0,0 +1 @@
1
+ 2.5.0