adcp 1.6.1__py3-none-any.whl → 2.1.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 (118) hide show
  1. adcp/__init__.py +110 -189
  2. adcp/adagents.py +11 -12
  3. adcp/client.py +16 -11
  4. adcp/py.typed +0 -0
  5. adcp/types/aliases.py +209 -0
  6. adcp/types/generated.py +540 -1134
  7. adcp/types/generated_poc/__init__.py +3 -0
  8. adcp/types/generated_poc/activate_signal_request.py +34 -0
  9. adcp/types/generated_poc/activate_signal_response.py +57 -0
  10. adcp/types/generated_poc/activation_key.py +30 -0
  11. adcp/types/generated_poc/adagents.py +266 -0
  12. adcp/types/generated_poc/asset_type.py +100 -0
  13. adcp/types/generated_poc/audio_asset.py +26 -0
  14. adcp/types/generated_poc/brand_manifest.py +260 -0
  15. adcp/types/generated_poc/brand_manifest_ref.py +361 -0
  16. adcp/types/generated_poc/build_creative_request.py +43 -0
  17. adcp/types/generated_poc/build_creative_response.py +57 -0
  18. adcp/types/generated_poc/channels.py +19 -0
  19. adcp/types/generated_poc/cpc_option.py +39 -0
  20. adcp/types/generated_poc/cpcv_option.py +41 -0
  21. adcp/types/generated_poc/cpm_auction_option.py +54 -0
  22. adcp/types/generated_poc/cpm_fixed_option.py +39 -0
  23. adcp/types/generated_poc/cpp_option.py +60 -0
  24. adcp/types/generated_poc/cpv_option.py +73 -0
  25. adcp/types/generated_poc/create_media_buy_request.py +96 -0
  26. adcp/types/generated_poc/create_media_buy_response.py +66 -0
  27. adcp/types/generated_poc/creative_asset.py +83 -0
  28. adcp/types/generated_poc/creative_assignment.py +27 -0
  29. adcp/types/generated_poc/creative_manifest.py +61 -0
  30. adcp/types/generated_poc/creative_policy.py +34 -0
  31. adcp/types/generated_poc/creative_status.py +14 -0
  32. adcp/types/generated_poc/css_asset.py +20 -0
  33. adcp/types/generated_poc/daast_asset.py +76 -0
  34. adcp/types/generated_poc/delivery_metrics.py +111 -0
  35. adcp/types/generated_poc/delivery_type.py +12 -0
  36. adcp/types/generated_poc/deployment.py +78 -0
  37. adcp/types/generated_poc/destination.py +43 -0
  38. adcp/types/generated_poc/error.py +29 -0
  39. adcp/types/generated_poc/flat_rate_option.py +93 -0
  40. adcp/types/generated_poc/format.py +260 -0
  41. adcp/types/generated_poc/format_id.py +29 -0
  42. adcp/types/generated_poc/frequency_cap.py +19 -0
  43. adcp/types/generated_poc/frequency_cap_scope.py +16 -0
  44. adcp/types/generated_poc/get_media_buy_delivery_request.py +65 -0
  45. adcp/types/generated_poc/get_media_buy_delivery_response.py +220 -0
  46. adcp/types/generated_poc/get_products_request.py +83 -0
  47. adcp/types/generated_poc/get_products_response.py +29 -0
  48. adcp/types/generated_poc/get_signals_request.py +77 -0
  49. adcp/types/generated_poc/get_signals_response.py +65 -0
  50. adcp/types/generated_poc/html_asset.py +18 -0
  51. adcp/types/generated_poc/identifier_types.py +29 -0
  52. adcp/types/generated_poc/image_asset.py +23 -0
  53. adcp/types/generated_poc/index.py +17 -0
  54. adcp/types/generated_poc/javascript_asset.py +25 -0
  55. adcp/types/generated_poc/list_authorized_properties_request.py +39 -0
  56. adcp/types/generated_poc/list_authorized_properties_response.py +85 -0
  57. adcp/types/generated_poc/list_creative_formats_request.py +93 -0
  58. adcp/types/generated_poc/list_creative_formats_response.py +63 -0
  59. adcp/types/generated_poc/list_creatives_request.py +154 -0
  60. adcp/types/generated_poc/list_creatives_response.py +234 -0
  61. adcp/types/generated_poc/markdown_asset.py +43 -0
  62. adcp/types/generated_poc/measurement.py +40 -0
  63. adcp/types/generated_poc/media_buy.py +37 -0
  64. adcp/types/generated_poc/media_buy_status.py +14 -0
  65. adcp/types/generated_poc/pacing.py +13 -0
  66. adcp/types/generated_poc/package.py +61 -0
  67. adcp/types/generated_poc/package_request.py +61 -0
  68. adcp/types/generated_poc/package_status.py +14 -0
  69. adcp/types/generated_poc/performance_feedback.py +89 -0
  70. adcp/types/generated_poc/placement.py +37 -0
  71. adcp/types/generated_poc/preview_creative_request.py +163 -0
  72. adcp/types/generated_poc/preview_creative_response.py +175 -0
  73. adcp/types/generated_poc/preview_render.py +144 -0
  74. adcp/types/generated_poc/pricing_model.py +17 -0
  75. adcp/types/generated_poc/pricing_option.py +365 -0
  76. adcp/types/generated_poc/product.py +211 -0
  77. adcp/types/generated_poc/promoted_offerings.py +102 -0
  78. adcp/types/generated_poc/promoted_products.py +38 -0
  79. adcp/types/generated_poc/property.py +79 -0
  80. adcp/types/generated_poc/protocol_envelope.py +61 -0
  81. adcp/types/generated_poc/provide_performance_feedback_request.py +85 -0
  82. adcp/types/generated_poc/provide_performance_feedback_response.py +59 -0
  83. adcp/types/generated_poc/publisher_identifier_types.py +15 -0
  84. adcp/types/generated_poc/push_notification_config.py +55 -0
  85. adcp/types/generated_poc/reporting_capabilities.py +68 -0
  86. adcp/types/generated_poc/response.py +24 -0
  87. adcp/types/generated_poc/standard_format_ids.py +45 -0
  88. adcp/types/generated_poc/start_timing.py +13 -0
  89. adcp/types/generated_poc/sub_asset.py +55 -0
  90. adcp/types/generated_poc/sync_creatives_request.py +69 -0
  91. adcp/types/generated_poc/sync_creatives_response.py +117 -0
  92. adcp/types/generated_poc/targeting.py +53 -0
  93. adcp/types/generated_poc/task_status.py +19 -0
  94. adcp/types/generated_poc/task_type.py +15 -0
  95. adcp/types/generated_poc/tasks_get_request.py +29 -0
  96. adcp/types/generated_poc/tasks_get_response.py +112 -0
  97. adcp/types/generated_poc/tasks_list_request.py +121 -0
  98. adcp/types/generated_poc/tasks_list_response.py +122 -0
  99. adcp/types/generated_poc/text_asset.py +20 -0
  100. adcp/types/generated_poc/update_media_buy_request.py +160 -0
  101. adcp/types/generated_poc/update_media_buy_response.py +67 -0
  102. adcp/types/generated_poc/url_asset.py +33 -0
  103. adcp/types/generated_poc/vast_asset.py +86 -0
  104. adcp/types/generated_poc/vcpm_auction_option.py +57 -0
  105. adcp/types/generated_poc/vcpm_fixed_option.py +43 -0
  106. adcp/types/generated_poc/video_asset.py +28 -0
  107. adcp/types/generated_poc/webhook_asset.py +65 -0
  108. adcp/types/generated_poc/webhook_payload.py +102 -0
  109. adcp/utils/preview_cache.py +54 -41
  110. adcp/validation.py +172 -0
  111. {adcp-1.6.1.dist-info → adcp-2.1.0.dist-info}/METADATA +42 -3
  112. adcp-2.1.0.dist-info/RECORD +132 -0
  113. adcp/types/tasks.py +0 -511
  114. adcp-1.6.1.dist-info/RECORD +0 -28
  115. {adcp-1.6.1.dist-info → adcp-2.1.0.dist-info}/WHEEL +0 -0
  116. {adcp-1.6.1.dist-info → adcp-2.1.0.dist-info}/entry_points.txt +0 -0
  117. {adcp-1.6.1.dist-info → adcp-2.1.0.dist-info}/licenses/LICENSE +0 -0
  118. {adcp-1.6.1.dist-info → adcp-2.1.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,7 @@
1
1
  """Helper utilities for generating creative preview URLs for grid rendering."""
2
2
 
3
+ # mypy: disable-error-code="arg-type,attr-defined,call-arg,unused-ignore,union-attr"
4
+
3
5
  from __future__ import annotations
4
6
 
5
7
  import hashlib
@@ -65,7 +67,7 @@ class PreviewURLGenerator:
65
67
  Returns:
66
68
  Preview data with preview_url and metadata, or None if generation fails
67
69
  """
68
- from adcp.types.generated import PreviewCreativeRequest
70
+ from adcp.types.generated import PreviewCreativeRequest1
69
71
 
70
72
  cache_key = _make_manifest_cache_key(format_id, manifest.model_dump(exclude_none=True))
71
73
 
@@ -73,31 +75,31 @@ class PreviewURLGenerator:
73
75
  return self._preview_cache[cache_key]
74
76
 
75
77
  try:
76
- request = PreviewCreativeRequest(
78
+ request = PreviewCreativeRequest1(
79
+ request_type="single",
77
80
  format_id=format_id,
78
81
  creative_manifest=manifest,
79
- inputs=None,
80
- template_id=None,
81
- context=None
82
82
  )
83
83
  result = await self.creative_agent_client.preview_creative(request)
84
84
 
85
85
  if result.success and result.data and result.data.previews:
86
86
  preview = result.data.previews[0]
87
- renders = preview.get("renders", [])
88
- first_render = renders[0] if renders else {}
89
-
90
- preview_data = {
91
- "preview_id": preview.get("preview_id"),
92
- "preview_url": first_render.get("preview_url"),
93
- "preview_html": first_render.get("preview_html"),
94
- "render_id": first_render.get("render_id"),
95
- "input": preview.get("input", {}),
96
- "expires_at": result.data.expires_at,
97
- }
98
-
99
- self._preview_cache[cache_key] = preview_data
100
- return preview_data
87
+ first_render = preview.renders[0] if preview.renders else None
88
+
89
+ if first_render:
90
+ has_url = hasattr(first_render, "preview_url")
91
+ preview_url = str(first_render.preview_url) if has_url else None
92
+ preview_data = {
93
+ "preview_id": preview.preview_id,
94
+ "preview_url": preview_url,
95
+ "preview_html": getattr(first_render, "preview_html", None),
96
+ "render_id": first_render.render_id,
97
+ "input": preview.input.model_dump(),
98
+ "expires_at": str(result.data.expires_at),
99
+ }
100
+
101
+ self._preview_cache[cache_key] = preview_data
102
+ return preview_data
101
103
 
102
104
  except Exception as e:
103
105
  logger.warning(f"Failed to generate preview for format {format_id}: {e}", exc_info=True)
@@ -142,15 +144,13 @@ class PreviewURLGenerator:
142
144
  results[idx] = self._preview_cache[cache_key]
143
145
  else:
144
146
  uncached_indices.append(idx)
145
- fid_dict = (
146
- format_id.model_dump()
147
- if hasattr(format_id, "model_dump")
148
- else format_id
147
+ fid_dict = format_id.model_dump() if hasattr(format_id, "model_dump") else format_id
148
+ uncached_requests.append(
149
+ {
150
+ "format_id": fid_dict,
151
+ "creative_manifest": manifest.model_dump(exclude_none=True),
152
+ }
149
153
  )
150
- uncached_requests.append({
151
- "format_id": fid_dict,
152
- "creative_manifest": manifest.model_dump(exclude_none=True),
153
- })
154
154
 
155
155
  # If everything was cached, return early
156
156
  if not uncached_requests:
@@ -376,9 +376,7 @@ async def add_preview_urls_to_products(
376
376
 
377
377
  format_tasks = [process_format(fid) for fid in product.format_ids]
378
378
  format_results = await asyncio.gather(*format_tasks)
379
- format_previews = {
380
- fid: data for fid, data in format_results if data is not None
381
- }
379
+ format_previews = {fid: data for fid, data in format_results if data is not None}
382
380
 
383
381
  if format_previews:
384
382
  product_dict["format_previews"] = format_previews
@@ -408,10 +406,16 @@ def _create_sample_manifest_for_format(fmt: Format) -> CreativeManifest | None:
408
406
  for asset in fmt.assets_required:
409
407
  if isinstance(asset, dict):
410
408
  asset_id = asset.get("asset_id")
411
- asset_type = asset.get("type")
409
+ asset_type = asset.get("asset_type")
412
410
 
413
411
  if asset_id:
414
412
  assets[asset_id] = _create_sample_asset(asset_type)
413
+ else:
414
+ # Handle Pydantic model
415
+ asset_id = asset.asset_id
416
+ has_value = hasattr(asset.asset_type, "value")
417
+ asset_type = asset.asset_type.value if has_value else str(asset.asset_type)
418
+ assets[asset_id] = _create_sample_asset(asset_type)
415
419
 
416
420
  if not assets:
417
421
  return None
@@ -432,11 +436,11 @@ def _create_sample_manifest_for_format_id(
432
436
  Returns:
433
437
  Sample CreativeManifest with placeholder assets
434
438
  """
435
- from adcp.types.generated import CreativeManifest
439
+ from adcp.types.generated import CreativeManifest, ImageAsset, UrlAsset
436
440
 
437
441
  assets = {
438
- "primary_asset": "https://example.com/sample-image.jpg",
439
- "clickthrough_url": "https://example.com",
442
+ "primary_asset": ImageAsset(url="https://example.com/sample-image.jpg"),
443
+ "clickthrough_url": UrlAsset(url="https://example.com"),
440
444
  }
441
445
 
442
446
  return CreativeManifest(format_id=format_id, promoted_offering=product.name, assets=assets)
@@ -450,17 +454,26 @@ def _create_sample_asset(asset_type: str | None) -> Any:
450
454
  asset_type: Type of asset (image, video, text, url, etc.)
451
455
 
452
456
  Returns:
453
- Sample asset value
457
+ Sample asset object (Pydantic model)
454
458
  """
459
+ from adcp.types.generated import (
460
+ HtmlAsset,
461
+ ImageAsset,
462
+ TextAsset,
463
+ UrlAsset,
464
+ VideoAsset,
465
+ )
466
+
455
467
  if asset_type == "image":
456
- return "https://via.placeholder.com/300x250.png"
468
+ return ImageAsset(url="https://via.placeholder.com/300x250.png")
457
469
  elif asset_type == "video":
458
- return "https://example.com/sample-video.mp4"
470
+ return VideoAsset(url="https://example.com/sample-video.mp4")
459
471
  elif asset_type == "text":
460
- return "Sample advertising text"
472
+ return TextAsset(content="Sample advertising text")
461
473
  elif asset_type == "url":
462
- return "https://example.com"
474
+ return UrlAsset(url="https://example.com")
463
475
  elif asset_type == "html":
464
- return "<div>Sample HTML</div>"
476
+ return HtmlAsset(content="<div>Sample HTML</div>")
465
477
  else:
466
- return "https://example.com/sample-asset"
478
+ # Default to URL asset for unknown types
479
+ return UrlAsset(url="https://example.com/sample-asset")
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adcp
3
- Version: 1.6.1
3
+ Version: 2.1.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
@@ -33,6 +33,8 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
33
  Requires-Dist: mypy>=1.0.0; extra == "dev"
34
34
  Requires-Dist: black>=23.0.0; extra == "dev"
35
35
  Requires-Dist: ruff>=0.1.0; extra == "dev"
36
+ Requires-Dist: datamodel-code-generator[http]>=0.35.0; extra == "dev"
37
+ Requires-Dist: email-validator>=2.0.0; extra == "dev"
36
38
  Dynamic: license-file
37
39
 
38
40
  # adcp - Python Client for Ad Context Protocol
@@ -92,7 +94,7 @@ print(products.products[0].name)
92
94
  **Standard API** (`client.*`) - Recommended for production:
93
95
  ```python
94
96
  from adcp.testing import test_agent
95
- from adcp.types.generated import GetProductsRequest
97
+ from adcp import GetProductsRequest
96
98
 
97
99
  # Explicit request objects and TaskResult wrapper
98
100
  request = GetProductsRequest(brief='Coffee brands')
@@ -122,6 +124,8 @@ Pre-configured agents (all include `.simple` accessor):
122
124
 
123
125
  See [examples/simple_api_demo.py](examples/simple_api_demo.py) for a complete comparison.
124
126
 
127
+ > **Tip**: Import types from the main `adcp` package (e.g., `from adcp import GetProductsRequest`) rather than `adcp.types.generated` for better API stability.
128
+
125
129
  ## Quick Start: Distributed Operations
126
130
 
127
131
  For production use, configure your own agents:
@@ -185,7 +189,7 @@ from adcp.testing import (
185
189
  test_agent_no_auth, test_agent_a2a_no_auth,
186
190
  creative_agent, test_agent_client, create_test_agent
187
191
  )
188
- from adcp.types.generated import GetProductsRequest, PreviewCreativeRequest
192
+ from adcp import GetProductsRequest, PreviewCreativeRequest
189
193
 
190
194
  # 1. Single agent with authentication (MCP)
191
195
  result = await test_agent.get_products(
@@ -241,6 +245,7 @@ client = ADCPClient(config)
241
245
  - **Auto-detection**: Automatically detect which protocol an agent uses
242
246
 
243
247
  ### Type Safety
248
+
244
249
  Full type hints with Pydantic validation and auto-generated types from the AdCP spec:
245
250
 
246
251
  ```python
@@ -256,6 +261,40 @@ if result.success:
256
261
  print(product.name, product.pricing_options) # Full IDE autocomplete!
257
262
  ```
258
263
 
264
+ #### Semantic Type Aliases
265
+
266
+ For discriminated union types (success/error responses), use semantic aliases for clearer code:
267
+
268
+ ```python
269
+ from adcp import (
270
+ CreateMediaBuySuccessResponse, # Clear: this is the success case
271
+ CreateMediaBuyErrorResponse, # Clear: this is the error case
272
+ )
273
+
274
+ def handle_response(
275
+ response: CreateMediaBuySuccessResponse | CreateMediaBuyErrorResponse
276
+ ) -> None:
277
+ if isinstance(response, CreateMediaBuySuccessResponse):
278
+ print(f"✅ Media buy created: {response.media_buy_id}")
279
+ else:
280
+ print(f"❌ Errors: {response.errors}")
281
+ ```
282
+
283
+ **Available semantic aliases:**
284
+ - Response types: `*SuccessResponse` / `*ErrorResponse` (e.g., `CreateMediaBuySuccessResponse`)
285
+ - Request variants: `*FormatRequest` / `*ManifestRequest` (e.g., `PreviewCreativeFormatRequest`)
286
+ - Preview renders: `PreviewRenderImage` / `PreviewRenderHtml` / `PreviewRenderIframe`
287
+ - Activation keys: `PropertyIdActivationKey` / `PropertyTagActivationKey`
288
+
289
+ See `examples/type_aliases_demo.py` for more examples.
290
+
291
+ **Import guidelines:**
292
+ - ✅ **DO**: Import from main package: `from adcp import GetProductsRequest`
293
+ - ✅ **DO**: Use semantic aliases: `from adcp import CreateMediaBuySuccessResponse`
294
+ - ⚠️ **AVOID**: Import from internal modules: `from adcp.types.generated import CreateMediaBuyResponse1`
295
+
296
+ The main package exports provide a stable API while internal generated types may change.
297
+
259
298
  ### Multi-Agent Operations
260
299
  Execute across multiple agents simultaneously:
261
300
 
@@ -0,0 +1,132 @@
1
+ adcp/__init__.py,sha256=lbYHt11mytsQ0zVHUqa2UKMGGc8uW0_6c55svUrN6So,6868
2
+ adcp/__main__.py,sha256=Avy_C71rruh2lOuojvuXDj09tkFOaek74nJ-dbx25Sw,12838
3
+ adcp/adagents.py,sha256=NjtK_3FmvikG4vlCGPxQwFYl-iOML09uIdtqT2lAWEA,17669
4
+ adcp/client.py,sha256=KFsNaHNYuapMLpjfqMbycDkEc147gEpxpwXzVuZ1y2o,28802
5
+ adcp/config.py,sha256=Vsy7ZPOI8G3fB_i5Nk-CHbC7wdasCUWuKlos0fwA0kY,2017
6
+ adcp/exceptions.py,sha256=1aZEWpaM92OxD2jl9yKsqJp5ReSWaj0S0DFhxChhLlA,6732
7
+ adcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ adcp/simple.py,sha256=FgPYWT32BNXkQz07r2x2gXgOmOikWLi88SzN5UIVSiU,10440
9
+ adcp/validation.py,sha256=NsTwTQbLmd1Z1bMcztR1llJB21ai1xuw5aVrca7LoE8,6793
10
+ adcp/protocols/__init__.py,sha256=6UFwACQ0QadBUzy17wUROHqsJDp8ztPW2jzyl53Zh_g,262
11
+ adcp/protocols/a2a.py,sha256=FHgc6G_eU2qD0vH7_RyS1eZvUFSb2j3-EsceoHPi384,12467
12
+ adcp/protocols/base.py,sha256=vBHD23Fzl_CCk_Gy9nvSbBYopcJlYkYyzoz-rhI8wHg,5214
13
+ adcp/protocols/mcp.py,sha256=d9uSpGd0BKvQ0JxztkfDvHwoDrDYhuiw5oivpYOAbmM,16647
14
+ adcp/testing/__init__.py,sha256=ZWp_floWjVZfy8RBG5v_FUXQ8YbN7xjXvVcX-_zl_HU,1416
15
+ adcp/testing/test_helpers.py,sha256=4n8fZYy1cVpjZpFW2SxBzpC8fmY-MBFrzY4tIPqe4rQ,10028
16
+ adcp/types/__init__.py,sha256=FXm4210pkzOIQQEgpe-EeLLd7mxofzEgKLGl1r8fj4o,465
17
+ adcp/types/aliases.py,sha256=U3-QMWcnif9BXjB6tmM3xFL2q0BiiDFtKgqw3Zixbzo,7561
18
+ adcp/types/base.py,sha256=QoEuVfI4yzefup0dc2KN11AcJTbcGxRep7xOw5hXfs8,837
19
+ adcp/types/core.py,sha256=RXkKCWCXS9BVJTNpe3Opm5O1I_LaQPMUuVwa-ipvS1Q,4839
20
+ adcp/types/generated.py,sha256=EGwfnyTr5bgLGRS0TAdsoipX__BPMEwPfxto8quPbYw,17218
21
+ adcp/types/generated_poc/__init__.py,sha256=d6d0uXG6VkArqJj_sd6XpUMDcHU6-ARk210TCDKeQD4,103
22
+ adcp/types/generated_poc/activate_signal_request.py,sha256=8zlkyPJampuGplIXKhPaLf_hgv5_cqGyHNVP8u5lyMs,1188
23
+ adcp/types/generated_poc/activate_signal_response.py,sha256=4R_MXLmzDaPARAlmSptaEqwzHfLiL6WgF5IYKDE0TBY,2015
24
+ adcp/types/generated_poc/activation_key.py,sha256=JFRWrPF4moOCm_Sfo12qORPTl3_gkWSuzbrSQyBgSRc,952
25
+ adcp/types/generated_poc/adagents.py,sha256=9nLxI7O8JVKuwEBmsllGNPI4D7YhXX_k2U67Tzku4Jg,8490
26
+ adcp/types/generated_poc/asset_type.py,sha256=bZhN1MEgPsK4YIuth-SybBm-OcqSqsEdmEeK273JJr4,3169
27
+ adcp/types/generated_poc/audio_asset.py,sha256=kFhVjowYVtgJVYcGVBSjQmj_jVMVfdY9tzDnSY649mA,795
28
+ adcp/types/generated_poc/brand_manifest.py,sha256=qQ6dpC2QQgzesRg6-kISaEoZi7MjlpxhJdKA6-MCP1U,9723
29
+ adcp/types/generated_poc/brand_manifest_ref.py,sha256=OfCcjNqgs2P6Zlgzpdk5y-hvWh71XCN67NIYXgaJmRY,15468
30
+ adcp/types/generated_poc/build_creative_request.py,sha256=KliEQyTg-66E-mUTL5fJFd8mzVAkS6P3EU2l1_KF_wI,1726
31
+ adcp/types/generated_poc/build_creative_response.py,sha256=T3wtqoPBGJZDQEucvHGgtlIfHRihsqL3n2tsSnbYaNI,1926
32
+ adcp/types/generated_poc/channels.py,sha256=YU9Q-jcthLFBLDW-vM6QVmzvtHghka9FwZGNVlM1-w8,386
33
+ adcp/types/generated_poc/cpc_option.py,sha256=7FRVzMjOciFBlUVyrNUHWZj15ZXr-_pPwaCcJsnPYQg,1168
34
+ adcp/types/generated_poc/cpcv_option.py,sha256=m8RQCA5nn6bEcjL64PZ3Vzt5fW3bnDFlwhEMvhIhBzI,1229
35
+ adcp/types/generated_poc/cpm_auction_option.py,sha256=_lD5RRE28yqnRFQKoAd8PWfYyrtp6UF2doPmFxRTwAY,1832
36
+ adcp/types/generated_poc/cpm_fixed_option.py,sha256=GgNFIAqg0FJHWTvHfEo8g8k-PaLKYwI5ep69_7wOkuI,1212
37
+ adcp/types/generated_poc/cpp_option.py,sha256=1_w6clFqWxrYOXN-ibJndcI-jSNOYZQOX_qLrpClPLU,1924
38
+ adcp/types/generated_poc/cpv_option.py,sha256=QU-RiZ27TgPDBLSeJs5uJ0TdHuayvIGkkAdkQcED5No,2028
39
+ adcp/types/generated_poc/create_media_buy_request.py,sha256=ImuhW7tcDi4O67do6WaqxlXHRxZm3ZUnkK_uHT0CMco,3533
40
+ adcp/types/generated_poc/create_media_buy_response.py,sha256=enfFSm4vYJdh75xLTu4SLGPX55_nAR9ZmBb_l-NSbc8,2469
41
+ adcp/types/generated_poc/creative_asset.py,sha256=0QFKsEIVQzcGKTR5EnNVVT9jKvyPBYY1YvIXzwOPiM0,2663
42
+ adcp/types/generated_poc/creative_assignment.py,sha256=RfuYwkhkMcTypU1_adE6O2ngLChcFpnRyDn5pGdmYAU,933
43
+ adcp/types/generated_poc/creative_manifest.py,sha256=tcIeqkHqybljVFVta5hfsNggcvV_doJ5gfGq73lHz3Q,2155
44
+ adcp/types/generated_poc/creative_policy.py,sha256=JSCEiQNw09m_HDkHkh8V5xR_XLuax_p0V_8xclcFtGU,909
45
+ adcp/types/generated_poc/creative_status.py,sha256=yADbaEynrN7rotbZ7AU8QzRQOCms7diHNcoVoi_mT6M,320
46
+ adcp/types/generated_poc/css_asset.py,sha256=XeUrBwfaqChrKT2KxxMuGSAKR5ZpY1a5iCsphH5HCp8,535
47
+ adcp/types/generated_poc/daast_asset.py,sha256=iYi6KpCP8x4Eyl66DL_UiK1MwN365YIoMY8j6cSwl9o,2401
48
+ adcp/types/generated_poc/delivery_metrics.py,sha256=uJR7ydkE8BEL-QR7jg1op4d6jbkr9HHHATph4QB2QNc,4468
49
+ adcp/types/generated_poc/delivery_type.py,sha256=QHnUetxoVtXIz46ATnL6Y0eClhUfqG-GiFUeoi55dz4,264
50
+ adcp/types/generated_poc/deployment.py,sha256=jLXbyT0CjGSa2LIdAVzhi5rnc1gaB1qMDkLzNTmdbLY,2866
51
+ adcp/types/generated_poc/destination.py,sha256=ImO_5RywSilO2nOi62g5C2Tp1A8Cghhh6_rBHS3XIc8,1278
52
+ adcp/types/generated_poc/error.py,sha256=EFwRojmMLJzuTa3Bq705-R07h3k0aUO0LtvvNPCvBSs,1014
53
+ adcp/types/generated_poc/flat_rate_option.py,sha256=SrWw8GDckretlNsGruidlSY6AssJYaOGWgnxbnY6aKM,2967
54
+ adcp/types/generated_poc/format.py,sha256=oElkmwngTCy9M8FpYUInWRgKgb0wdrNj94AzkNHOtuE,9440
55
+ adcp/types/generated_poc/format_id.py,sha256=XEZJQ2UlH-WoIn6XKHHEfXfhDPW9JctO2eMyNHp-SHs,864
56
+ adcp/types/generated_poc/frequency_cap.py,sha256=pCLC16QBlGY5asJ3L5Zipdspl7wBNuTPKwCGSlPCewI,475
57
+ adcp/types/generated_poc/frequency_cap_scope.py,sha256=kzcqOAE39TMaaBxJyIZqiBVnAtCcSvJvcwQAE52enEM,437
58
+ adcp/types/generated_poc/get_media_buy_delivery_request.py,sha256=tv2fFJFwhuGvw-6vEu_a-81tGnwFRzTJSas26Mt02_w,1933
59
+ adcp/types/generated_poc/get_media_buy_delivery_response.py,sha256=Tkc9zgbLJQUU7DzcaZEcx7BZfMaFElmKYRZK8gn0b7U,8164
60
+ adcp/types/generated_poc/get_products_request.py,sha256=PfradwAXM42m3XV1K-VUkEcetCbBleRhC1Q_R0qfB5E,2920
61
+ adcp/types/generated_poc/get_products_response.py,sha256=7dpIW73iejDMJggGt5iya7_eNQT2LmGSlEonyRcqhyw,934
62
+ adcp/types/generated_poc/get_signals_request.py,sha256=etn_7H0Hn9-mA7WjeEyKPDc-LCCJbBbEiuFZzmsOdzw,2558
63
+ adcp/types/generated_poc/get_signals_response.py,sha256=8kz9ycKDgRGmaQPLNnxdq0Kby1yuLyJ8KO58xgmOrxQ,2211
64
+ adcp/types/generated_poc/html_asset.py,sha256=1bMlSgeO-g8ePRgTgq64MqRr5QFNO4QAS3VXJvWzEos,505
65
+ adcp/types/generated_poc/identifier_types.py,sha256=bmT7o_KQOiYt3_lsxwaGjMaNQzsOt2QYlLaWq_Jgyf4,860
66
+ adcp/types/generated_poc/image_asset.py,sha256=7Yoa5K93H3p8n0_epJ8uM1G_TYTaSdOVzXbyqHZu20I,836
67
+ adcp/types/generated_poc/index.py,sha256=bNMI2MCYUahcUoWf3JJOES1mhp0Cnz_ZFuo61Ax6bLU,560
68
+ adcp/types/generated_poc/javascript_asset.py,sha256=HnPD0p8_CcNf9ELZ8RWJMsrSjHKKieqspEUcrFn9CHA,640
69
+ adcp/types/generated_poc/list_authorized_properties_request.py,sha256=TwSZznEBL15GUNlVfgXBNktXaEWZFuH2Mrhtand0uA4,1283
70
+ adcp/types/generated_poc/list_authorized_properties_response.py,sha256=y6kxZDvjPu31c8j5KUR_0a_gJhmI0XTZPvFFG2h9_50,3260
71
+ adcp/types/generated_poc/list_creative_formats_request.py,sha256=0TC38knPXV-hZmFd33JMqlxNR-qT2eueu88ASwx56-8,3088
72
+ adcp/types/generated_poc/list_creative_formats_response.py,sha256=3sl540GPgFrCRkApLacjpqphNdSos5DMmUfEJ_1_Tgo,2136
73
+ adcp/types/generated_poc/list_creatives_request.py,sha256=Ke5bxN5EubDvMEYtvpd2ZSSANwa82Jh52OSGOKej8h0,5319
74
+ adcp/types/generated_poc/list_creatives_response.py,sha256=T1VyU1gYyBzLrTQNOA5Pf89zTXftoOCD3R4GUE6xgQw,8088
75
+ adcp/types/generated_poc/markdown_asset.py,sha256=OYN2frFau32Cu3GlfCnFWHdfYGUvnJ6l8clWjLtCJVg,1215
76
+ adcp/types/generated_poc/measurement.py,sha256=3cxg9O2LZbiv7KjTubU0PNA4MugogPy-1sh0Gc46tZ4,1051
77
+ adcp/types/generated_poc/media_buy.py,sha256=rsaNF7Bi-fICdDLwF_uaAeX8Zi57VN2IhzcfCLmM5ak,1368
78
+ adcp/types/generated_poc/media_buy_status.py,sha256=y6j7Clpnn9sZsDX3iL1G7LQfh-LaSjcKtJA3IT_GpKY,319
79
+ adcp/types/generated_poc/pacing.py,sha256=BgDmzHA3ynqArDEbW2pq9A80_B3QAskb01AW2GS5glM,253
80
+ adcp/types/generated_poc/package.py,sha256=lOPnovO9IzKv3DAk1cGNiZH2FWfuHlerkSx4uGc-w1s,2074
81
+ adcp/types/generated_poc/package_request.py,sha256=u_25V3vrInReg80qHbjlbHTxV3v61-OYqNt3R5HoPH8,2171
82
+ adcp/types/generated_poc/package_status.py,sha256=6ZYBdKqYle7QSL0ni3ZwHqmLTIJxHfZL8WQh5bIBhjo,290
83
+ adcp/types/generated_poc/performance_feedback.py,sha256=CI601JYkllL5n82OayYGbOyureJ3MaswDTVSQ55uFoc,2923
84
+ adcp/types/generated_poc/placement.py,sha256=LvdAVR2HN1nZMsoEkLha3AKt2aczt41-dO08Fr2typM,1052
85
+ adcp/types/generated_poc/preview_creative_request.py,sha256=MA885DHNKBlVRI473aE2sBnfDdhbmSQxpno4bXd5cGk,6059
86
+ adcp/types/generated_poc/preview_creative_response.py,sha256=EAPDyMCYpVC8pbIlpHkrTJlHESTJlHReewTJtTv7O7M,6140
87
+ adcp/types/generated_poc/preview_render.py,sha256=ryBJsjSy7yS_1V9hcYu2mRgK5apAYgi2kYQ7zAycWuE,5024
88
+ adcp/types/generated_poc/pricing_model.py,sha256=ktmIGrqCigaC6S5ctSIj401DUbxcpWEsayejhtg1yz8,324
89
+ adcp/types/generated_poc/pricing_option.py,sha256=W3Paxdxqij2x5mlQlXLhI5u1aXDiEZ2GPP8_NWJdOB4,12447
90
+ adcp/types/generated_poc/product.py,sha256=Lrpwv-acTONRL82dt1SEI-g43XfkJ-16kLtsqEYWIXU,7639
91
+ adcp/types/generated_poc/promoted_offerings.py,sha256=QhjwUEMrKikE50u-98EJ_ZihVKTj_rU0AfR6X3QEkYI,3227
92
+ adcp/types/generated_poc/promoted_products.py,sha256=wXeuc2Sf7nhSmiarPHDZ3gPPdp0zS0rkEHFG2N3Sejo,1252
93
+ adcp/types/generated_poc/property.py,sha256=Di-jsdwpl44-CGk3Zk8OBUwb8kbmClBhq2DxxPJSTbg,2563
94
+ adcp/types/generated_poc/protocol_envelope.py,sha256=7Cb7UddkRcZaFsNpX-3YLV4GhvIhxst2xxrsqlo9fIc,2715
95
+ adcp/types/generated_poc/provide_performance_feedback_request.py,sha256=js69ABROv1bjwnIOqYzRHFA17j6t3nH_f6vTmfH4brY,2820
96
+ adcp/types/generated_poc/provide_performance_feedback_response.py,sha256=V2d1s2jTdsqjGpceQnf1ZgBEbRRCePAXwIpsur-nzjA,1973
97
+ adcp/types/generated_poc/publisher_identifier_types.py,sha256=MGPR-RjZ9y_dZOen95Zchu_kP3MCc1EmpDWRuzbA4kE,321
98
+ adcp/types/generated_poc/push_notification_config.py,sha256=S9d4el3u1JDwGAk4NriGDZlXGzheuizsrsB2iymwFDw,1732
99
+ adcp/types/generated_poc/reporting_capabilities.py,sha256=ii2aLVOxi9URkAViqrSPDFBCXXqwODlXuxojZ2zqSRo,2107
100
+ adcp/types/generated_poc/response.py,sha256=IvTnxhwrfrPWZnmlcpvWN_cgkJQcjq_biW5Q5LW9geY,707
101
+ adcp/types/generated_poc/standard_format_ids.py,sha256=CZ4pRNkUREPXv-opgDT_L_R4LxsAUDDnbMOCYY50Ct4,1921
102
+ adcp/types/generated_poc/start_timing.py,sha256=PEedDJUtaYg9WMA8A_USadYGZduTjXtZRaDwcdQvkPs,397
103
+ adcp/types/generated_poc/sub_asset.py,sha256=RHYmabfVPVcChJ0hEiE7DLnSCwL5-NutncZ_lfk4De0,1666
104
+ adcp/types/generated_poc/sync_creatives_request.py,sha256=uNZtnLocfqNZwbCYOZCd8qdAiC04pKTR-QIUzMGf_gs,2563
105
+ adcp/types/generated_poc/sync_creatives_response.py,sha256=rRjP2f84Cd1JpyPRW4vYINvEluq1eabUOUERbGGFbLI,4096
106
+ adcp/types/generated_poc/targeting.py,sha256=-KBOizlTIhROQkk1Rt8-3i3vb5hixM7moHTfP5LxWuw,1743
107
+ adcp/types/generated_poc/task_status.py,sha256=jqXuwlkMwFoJaVZthrP1PpQ1kOsiKrRTcTjwo7R49II,444
108
+ adcp/types/generated_poc/task_type.py,sha256=wFanzM0Lib8i8v7PXoO-gUBM8igynCfP86p99m1E8fA,382
109
+ adcp/types/generated_poc/tasks_get_request.py,sha256=enkox69QoUQSINQZ9ckdlgmli-kx1V-jpCgJnmohBAI,973
110
+ adcp/types/generated_poc/tasks_get_response.py,sha256=KLlliUYMdOsOEzzEHiJkQJ9fdMFo-MD_e0wCG3oXkn8,3988
111
+ adcp/types/generated_poc/tasks_list_request.py,sha256=wjH8sV_msjjI7aosk8gI6Ape1xzrNcpUZ-9Dx4yzGhQ,4083
112
+ adcp/types/generated_poc/tasks_list_response.py,sha256=qhKzICjB8sMHWRXhNFV-c6S1LODjx7usCTPpF62G7jU,4063
113
+ adcp/types/generated_poc/text_asset.py,sha256=dY9kYUNlXzyjTVDQQvOr9ZdjrmpMYsqfM5DFQUWLJTY,532
114
+ adcp/types/generated_poc/update_media_buy_request.py,sha256=Wkb0N3SMybofpTP5ktrJeZe8-K1YjKozQu7tf_r2aP8,6071
115
+ adcp/types/generated_poc/update_media_buy_response.py,sha256=srFXZTZOmMXx8pBKnh4d0e0haJMiOQD3RnzNUmzRMeA,2506
116
+ adcp/types/generated_poc/url_asset.py,sha256=b9VxwAvvGCcYREwYlbgj47j8tZI9DZNFA39TYNovIps,1114
117
+ adcp/types/generated_poc/vast_asset.py,sha256=2fOBI-Go9HRVt2GHNop7w25wpNxCrmhEOF21cbY5X_4,2679
118
+ adcp/types/generated_poc/vcpm_auction_option.py,sha256=cTtK61hUcCC0PERql660qApTDjtT2Du4f9z6mfs_xWQ,1866
119
+ adcp/types/generated_poc/vcpm_fixed_option.py,sha256=Thc3RTo7_jaOHrqeQzxup0n8ibK7xg0zVM7bJbzH2HI,1278
120
+ adcp/types/generated_poc/video_asset.py,sha256=Nfj-ea5C8yRuVFBSOw9wW2vG2diIJTYn4zRw42lFoKY,978
121
+ adcp/types/generated_poc/webhook_asset.py,sha256=urQuXkPe0nzo7ZXovijSH-kGmVZI5HUkTkDfqBdFK7w,1935
122
+ adcp/types/generated_poc/webhook_payload.py,sha256=8VFvROPthmK4tYT2ELXm1trRFH-_ioE2fn7JfkDJ86U,3563
123
+ adcp/utils/__init__.py,sha256=uetvSJB19CjQbtwEYZiTnumJG11GsafQmXm5eR3hL7E,153
124
+ adcp/utils/operation_id.py,sha256=wQX9Bb5epXzRq23xoeYPTqzu5yLuhshg7lKJZihcM2k,294
125
+ adcp/utils/preview_cache.py,sha256=HbYgHMLIvDddFD6HSupGUze9YLsNOBPlbwlyogUOMcs,18498
126
+ adcp/utils/response_parser.py,sha256=uPk2vIH-RYZmq7y3i8lC4HTMQ3FfKdlgXKTjgJ1955M,6253
127
+ adcp-2.1.0.dist-info/licenses/LICENSE,sha256=PF39NR3Ae8PLgBhg3Uxw6ju7iGVIf8hfv9LRWQdii_U,629
128
+ adcp-2.1.0.dist-info/METADATA,sha256=pnih_Vvk8NMhChX8PXduKloMPSU2E-lqsbubUX5_xJ8,23017
129
+ adcp-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
130
+ adcp-2.1.0.dist-info/entry_points.txt,sha256=DQKpcGsJX8DtVI_SGApQ7tNvqUB4zkTLaTAEpFgmi3U,44
131
+ adcp-2.1.0.dist-info/top_level.txt,sha256=T1_NF0GefncFU9v_k56oDwKSJREyCqIM8lAwNZf0EOs,5
132
+ adcp-2.1.0.dist-info/RECORD,,