adcp 2.12.1__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.
Files changed (149) hide show
  1. adcp/__init__.py +2 -1
  2. adcp/protocols/a2a.py +315 -204
  3. adcp/protocols/mcp.py +95 -16
  4. adcp/types/_generated.py +476 -97
  5. adcp/types/aliases.py +1 -3
  6. adcp/types/base.py +193 -0
  7. adcp/types/generated_poc/adagents.py +1 -1
  8. adcp/types/generated_poc/core/activation_key.py +1 -1
  9. adcp/types/generated_poc/core/assets/audio_asset.py +1 -1
  10. adcp/types/generated_poc/core/assets/css_asset.py +1 -1
  11. adcp/types/generated_poc/core/assets/daast_asset.py +1 -1
  12. adcp/types/generated_poc/core/assets/html_asset.py +1 -1
  13. adcp/types/generated_poc/core/assets/image_asset.py +1 -1
  14. adcp/types/generated_poc/core/assets/javascript_asset.py +1 -1
  15. adcp/types/generated_poc/core/assets/text_asset.py +1 -1
  16. adcp/types/generated_poc/core/assets/url_asset.py +1 -1
  17. adcp/types/generated_poc/core/assets/vast_asset.py +1 -1
  18. adcp/types/generated_poc/core/assets/video_asset.py +1 -1
  19. adcp/types/generated_poc/core/assets/webhook_asset.py +1 -1
  20. adcp/types/generated_poc/core/brand_manifest.py +1 -1
  21. adcp/types/generated_poc/core/context.py +1 -1
  22. adcp/types/generated_poc/core/creative_asset.py +1 -1
  23. adcp/types/generated_poc/core/creative_assignment.py +1 -1
  24. adcp/types/generated_poc/core/creative_filters.py +1 -1
  25. adcp/types/generated_poc/core/creative_manifest.py +1 -1
  26. adcp/types/generated_poc/core/creative_policy.py +1 -1
  27. adcp/types/generated_poc/core/delivery_metrics.py +1 -1
  28. adcp/types/generated_poc/core/deployment.py +1 -1
  29. adcp/types/generated_poc/core/destination.py +1 -1
  30. adcp/types/generated_poc/core/dimensions.py +1 -1
  31. adcp/types/generated_poc/core/error.py +1 -1
  32. adcp/types/generated_poc/core/ext.py +1 -1
  33. adcp/types/generated_poc/core/format.py +1 -1
  34. adcp/types/generated_poc/core/format_id.py +1 -1
  35. adcp/types/generated_poc/core/frequency_cap.py +1 -1
  36. adcp/types/generated_poc/core/measurement.py +1 -1
  37. adcp/types/generated_poc/core/media_buy.py +1 -1
  38. adcp/types/generated_poc/core/package.py +1 -1
  39. adcp/types/generated_poc/core/performance_feedback.py +1 -1
  40. adcp/types/generated_poc/core/placement.py +1 -1
  41. adcp/types/generated_poc/core/product.py +1 -1
  42. adcp/types/generated_poc/core/product_filters.py +1 -1
  43. adcp/types/generated_poc/core/promoted_offerings.py +1 -1
  44. adcp/types/generated_poc/core/promoted_products.py +1 -1
  45. adcp/types/generated_poc/core/property.py +1 -1
  46. adcp/types/generated_poc/core/property_id.py +1 -1
  47. adcp/types/generated_poc/core/property_tag.py +1 -1
  48. adcp/types/generated_poc/core/protocol_envelope.py +1 -1
  49. adcp/types/generated_poc/core/publisher_property_selector.py +1 -1
  50. adcp/types/generated_poc/core/push_notification_config.py +1 -1
  51. adcp/types/generated_poc/core/reporting_capabilities.py +1 -1
  52. adcp/types/generated_poc/core/response.py +1 -1
  53. adcp/types/generated_poc/core/signal_filters.py +1 -1
  54. adcp/types/generated_poc/core/sub_asset.py +1 -1
  55. adcp/types/generated_poc/core/targeting.py +1 -1
  56. adcp/types/generated_poc/core/webhook_payload.py +1 -1
  57. adcp/types/generated_poc/creative/list_creative_formats_request.py +1 -1
  58. adcp/types/generated_poc/creative/list_creative_formats_response.py +1 -1
  59. adcp/types/generated_poc/creative/preview_creative_request.py +1 -1
  60. adcp/types/generated_poc/creative/preview_creative_response.py +1 -1
  61. adcp/types/generated_poc/creative/preview_render.py +1 -1
  62. adcp/types/generated_poc/enums/adcp_domain.py +1 -1
  63. adcp/types/generated_poc/enums/asset_content_type.py +1 -1
  64. adcp/types/generated_poc/enums/auth_scheme.py +1 -1
  65. adcp/types/generated_poc/enums/available_metric.py +1 -1
  66. adcp/types/generated_poc/enums/channels.py +1 -1
  67. adcp/types/generated_poc/enums/co_branding_requirement.py +1 -1
  68. adcp/types/generated_poc/enums/creative_action.py +1 -1
  69. adcp/types/generated_poc/enums/creative_agent_capability.py +1 -1
  70. adcp/types/generated_poc/enums/creative_sort_field.py +1 -1
  71. adcp/types/generated_poc/enums/creative_status.py +1 -1
  72. adcp/types/generated_poc/enums/daast_tracking_event.py +1 -1
  73. adcp/types/generated_poc/enums/daast_version.py +1 -1
  74. adcp/types/generated_poc/enums/delivery_type.py +1 -1
  75. adcp/types/generated_poc/enums/dimension_unit.py +1 -1
  76. adcp/types/generated_poc/enums/feed_format.py +1 -1
  77. adcp/types/generated_poc/enums/feedback_source.py +1 -1
  78. adcp/types/generated_poc/enums/format_category.py +1 -1
  79. adcp/types/generated_poc/enums/format_id_parameter.py +1 -1
  80. adcp/types/generated_poc/enums/frequency_cap_scope.py +1 -1
  81. adcp/types/generated_poc/enums/history_entry_type.py +1 -1
  82. adcp/types/generated_poc/enums/http_method.py +1 -1
  83. adcp/types/generated_poc/enums/identifier_types.py +1 -1
  84. adcp/types/generated_poc/enums/javascript_module_type.py +1 -1
  85. adcp/types/generated_poc/enums/landing_page_requirement.py +1 -1
  86. adcp/types/generated_poc/enums/markdown_flavor.py +1 -1
  87. adcp/types/generated_poc/enums/media_buy_status.py +1 -1
  88. adcp/types/generated_poc/enums/metric_type.py +1 -1
  89. adcp/types/generated_poc/enums/notification_type.py +1 -1
  90. adcp/types/generated_poc/enums/pacing.py +1 -1
  91. adcp/types/generated_poc/enums/preview_output_format.py +1 -1
  92. adcp/types/generated_poc/enums/pricing_model.py +1 -1
  93. adcp/types/generated_poc/enums/property_type.py +1 -1
  94. adcp/types/generated_poc/enums/publisher_identifier_types.py +1 -1
  95. adcp/types/generated_poc/enums/reporting_frequency.py +1 -1
  96. adcp/types/generated_poc/enums/signal_catalog_type.py +1 -1
  97. adcp/types/generated_poc/enums/sort_direction.py +1 -1
  98. adcp/types/generated_poc/enums/standard_format_ids.py +1 -1
  99. adcp/types/generated_poc/enums/task_status.py +1 -1
  100. adcp/types/generated_poc/enums/task_type.py +1 -1
  101. adcp/types/generated_poc/enums/update_frequency.py +1 -1
  102. adcp/types/generated_poc/enums/url_asset_type.py +1 -1
  103. adcp/types/generated_poc/enums/validation_mode.py +1 -1
  104. adcp/types/generated_poc/enums/vast_tracking_event.py +1 -1
  105. adcp/types/generated_poc/enums/vast_version.py +1 -1
  106. adcp/types/generated_poc/enums/webhook_response_type.py +1 -1
  107. adcp/types/generated_poc/enums/webhook_security_method.py +1 -1
  108. adcp/types/generated_poc/media_buy/build_creative_request.py +1 -1
  109. adcp/types/generated_poc/media_buy/build_creative_response.py +1 -1
  110. adcp/types/generated_poc/media_buy/create_media_buy_request.py +1 -1
  111. adcp/types/generated_poc/media_buy/create_media_buy_response.py +1 -1
  112. adcp/types/generated_poc/media_buy/get_media_buy_delivery_request.py +1 -1
  113. adcp/types/generated_poc/media_buy/get_media_buy_delivery_response.py +1 -1
  114. adcp/types/generated_poc/media_buy/get_products_request.py +1 -1
  115. adcp/types/generated_poc/media_buy/get_products_response.py +1 -1
  116. adcp/types/generated_poc/media_buy/list_authorized_properties_request.py +1 -1
  117. adcp/types/generated_poc/media_buy/list_authorized_properties_response.py +1 -1
  118. adcp/types/generated_poc/media_buy/list_creative_formats_request.py +1 -1
  119. adcp/types/generated_poc/media_buy/list_creative_formats_response.py +1 -1
  120. adcp/types/generated_poc/media_buy/list_creatives_request.py +1 -1
  121. adcp/types/generated_poc/media_buy/list_creatives_response.py +1 -1
  122. adcp/types/generated_poc/media_buy/package_request.py +1 -1
  123. adcp/types/generated_poc/media_buy/provide_performance_feedback_request.py +1 -1
  124. adcp/types/generated_poc/media_buy/provide_performance_feedback_response.py +1 -1
  125. adcp/types/generated_poc/media_buy/sync_creatives_request.py +1 -1
  126. adcp/types/generated_poc/media_buy/sync_creatives_response.py +1 -1
  127. adcp/types/generated_poc/media_buy/update_media_buy_request.py +1 -1
  128. adcp/types/generated_poc/media_buy/update_media_buy_response.py +1 -1
  129. adcp/types/generated_poc/pricing_options/cpc_option.py +1 -1
  130. adcp/types/generated_poc/pricing_options/cpcv_option.py +1 -1
  131. adcp/types/generated_poc/pricing_options/cpm_auction_option.py +1 -1
  132. adcp/types/generated_poc/pricing_options/cpm_fixed_option.py +1 -1
  133. adcp/types/generated_poc/pricing_options/cpp_option.py +1 -1
  134. adcp/types/generated_poc/pricing_options/cpv_option.py +1 -1
  135. adcp/types/generated_poc/pricing_options/flat_rate_option.py +1 -1
  136. adcp/types/generated_poc/pricing_options/vcpm_auction_option.py +1 -1
  137. adcp/types/generated_poc/pricing_options/vcpm_fixed_option.py +1 -1
  138. adcp/types/generated_poc/protocols/adcp_extension.py +1 -1
  139. adcp/types/generated_poc/signals/activate_signal_request.py +1 -1
  140. adcp/types/generated_poc/signals/activate_signal_response.py +1 -1
  141. adcp/types/generated_poc/signals/get_signals_request.py +1 -1
  142. adcp/types/generated_poc/signals/get_signals_response.py +1 -1
  143. {adcp-2.12.1.dist-info → adcp-2.13.0.dist-info}/METADATA +1 -1
  144. adcp-2.13.0.dist-info/RECORD +176 -0
  145. adcp-2.12.1.dist-info/RECORD +0 -176
  146. {adcp-2.12.1.dist-info → adcp-2.13.0.dist-info}/WHEEL +0 -0
  147. {adcp-2.12.1.dist-info → adcp-2.13.0.dist-info}/entry_points.txt +0 -0
  148. {adcp-2.12.1.dist-info → adcp-2.13.0.dist-info}/licenses/LICENSE +0 -0
  149. {adcp-2.12.1.dist-info → adcp-2.13.0.dist-info}/top_level.txt +0 -0
