airbyte-agent-mailchimp 0.1.4__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 (57) hide show
  1. airbyte_agent_mailchimp/__init__.py +217 -0
  2. airbyte_agent_mailchimp/_vendored/__init__.py +1 -0
  3. airbyte_agent_mailchimp/_vendored/connector_sdk/__init__.py +82 -0
  4. airbyte_agent_mailchimp/_vendored/connector_sdk/auth_strategies.py +1120 -0
  5. airbyte_agent_mailchimp/_vendored/connector_sdk/auth_template.py +135 -0
  6. airbyte_agent_mailchimp/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
  7. airbyte_agent_mailchimp/_vendored/connector_sdk/cloud_utils/client.py +213 -0
  8. airbyte_agent_mailchimp/_vendored/connector_sdk/connector_model_loader.py +965 -0
  9. airbyte_agent_mailchimp/_vendored/connector_sdk/constants.py +78 -0
  10. airbyte_agent_mailchimp/_vendored/connector_sdk/exceptions.py +23 -0
  11. airbyte_agent_mailchimp/_vendored/connector_sdk/executor/__init__.py +31 -0
  12. airbyte_agent_mailchimp/_vendored/connector_sdk/executor/hosted_executor.py +196 -0
  13. airbyte_agent_mailchimp/_vendored/connector_sdk/executor/local_executor.py +1641 -0
  14. airbyte_agent_mailchimp/_vendored/connector_sdk/executor/models.py +190 -0
  15. airbyte_agent_mailchimp/_vendored/connector_sdk/extensions.py +693 -0
  16. airbyte_agent_mailchimp/_vendored/connector_sdk/http/__init__.py +37 -0
  17. airbyte_agent_mailchimp/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
  18. airbyte_agent_mailchimp/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
  19. airbyte_agent_mailchimp/_vendored/connector_sdk/http/config.py +98 -0
  20. airbyte_agent_mailchimp/_vendored/connector_sdk/http/exceptions.py +119 -0
  21. airbyte_agent_mailchimp/_vendored/connector_sdk/http/protocols.py +114 -0
  22. airbyte_agent_mailchimp/_vendored/connector_sdk/http/response.py +104 -0
  23. airbyte_agent_mailchimp/_vendored/connector_sdk/http_client.py +686 -0
  24. airbyte_agent_mailchimp/_vendored/connector_sdk/introspection.py +262 -0
  25. airbyte_agent_mailchimp/_vendored/connector_sdk/logging/__init__.py +11 -0
  26. airbyte_agent_mailchimp/_vendored/connector_sdk/logging/logger.py +264 -0
  27. airbyte_agent_mailchimp/_vendored/connector_sdk/logging/types.py +92 -0
  28. airbyte_agent_mailchimp/_vendored/connector_sdk/observability/__init__.py +11 -0
  29. airbyte_agent_mailchimp/_vendored/connector_sdk/observability/config.py +179 -0
  30. airbyte_agent_mailchimp/_vendored/connector_sdk/observability/models.py +19 -0
  31. airbyte_agent_mailchimp/_vendored/connector_sdk/observability/redactor.py +81 -0
  32. airbyte_agent_mailchimp/_vendored/connector_sdk/observability/session.py +103 -0
  33. airbyte_agent_mailchimp/_vendored/connector_sdk/performance/__init__.py +6 -0
  34. airbyte_agent_mailchimp/_vendored/connector_sdk/performance/instrumentation.py +57 -0
  35. airbyte_agent_mailchimp/_vendored/connector_sdk/performance/metrics.py +93 -0
  36. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/__init__.py +75 -0
  37. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/base.py +164 -0
  38. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/components.py +239 -0
  39. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/connector.py +120 -0
  40. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/extensions.py +230 -0
  41. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/operations.py +146 -0
  42. airbyte_agent_mailchimp/_vendored/connector_sdk/schema/security.py +223 -0
  43. airbyte_agent_mailchimp/_vendored/connector_sdk/secrets.py +182 -0
  44. airbyte_agent_mailchimp/_vendored/connector_sdk/telemetry/__init__.py +10 -0
  45. airbyte_agent_mailchimp/_vendored/connector_sdk/telemetry/config.py +32 -0
  46. airbyte_agent_mailchimp/_vendored/connector_sdk/telemetry/events.py +59 -0
  47. airbyte_agent_mailchimp/_vendored/connector_sdk/telemetry/tracker.py +155 -0
  48. airbyte_agent_mailchimp/_vendored/connector_sdk/types.py +245 -0
  49. airbyte_agent_mailchimp/_vendored/connector_sdk/utils.py +60 -0
  50. airbyte_agent_mailchimp/_vendored/connector_sdk/validation.py +822 -0
  51. airbyte_agent_mailchimp/connector.py +1378 -0
  52. airbyte_agent_mailchimp/connector_model.py +4749 -0
  53. airbyte_agent_mailchimp/models.py +956 -0
  54. airbyte_agent_mailchimp/types.py +164 -0
  55. airbyte_agent_mailchimp-0.1.4.dist-info/METADATA +119 -0
  56. airbyte_agent_mailchimp-0.1.4.dist-info/RECORD +57 -0
  57. airbyte_agent_mailchimp-0.1.4.dist-info/WHEEL +4 -0