adcp/protocols/mcp.py CHANGED
@@ -9,6 +9,16 @@ from contextlib import AsyncExitStack
9
9
  from typing import TYPE_CHECKING, Any
10
10
  from urllib.parse import urlparse
11
11
 
12
+ # ExceptionGroup and BaseExceptionGroup are available in Python 3.11+
13
+ # In 3.11+, they're built-in types. For 3.10, we need to handle their absence.
14
+ try:
15
+ _ExceptionGroup: type[BaseException] | None = ExceptionGroup # type: ignore[name-defined]
16
+ _BaseExceptionGroup: type[BaseException] | None = BaseExceptionGroup # type: ignore[name-defined]
17
+ except NameError:
18
+ # Python 3.10 - ExceptionGroup doesn't exist
19
+ _ExceptionGroup = None
20
+ _BaseExceptionGroup = None
21
+
12
22
  logger = logging.getLogger(__name__)
13
23
 
14
24
  if TYPE_CHECKING:
@@ -23,6 +33,14 @@ try:
23
33
  except ImportError:
24
34
  MCP_AVAILABLE = False
25
35
 
36
+ try:
37
+ from httpx import HTTPStatusError
38
+
39
+ HTTPX_AVAILABLE = True
40
+ except ImportError:
41
+ HTTPX_AVAILABLE = False
42
+ HTTPStatusError = None # type: ignore[assignment, misc]
43
+
26
44
  from adcp.exceptions import ADCPConnectionError, ADCPTimeoutError
27
45
  from adcp.protocols.base import ProtocolAdapter
28
46
  from adcp.types.core import DebugInfo, TaskResult, TaskStatus
@@ -56,23 +74,80 @@ class MCPAdapter(ProtocolAdapter):
56
74
  self._session = None
57
75
  try:
58
76
  await old_stack.aclose()
59
- except asyncio.CancelledError:
60
- logger.debug(f"MCP session cleanup cancelled {context}")
61
- except RuntimeError as cleanup_error:
62
- # Known anyio task group cleanup issue
63
- error_msg = str(cleanup_error).lower()
64
- if "cancel scope" in error_msg or "async context" in error_msg:
65
- logger.debug(f"Ignoring anyio cleanup error {context}: {cleanup_error}")
66
- else:
67
- logger.warning(
68
- f"Unexpected RuntimeError during cleanup {context}: {cleanup_error}"
69
- )
70
- except Exception as cleanup_error:
71
- # Log unexpected cleanup errors but don't raise to preserve original error
72
- logger.warning(
73
- f"Unexpected error during cleanup {context}: {cleanup_error}", exc_info=True
77
+ except BaseException as cleanup_error:
78
+ # Handle all cleanup errors including ExceptionGroup
79
+ # Re-raise KeyboardInterrupt and SystemExit immediately
80
+ if isinstance(cleanup_error, (KeyboardInterrupt, SystemExit)):
81
+ raise
82
+
83
+ if isinstance(cleanup_error, asyncio.CancelledError):
84
+ logger.debug(f"MCP session cleanup cancelled {context}")
85
+ return
86
+
87
+ # Handle ExceptionGroup/BaseExceptionGroup from task group failures (Python 3.11+)
88
+ # ExceptionGroup: for Exception subclasses (e.g., HTTPStatusError)
89
+ # BaseExceptionGroup: for BaseException subclasses (e.g., CancelledError)
90
+ # We need both because CancelledError is a BaseException, not an Exception
91
+ is_exception_group = (
92
+ _ExceptionGroup is not None and isinstance(cleanup_error, _ExceptionGroup)
93
+ ) or (
94
+ _BaseExceptionGroup is not None
95
+ and isinstance(cleanup_error, _BaseExceptionGroup)
74
96
  )
75
97
 
98
+ if is_exception_group:
99
+ # Check if all exceptions in the group are CancelledError
100
+ # If so, treat the entire group as a cancellation
101
+ all_cancelled = all(
102
+ isinstance(exc, asyncio.CancelledError)
103
+ for exc in cleanup_error.exceptions # type: ignore[attr-defined]
104
+ )
105
+ if all_cancelled:
106
+ logger.debug(f"MCP session cleanup cancelled {context}")
107
+ return
108
+
109
+ # Mixed group: skip CancelledErrors and log real errors
110
+ exceptions = cleanup_error.exceptions # type: ignore[attr-defined]
111
+ cancelled_errors = [
112
+ exc for exc in exceptions if isinstance(exc, asyncio.CancelledError)
113
+ ]
114
+ cancelled_count = len(cancelled_errors)
115
+ if cancelled_count > 0:
116
+ logger.debug(
117
+ f"Skipping {cancelled_count} CancelledError(s) "
118
+ f"in mixed exception group {context}"
119
+ )
120
+
121
+ # Log each non-cancelled exception individually
122
+ for exc in exceptions:
123
+ if not isinstance(exc, asyncio.CancelledError):
124
+ self._log_cleanup_error(exc, context)
125
+ else:
126
+ self._log_cleanup_error(cleanup_error, context)
127
+
128
+ def _log_cleanup_error(self, exc: BaseException, context: str) -> None:
129
+ """Log a cleanup error without raising."""
130
+ # Check for known cleanup error patterns from httpx/anyio
131
+ exc_str = str(exc).lower()
132
+
133
+ # Common cleanup errors that are expected when connection fails
134
+ is_known_cleanup_error = (
135
+ isinstance(exc, RuntimeError)
136
+ and ("cancel scope" in exc_str or "async context" in exc_str)
137
+ ) or (
138
+ # HTTP errors during cleanup (if httpx is available)
139
+ HTTPX_AVAILABLE
140
+ and HTTPStatusError is not None
141
+ and isinstance(exc, HTTPStatusError)
142
+ )
143
+
144
+ if is_known_cleanup_error:
145
+ # Expected cleanup errors - log at debug level without stack trace
146
+ logger.debug(f"Ignoring expected cleanup error {context}: {exc}")
147
+ else:
148
+ # Truly unexpected cleanup errors - log at warning with full context
149
+ logger.warning(f"Unexpected error during cleanup {context}: {exc}", exc_info=True)
150
+
76
151
  async def _get_session(self) -> ClientSession:
77
152
  """
78
153
  Get or create MCP client session with URL fallback handling.
@@ -146,7 +221,11 @@ class MCPAdapter(ProtocolAdapter):
146
221
  )
147
222
 
148
223
  return self._session # type: ignore[no-any-return]
149
- except Exception as e:
224
+ except BaseException as e:
225
+ # Catch BaseException to handle CancelledError from failed initialization
226
+ # Re-raise KeyboardInterrupt and SystemExit immediately
227
+ if isinstance(e, (KeyboardInterrupt, SystemExit)):
228
+ raise
150
229
  last_error = e
151
230
  # Clean up the exit stack on failure to avoid resource leaks
152
231
  await self._cleanup_failed_connection("during connection attempt")