@@ -0,0 +1,37 @@
1
+ """HTTP abstraction layer for the Airbyte SDK.
2
+
3
+ This package provides a client-agnostic HTTP interface that allows the SDK to work
4
+ with different HTTP client implementations (httpx, aiohttp, etc.) while maintaining
5
+ a consistent API.
6
+ """
7
+
8
+ from .config import ClientConfig, ConnectionLimits, TimeoutConfig
9
+ from .exceptions import (
10
+ AuthenticationError,
11
+ HTTPClientError,
12
+ HTTPStatusError,
13
+ NetworkError,
14
+ RateLimitError,
15
+ TimeoutError,
16
+ )
17
+ from .protocols import HTTPClientProtocol, HTTPResponseProtocol
18
+ from .response import HTTPResponse
19
+
20
+ __all__ = [
21
+ # Configuration
22
+ "ClientConfig",
23
+ "ConnectionLimits",
24
+ "TimeoutConfig",
25
+ # Protocols
26
+ "HTTPClientProtocol",
27
+ "HTTPResponseProtocol",
28
+ # Response
29
+ "HTTPResponse",
30
+ # Exceptions
31
+ "HTTPClientError",
32
+ "HTTPStatusError",
33
+ "AuthenticationError",
34
+ "RateLimitError",
35
+ "NetworkError",
36
+ "TimeoutError",
37
+ ]
@@ -0,0 +1,9 @@
1
+ """HTTP client adapter implementations.
2
+
3
+ This package contains implementations of HTTPClientProtocol for different
4
+ HTTP client libraries.
5
+ """
6
+
7
+ from .httpx_adapter import HTTPXClient
8
+
9
+ __all__ = ["HTTPXClient"]
@@ -0,0 +1,251 @@
1
+ """HTTPX adapter implementing the HTTP client protocol."""
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from ..config import ClientConfig, ConnectionLimits, TimeoutConfig
8
+ from ..exceptions import (
9
+ AuthenticationError,
10
+ HTTPStatusError,
11
+ NetworkError,
12
+ RateLimitError,
13
+ TimeoutError,
14
+ )
15
+ from ..protocols import HTTPResponseProtocol
16
+ from ..response import HTTPResponse
17
+
18
+
19
+ class HTTPXClient:
20
+ """HTTPX-based implementation of the HTTP client protocol.
21
+
22
+ This adapter wraps httpx.AsyncClient and provides the HTTPClientProtocol interface,
23
+ allowing httpx to be swapped out for a different HTTP client in the future.
24
+ """
25
+
26
+ def __init__(self, config: ClientConfig | None = None) -> None:
27
+ """Initialize the HTTPX client adapter.
28
+
29
+ Args:
30
+ config: Client configuration. If None, uses default configuration.
31
+ """
32
+ self.config = config or ClientConfig()
33
+ self._client: httpx.AsyncClient | None = None
34
+
35
+ def _create_client(self) -> httpx.AsyncClient:
36
+ """Create and configure the httpx AsyncClient.
37
+
38
+ Returns:
39
+ Configured httpx.AsyncClient instance.
40
+ """
41
+ # Convert SDK config to httpx config
42
+ limits = self._convert_limits(self.config.limits) # type: ignore
43
+ timeout = self._convert_timeout(self.config.timeout) # type: ignore
44
+
45
+ return httpx.AsyncClient(
46
+ base_url=self.config.base_url or "",
47
+ timeout=timeout,
48
+ limits=limits,
49
+ follow_redirects=self.config.follow_redirects,
50
+ )
51
+
52
+ def _convert_limits(self, limits: ConnectionLimits) -> httpx.Limits:
53
+ """Convert SDK ConnectionLimits to httpx.Limits.
54
+
55
+ Args:
56
+ limits: SDK connection limits configuration
57
+
58
+ Returns:
59
+ httpx.Limits instance
60
+ """
61
+ return httpx.Limits(
62
+ max_connections=limits.max_connections,
63
+ max_keepalive_connections=limits.max_keepalive_connections,
64
+ )
65
+
66
+ def _convert_timeout(self, timeout: TimeoutConfig) -> httpx.Timeout:
67
+ """Convert SDK TimeoutConfig to httpx.Timeout.
68
+
69
+ Args:
70
+ timeout: SDK timeout configuration
71
+
72
+ Returns:
73
+ httpx.Timeout instance
74
+ """
75
+ return httpx.Timeout(
76
+ connect=timeout.connect,
77
+ read=timeout.read,
78
+ write=timeout.write,
79
+ pool=timeout.pool,
80
+ )
81
+
82
+ def _convert_response(self, httpx_response: httpx.Response, *, stream: bool = False) -> HTTPResponse:
83
+ """Convert httpx.Response to SDK HTTPResponse.
84
+
85
+ Args:
86
+ httpx_response: The httpx response object
87
+ stream: Whether the response should be treated as streaming (do not eagerly read body)
88
+
89
+ Returns:
90
+ HTTPResponse wrapping the httpx response
91
+ """
92
+ return HTTPResponse(
93
+ status_code=httpx_response.status_code,
94
+ headers=dict(httpx_response.headers),
95
+ # When streaming, avoid eagerly reading the body
96
+ content=b"" if stream else httpx_response.content,
97
+ _original_response=httpx_response,
98
+ )
99
+
100
+ async def request(
101
+ self,
102
+ method: str,
103
+ url: str,
104
+ *,
105
+ params: dict[str, Any] | None = None,
106
+ json: dict[str, Any] | None = None,
107
+ data: dict[str, Any] | str | None = None,
108
+ headers: dict[str, str] | None = None,
109
+ **kwargs: Any,
110
+ ) -> HTTPResponseProtocol:
111
+ """Execute an HTTP request using httpx.
112
+
113
+ Args:
114
+ method: HTTP method (GET, POST, PUT, DELETE, etc.)
115
+ url: The URL to request
116
+ params: Query parameters to append to the URL
117
+ json: JSON data to send in the request body
118
+ data: Form data or raw string to send in the request body
119
+ headers: HTTP headers to include in the request
120
+ **kwargs: Additional httpx-specific parameters
121
+
122
+ Returns:
123
+ HTTPResponse with the response data.
124
+
125
+ Raises:
126
+ HTTPStatusError: For 4xx or 5xx HTTP status codes
127
+ AuthenticationError: For 401 or 403 status codes
128
+ RateLimitError: For 429 status codes
129
+ TimeoutError: For timeout errors
130
+ NetworkError: For network/connection errors
131
+ """
132
+ if self._client is None:
133
+ self._client = self._create_client()
134
+
135
+ # Extract stream parameter (not supported by httpx.request directly)
136
+ stream = kwargs.pop("stream", False)
137
+
138
+ try:
139
+ # Execute the request
140
+ httpx_response = await self._client.request(
141
+ method=method,
142
+ url=url,
143
+ params=params,
144
+ json=json,
145
+ data=data,
146
+ headers=headers,
147
+ **kwargs,
148
+ )
149
+
150
+ # Convert to SDK response
151
+ response = self._convert_response(httpx_response, stream=stream)
152
+
153
+ # Check for HTTP errors and wrap them
154
+ if httpx_response.status_code >= 400:
155
+ await self._handle_http_error(httpx_response, response)
156
+
157
+ return response
158
+
159
+ except httpx.TimeoutException as e:
160
+ raise TimeoutError(
161
+ message=f"Request timed out: {e}",
162
+ timeout_type=None, # httpx doesn't provide specific timeout type
163
+ original_error=e,
164
+ ) from e
165
+
166
+ except (httpx.ConnectError, httpx.NetworkError) as e:
167
+ raise NetworkError(
168
+ message=f"Network error: {e}",
169
+ original_error=e,
170
+ ) from e
171
+
172
+ async def _handle_http_error(self, httpx_response: httpx.Response, sdk_response: HTTPResponse) -> None:
173
+ """Handle HTTP error responses by raising appropriate SDK exceptions.
174
+
175
+ Args:
176
+ httpx_response: The original httpx response
177
+ sdk_response: The converted SDK response
178
+
179
+ Raises:
180
+ AuthenticationError: For 401 or 403 status codes
181
+ RateLimitError: For 429 status codes
182
+ HTTPStatusError: For other 4xx or 5xx status codes
183
+ """
184
+ status_code = httpx_response.status_code
185
+
186
+ # Try to get error message from response
187
+ try:
188
+ error_data = httpx_response.json()
189
+ error_message = error_data.get("message") or error_data.get("error") or str(error_data)
190
+ except Exception:
191
+ error_message = httpx_response.text or f"HTTP {status_code} error"
192
+
193
+ # Raise specific exceptions based on status code
194
+ if status_code in (401, 403):
195
+ raise AuthenticationError(
196
+ message=f"Authentication failed: {error_message} (HTTP {status_code})",
197
+ status_code=status_code,
198
+ response=sdk_response,
199
+ )
200
+
201
+ if status_code == 429:
202
+ # Try to parse Retry-After header
203
+ retry_after = None
204
+ if "retry-after" in httpx_response.headers:
205
+ try:
206
+ retry_after = int(httpx_response.headers["retry-after"])
207
+ except ValueError:
208
+ pass
209
+
210
+ error_msg = f"Rate limit exceeded: {error_message}"
211
+ if retry_after:
212
+ error_msg += f" (retry after {retry_after}s)"
213
+
214
+ raise RateLimitError(
215
+ message=error_msg,
216
+ retry_after=retry_after,
217
+ response=sdk_response,
218
+ )
219
+
220
+ # Generic HTTP error
221
+ raise HTTPStatusError(
222
+ status_code=status_code,
223
+ message=error_message,
224
+ response=sdk_response,
225
+ )
226
+
227
+ async def aclose(self) -> None:
228
+ """Close the HTTP client and cleanup resources."""
229
+ if self._client is not None:
230
+ await self._client.aclose()
231
+ self._client = None
232
+
233
+ async def __aenter__(self) -> "HTTPXClient":
234
+ """Enter async context manager.
235
+
236
+ Returns:
237
+ The client instance.
238
+ """
239
+ if self._client is None:
240
+ self._client = self._create_client()
241
+ return self
242
+
243
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
244
+ """Exit async context manager and cleanup resources.
245
+
246
+ Args:
247
+ exc_type: Exception type if an exception occurred
248
+ exc_val: Exception value if an exception occurred
249
+ exc_tb: Exception traceback if an exception occurred
250
+ """
251
+ await self.aclose()
@@ -0,0 +1,98 @@
1
+ """Configuration classes for HTTP clients."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from ..constants import (
8
+ DEFAULT_CONNECT_TIMEOUT,
9
+ DEFAULT_MAX_CONNECTIONS,
10
+ DEFAULT_MAX_KEEPALIVE_CONNECTIONS,
11
+ DEFAULT_POOL_TIMEOUT,
12
+ DEFAULT_READ_TIMEOUT,
13
+ DEFAULT_WRITE_TIMEOUT,
14
+ )
15
+
16
+
17
+ @dataclass
18
+ class ConnectionLimits:
19
+ """Configuration for HTTP connection pooling limits.
20
+
21
+ This replaces httpx.Limits and provides a client-agnostic way to configure
22
+ connection pooling behavior.
23
+ """
24
+
25
+ max_connections: int = DEFAULT_MAX_CONNECTIONS
26
+ """Maximum number of concurrent connections to allow."""
27
+
28
+ max_keepalive_connections: int = DEFAULT_MAX_KEEPALIVE_CONNECTIONS
29
+ """Maximum number of connections to keep alive in the pool."""
30
+
31
+ def __post_init__(self) -> None:
32
+ """Validate configuration values."""
33
+ if self.max_connections < 1:
34
+ raise ValueError("max_connections must be at least 1")
35
+ if self.max_keepalive_connections < 0:
36
+ raise ValueError("max_keepalive_connections must be non-negative")
37
+ if self.max_keepalive_connections > self.max_connections:
38
+ raise ValueError("max_keepalive_connections cannot exceed max_connections")
39
+
40
+
41
+ @dataclass
42
+ class TimeoutConfig:
43
+ """Configuration for HTTP request timeouts.
44
+
45
+ This replaces httpx.Timeout and provides a client-agnostic way to configure
46
+ timeout behavior for different phases of the HTTP request.
47
+ """
48
+
49
+ connect: float | None = DEFAULT_CONNECT_TIMEOUT
50
+ """Timeout for establishing a connection (seconds). None means no timeout."""
51
+
52
+ read: float | None = DEFAULT_READ_TIMEOUT
53
+ """Timeout for reading response data (seconds). None means no timeout."""
54
+
55
+ write: float | None = DEFAULT_WRITE_TIMEOUT
56
+ """Timeout for writing request data (seconds). None means no timeout."""
57
+
58
+ pool: float | None = DEFAULT_POOL_TIMEOUT
59
+ """Timeout for acquiring a connection from the pool (seconds). None means no timeout."""
60
+
61
+ def __post_init__(self) -> None:
62
+ """Validate configuration values."""
63
+ for name, value in [
64
+ ("connect", self.connect),
65
+ ("read", self.read),
66
+ ("write", self.write),
67
+ ("pool", self.pool),
68
+ ]:
69
+ if value is not None and value <= 0:
70
+ raise ValueError(f"{name} timeout must be positive or None")
71
+
72
+
73
+ @dataclass
74
+ class ClientConfig:
75
+ """Overall configuration for an HTTP client.
76
+
77
+ This provides a complete, client-agnostic configuration for HTTP clients
78
+ that can be mapped to any underlying HTTP client implementation.
79
+ """
80
+
81
+ timeout: TimeoutConfig | None = None
82
+ """Timeout configuration. If None, uses default timeouts."""
83
+
84
+ limits: ConnectionLimits | None = None
85
+ """Connection pooling limits. If None, uses default limits."""
86
+
87
+ base_url: str | None = None
88
+ """Optional base URL to prepend to all requests."""
89
+
90
+ follow_redirects: bool = True
91
+ """Whether to automatically follow HTTP redirects."""
92
+
93
+ def __post_init__(self) -> None:
94
+ """Set default values for None fields."""
95
+ if self.timeout is None:
96
+ self.timeout = TimeoutConfig()
97
+ if self.limits is None:
98
+ self.limits = ConnectionLimits()
@@ -0,0 +1,119 @@
1
+ """HTTP-related exceptions for the Airbyte SDK."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from .response import HTTPResponse
7
+
8
+
9
+ class HTTPClientError(Exception):
10
+ """Base exception for HTTP client errors."""
11
+
12
+ pass
13
+
14
+
15
+ class HTTPStatusError(HTTPClientError):
16
+ """Raised when an HTTP response has a 4xx or 5xx status code.
17
+
18
+ This is the base exception for status code errors and is raised by
19
+ HTTPResponse.raise_for_status().
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ status_code: int,
25
+ message: str,
26
+ response: "HTTPResponse | None" = None,
27
+ ) -> None:
28
+ """Initialize HTTP status error.
29
+
30
+ Args:
31
+ status_code: The HTTP status code (e.g., 404, 500)
32
+ message: Error message describing the issue
33
+ response: Optional HTTPResponse object for accessing details
34
+ """
35
+ super().__init__(message)
36
+ self.status_code = status_code
37
+ self.response = response
38
+
39
+
40
+ class AuthenticationError(HTTPStatusError):
41
+ """Raised when authentication credentials are missing or invalid (401, 403)."""
42
+
43
+ def __init__(
44
+ self,
45
+ message: str,
46
+ status_code: int = 401,
47
+ response: "HTTPResponse | None" = None,
48
+ ) -> None:
49
+ """Initialize authentication error.
50
+
51
+ Args:
52
+ message: Error message describing the authentication issue
53
+ status_code: HTTP status code (401 or 403)
54
+ response: Optional HTTPResponse object for accessing details
55
+ """
56
+ super().__init__(status_code=status_code, message=message, response=response)
57
+
58
+
59
+ class RateLimitError(HTTPStatusError):
60
+ """Raised when API rate limit is exceeded (429 response)."""
61
+
62
+ def __init__(
63
+ self,
64
+ message: str,
65
+ retry_after: int | None = None,
66
+ response: "HTTPResponse | None" = None,
67
+ ) -> None:
68
+ """Initialize rate limit error.
69
+
70
+ Args:
71
+ message: Error message describing the rate limit
72
+ retry_after: Seconds to wait before retrying (from Retry-After header)
73
+ response: Optional HTTPResponse object for accessing details
74
+ """
75
+ super().__init__(status_code=429, message=message, response=response)
76
+ self.retry_after = retry_after
77
+
78
+
79
+ class NetworkError(HTTPClientError):
80
+ """Raised when network connection fails.
81
+
82
+ This includes connection errors, DNS resolution failures, and other
83
+ network-level issues.
84
+ """
85
+
86
+ def __init__(self, message: str, original_error: Exception | None = None) -> None:
87
+ """Initialize network error.
88
+
89
+ Args:
90
+ message: Error message describing the network issue
91
+ original_error: Optional original exception from the HTTP client
92
+ """
93
+ super().__init__(message)
94
+ self.original_error = original_error
95
+
96
+
97
+ class TimeoutError(HTTPClientError):
98
+ """Raised when a request times out.
99
+
100
+ This can occur during connection establishment, reading the response,
101
+ or writing the request.
102
+ """
103
+
104
+ def __init__(
105
+ self,
106
+ message: str,
107
+ timeout_type: str | None = None,
108
+ original_error: Exception | None = None,
109
+ ) -> None:
110
+ """Initialize timeout error.
111
+
112
+ Args:
113
+ message: Error message describing the timeout
114
+ timeout_type: Optional type of timeout (connect, read, write, pool)
115
+ original_error: Optional original exception from the HTTP client
116
+ """
117
+ super().__init__(message)
118
+ self.timeout_type = timeout_type
119
+ self.original_error = original_error
@@ -0,0 +1,114 @@
1
+ """HTTP client and response protocols for abstracting HTTP client implementations."""
2
+
3
+ from typing import Any, Protocol, runtime_checkable
4
+
5
+
6
+ @runtime_checkable
7
+ class HTTPResponseProtocol(Protocol):
8
+ """Protocol defining the interface for HTTP responses.
9
+
10
+ This protocol abstracts the response interface, allowing different HTTP clients
11
+ to provide responses that work with the SDK.
12
+ """
13
+
14
+ @property
15
+ def status_code(self) -> int:
16
+ """The HTTP status code of the response."""
17
+ ...
18
+
19
+ @property
20
+ def headers(self) -> dict[str, str]:
21
+ """The response headers as a dictionary."""
22
+ ...
23
+
24
+ async def json(self) -> Any:
25
+ """Parse the response body as JSON.
26
+
27
+ Returns:
28
+ The parsed JSON data (dict, list, or primitive).
29
+
30
+ Raises:
31
+ ValueError: If the response body is not valid JSON.
32
+ """
33
+ ...
34
+
35
+ async def text(self) -> str:
36
+ """Get the response body as text.
37
+
38
+ Returns:
39
+ The response body decoded as a string.
40
+ """
41
+ ...
42
+
43
+ def raise_for_status(self) -> None:
44
+ """Raise an exception if the response status indicates an error.
45
+
46
+ Raises:
47
+ Exception: For 4xx or 5xx status codes.
48
+ """
49
+ ...
50
+
51
+
52
+ @runtime_checkable
53
+ class HTTPClientProtocol(Protocol):
54
+ """Protocol defining the interface for HTTP clients.
55
+
56
+ This protocol abstracts the HTTP client interface, allowing the SDK to work with
57
+ different HTTP client implementations (httpx, aiohttp, etc.).
58
+ """
59
+
60
+ async def request(
61
+ self,
62
+ method: str,
63
+ url: str,
64
+ *,
65
+ params: dict[str, Any] | None = None,
66
+ json: dict[str, Any] | None = None,
67
+ data: dict[str, Any] | str | None = None,
68
+ headers: dict[str, str] | None = None,
69
+ **kwargs: Any,
70
+ ) -> HTTPResponseProtocol:
71
+ """Execute an HTTP request.
72
+
73
+ Args:
74
+ method: HTTP method (GET, POST, PUT, DELETE, etc.)
75
+ url: The URL to request
76
+ params: Query parameters to append to the URL
77
+ json: JSON data to send in the request body
78
+ data: Form data or raw string to send in the request body
79
+ headers: HTTP headers to include in the request
80
+ **kwargs: Additional client-specific parameters
81
+
82
+ Returns:
83
+ An HTTPResponseProtocol implementation with the response data.
84
+
85
+ Raises:
86
+ Exception: For network errors, timeouts, or other request failures.
87
+ """
88
+ ...
89
+
90
+ async def aclose(self) -> None:
91
+ """Close the HTTP client and cleanup resources.
92
+
93
+ This should be called when the client is no longer needed to properly
94
+ cleanup connections and resources.
95
+ """
96
+ ...
97
+
98
+ async def __aenter__(self) -> "HTTPClientProtocol":
99
+ """Enter async context manager.
100
+
101
+ Returns:
102
+ The client instance.
103
+ """
104
+ ...
105
+
106
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
107
+ """Exit async context manager and cleanup resources.
108
+
109
+ Args:
110
+ exc_type: Exception type if an exception occurred
111
+ exc_val: Exception value if an exception occurred
112
+ exc_tb: Exception traceback if an exception occurred
113
+ """
114
+ ...