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,1378 @@
1
+ """
2
+ Mailchimp connector.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ from typing import TYPE_CHECKING, Any, Callable, TypeVar, overload
9
+ try:
10
+ from typing import Literal
11
+ except ImportError:
12
+ from typing_extensions import Literal
13
+
14
+ from .connector_model import MailchimpConnectorModel
15
+ from ._vendored.connector_sdk.introspection import describe_entities, generate_tool_description
16
+ from .types import (
17
+ AutomationsListParams,
18
+ CampaignsGetParams,
19
+ CampaignsListParams,
20
+ EmailActivityListParams,
21
+ InterestCategoriesGetParams,
22
+ InterestCategoriesListParams,
23
+ InterestsGetParams,
24
+ InterestsListParams,
25
+ ListMembersGetParams,
26
+ ListMembersListParams,
27
+ ListsGetParams,
28
+ ListsListParams,
29
+ ReportsGetParams,
30
+ ReportsListParams,
31
+ SegmentMembersListParams,
32
+ SegmentsGetParams,
33
+ SegmentsListParams,
34
+ TagsListParams,
35
+ UnsubscribesListParams,
36
+ )
37
+ if TYPE_CHECKING:
38
+ from .models import MailchimpAuthConfig
39
+ # Import response models and envelope models at runtime
40
+ from .models import (
41
+ MailchimpExecuteResult,
42
+ MailchimpExecuteResultWithMeta,
43
+ CampaignsListResult,
44
+ ListsListResult,
45
+ ListMembersListResult,
46
+ ReportsListResult,
47
+ EmailActivityListResult,
48
+ AutomationsListResult,
49
+ TagsListResult,
50
+ InterestCategoriesListResult,
51
+ InterestsListResult,
52
+ SegmentsListResult,
53
+ SegmentMembersListResult,
54
+ UnsubscribesListResult,
55
+ Automation,
56
+ Campaign,
57
+ EmailActivity,
58
+ Interest,
59
+ InterestCategory,
60
+ List,
61
+ ListMember,
62
+ Report,
63
+ Segment,
64
+ SegmentMember,
65
+ Tag,
66
+ Unsubscribe,
67
+ )
68
+
69
+ # TypeVar for decorator type preservation
70
+ _F = TypeVar("_F", bound=Callable[..., Any])
71
+
72
+
73
+
74
+ class MailchimpConnector:
75
+ """
76
+ Type-safe Mailchimp API connector.
77
+
78
+ Auto-generated from OpenAPI specification with full type safety.
79
+ """
80
+
81
+ connector_name = "mailchimp"
82
+ connector_version = "1.0.1"
83
+ vendored_sdk_version = "0.1.0" # Version of vendored connector-sdk
84
+
85
+ # Map of (entity, action) -> needs_envelope for envelope wrapping decision
86
+ _ENVELOPE_MAP = {
87
+ ("campaigns", "list"): True,
88
+ ("campaigns", "get"): None,
89
+ ("lists", "list"): True,
90
+ ("lists", "get"): None,
91
+ ("list_members", "list"): True,
92
+ ("list_members", "get"): None,
93
+ ("reports", "list"): True,
94
+ ("reports", "get"): None,
95
+ ("email_activity", "list"): True,
96
+ ("automations", "list"): True,
97
+ ("tags", "list"): True,
98
+ ("interest_categories", "list"): True,
99
+ ("interest_categories", "get"): None,
100
+ ("interests", "list"): True,
101
+ ("interests", "get"): None,
102
+ ("segments", "list"): True,
103
+ ("segments", "get"): None,
104
+ ("segment_members", "list"): True,
105
+ ("unsubscribes", "list"): True,
106
+ }
107
+
108
+ # Map of (entity, action) -> {python_param_name: api_param_name}
109
+ # Used to convert snake_case TypedDict keys to API parameter names in execute()
110
+ _PARAM_MAP = {
111
+ ('campaigns', 'list'): {'count': 'count', 'offset': 'offset', 'type': 'type', 'status': 'status', 'before_send_time': 'before_send_time', 'since_send_time': 'since_send_time', 'before_create_time': 'before_create_time', 'since_create_time': 'since_create_time', 'list_id': 'list_id', 'folder_id': 'folder_id', 'sort_field': 'sort_field', 'sort_dir': 'sort_dir'},
112
+ ('campaigns', 'get'): {'campaign_id': 'campaign_id'},
113
+ ('lists', 'list'): {'count': 'count', 'offset': 'offset', 'before_date_created': 'before_date_created', 'since_date_created': 'since_date_created', 'before_campaign_last_sent': 'before_campaign_last_sent', 'since_campaign_last_sent': 'since_campaign_last_sent', 'email': 'email', 'sort_field': 'sort_field', 'sort_dir': 'sort_dir'},
114
+ ('lists', 'get'): {'list_id': 'list_id'},
115
+ ('list_members', 'list'): {'list_id': 'list_id', 'count': 'count', 'offset': 'offset', 'email_type': 'email_type', 'status': 'status', 'since_timestamp_opt': 'since_timestamp_opt', 'before_timestamp_opt': 'before_timestamp_opt', 'since_last_changed': 'since_last_changed', 'before_last_changed': 'before_last_changed', 'unique_email_id': 'unique_email_id', 'vip_only': 'vip_only', 'interest_category_id': 'interest_category_id', 'interest_ids': 'interest_ids', 'interest_match': 'interest_match', 'sort_field': 'sort_field', 'sort_dir': 'sort_dir'},
116
+ ('list_members', 'get'): {'list_id': 'list_id', 'subscriber_hash': 'subscriber_hash'},
117
+ ('reports', 'list'): {'count': 'count', 'offset': 'offset', 'type': 'type', 'before_send_time': 'before_send_time', 'since_send_time': 'since_send_time'},
118
+ ('reports', 'get'): {'campaign_id': 'campaign_id'},
119
+ ('email_activity', 'list'): {'campaign_id': 'campaign_id', 'count': 'count', 'offset': 'offset', 'since': 'since'},
120
+ ('automations', 'list'): {'count': 'count', 'offset': 'offset', 'before_create_time': 'before_create_time', 'since_create_time': 'since_create_time', 'before_start_time': 'before_start_time', 'since_start_time': 'since_start_time', 'status': 'status'},
121
+ ('tags', 'list'): {'list_id': 'list_id', 'name': 'name'},
122
+ ('interest_categories', 'list'): {'list_id': 'list_id', 'count': 'count', 'offset': 'offset'},
123
+ ('interest_categories', 'get'): {'list_id': 'list_id', 'interest_category_id': 'interest_category_id'},
124
+ ('interests', 'list'): {'list_id': 'list_id', 'interest_category_id': 'interest_category_id', 'count': 'count', 'offset': 'offset'},
125
+ ('interests', 'get'): {'list_id': 'list_id', 'interest_category_id': 'interest_category_id', 'interest_id': 'interest_id'},
126
+ ('segments', 'list'): {'list_id': 'list_id', 'count': 'count', 'offset': 'offset', 'type': 'type', 'since_created_at': 'since_created_at', 'before_created_at': 'before_created_at', 'since_updated_at': 'since_updated_at', 'before_updated_at': 'before_updated_at'},
127
+ ('segments', 'get'): {'list_id': 'list_id', 'segment_id': 'segment_id'},
128
+ ('segment_members', 'list'): {'list_id': 'list_id', 'segment_id': 'segment_id', 'count': 'count', 'offset': 'offset'},
129
+ ('unsubscribes', 'list'): {'campaign_id': 'campaign_id', 'count': 'count', 'offset': 'offset'},
130
+ }
131
+
132
+ def __init__(
133
+ self,
134
+ auth_config: MailchimpAuthConfig | None = None,
135
+ external_user_id: str | None = None,
136
+ airbyte_client_id: str | None = None,
137
+ airbyte_client_secret: str | None = None,
138
+ on_token_refresh: Any | None = None,
139
+ data_center: str | None = None ):
140
+ """
141
+ Initialize a new mailchimp connector instance.
142
+
143
+ Supports both local and hosted execution modes:
144
+ - Local mode: Provide `auth_config` for direct API calls
145
+ - Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
146
+
147
+ Args:
148
+ auth_config: Typed authentication configuration (required for local mode)
149
+ external_user_id: External user ID (required for hosted mode)
150
+ airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
151
+ airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
152
+ on_token_refresh: Optional callback for OAuth2 token refresh persistence.
153
+ Called with new_tokens dict when tokens are refreshed. Can be sync or async.
154
+ Example: lambda tokens: save_to_database(tokens) data_center: The data center for your Mailchimp account (e.g., us1, us2, us6)
155
+ Examples:
156
+ # Local mode (direct API calls)
157
+ connector = MailchimpConnector(auth_config=MailchimpAuthConfig(api_key="...", data_center="..."))
158
+ # Hosted mode (executed on Airbyte cloud)
159
+ connector = MailchimpConnector(
160
+ external_user_id="user-123",
161
+ airbyte_client_id="client_abc123",
162
+ airbyte_client_secret="secret_xyz789"
163
+ )
164
+
165
+ # Local mode with OAuth2 token refresh callback
166
+ def save_tokens(new_tokens: dict) -> None:
167
+ # Persist updated tokens to your storage (file, database, etc.)
168
+ with open("tokens.json", "w") as f:
169
+ json.dump(new_tokens, f)
170
+
171
+ connector = MailchimpConnector(
172
+ auth_config=MailchimpAuthConfig(access_token="...", refresh_token="..."),
173
+ on_token_refresh=save_tokens
174
+ )
175
+ """
176
+ # Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
177
+ if external_user_id and airbyte_client_id and airbyte_client_secret:
178
+ from ._vendored.connector_sdk.executor import HostedExecutor
179
+ self._executor = HostedExecutor(
180
+ external_user_id=external_user_id,
181
+ airbyte_client_id=airbyte_client_id,
182
+ airbyte_client_secret=airbyte_client_secret,
183
+ connector_definition_id=str(MailchimpConnectorModel.id),
184
+ )
185
+ else:
186
+ # Local mode: auth_config required
187
+ if not auth_config:
188
+ raise ValueError(
189
+ "Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
190
+ "or auth_config for local mode"
191
+ )
192
+
193
+ from ._vendored.connector_sdk.executor import LocalExecutor
194
+
195
+ # Build config_values dict from server variables
196
+ config_values: dict[str, str] = {}
197
+ if data_center:
198
+ config_values["data_center"] = data_center
199
+
200
+ self._executor = LocalExecutor(
201
+ model=MailchimpConnectorModel,
202
+ auth_config=auth_config.model_dump() if auth_config else None,
203
+ config_values=config_values,
204
+ on_token_refresh=on_token_refresh
205
+ )
206
+
207
+ # Update base_url with server variables if provided
208
+ base_url = self._executor.http_client.base_url
209
+ if data_center:
210
+ base_url = base_url.replace("{data_center}", data_center)
211
+ self._executor.http_client.base_url = base_url
212
+
213
+ # Initialize entity query objects
214
+ self.campaigns = CampaignsQuery(self)
215
+ self.lists = ListsQuery(self)
216
+ self.list_members = ListMembersQuery(self)
217
+ self.reports = ReportsQuery(self)
218
+ self.email_activity = EmailActivityQuery(self)
219
+ self.automations = AutomationsQuery(self)
220
+ self.tags = TagsQuery(self)
221
+ self.interest_categories = InterestCategoriesQuery(self)
222
+ self.interests = InterestsQuery(self)
223
+ self.segments = SegmentsQuery(self)
224
+ self.segment_members = SegmentMembersQuery(self)
225
+ self.unsubscribes = UnsubscribesQuery(self)
226
+
227
+ # ===== TYPED EXECUTE METHOD (Recommended Interface) =====
228
+
229
+ @overload
230
+ async def execute(
231
+ self,
232
+ entity: Literal["campaigns"],
233
+ action: Literal["list"],
234
+ params: "CampaignsListParams"
235
+ ) -> "CampaignsListResult": ...
236
+
237
+ @overload
238
+ async def execute(
239
+ self,
240
+ entity: Literal["campaigns"],
241
+ action: Literal["get"],
242
+ params: "CampaignsGetParams"
243
+ ) -> "Campaign": ...
244
+
245
+ @overload
246
+ async def execute(
247
+ self,
248
+ entity: Literal["lists"],
249
+ action: Literal["list"],
250
+ params: "ListsListParams"
251
+ ) -> "ListsListResult": ...
252
+
253
+ @overload
254
+ async def execute(
255
+ self,
256
+ entity: Literal["lists"],
257
+ action: Literal["get"],
258
+ params: "ListsGetParams"
259
+ ) -> "List": ...
260
+
261
+ @overload
262
+ async def execute(
263
+ self,
264
+ entity: Literal["list_members"],
265
+ action: Literal["list"],
266
+ params: "ListMembersListParams"
267
+ ) -> "ListMembersListResult": ...
268
+
269
+ @overload
270
+ async def execute(
271
+ self,
272
+ entity: Literal["list_members"],
273
+ action: Literal["get"],
274
+ params: "ListMembersGetParams"
275
+ ) -> "ListMember": ...
276
+
277
+ @overload
278
+ async def execute(
279
+ self,
280
+ entity: Literal["reports"],
281
+ action: Literal["list"],
282
+ params: "ReportsListParams"
283
+ ) -> "ReportsListResult": ...
284
+
285
+ @overload
286
+ async def execute(
287
+ self,
288
+ entity: Literal["reports"],
289
+ action: Literal["get"],
290
+ params: "ReportsGetParams"
291
+ ) -> "Report": ...
292
+
293
+ @overload
294
+ async def execute(
295
+ self,
296
+ entity: Literal["email_activity"],
297
+ action: Literal["list"],
298
+ params: "EmailActivityListParams"
299
+ ) -> "EmailActivityListResult": ...
300
+
301
+ @overload
302
+ async def execute(
303
+ self,
304
+ entity: Literal["automations"],
305
+ action: Literal["list"],
306
+ params: "AutomationsListParams"
307
+ ) -> "AutomationsListResult": ...
308
+
309
+ @overload
310
+ async def execute(
311
+ self,
312
+ entity: Literal["tags"],
313
+ action: Literal["list"],
314
+ params: "TagsListParams"
315
+ ) -> "TagsListResult": ...
316
+
317
+ @overload
318
+ async def execute(
319
+ self,
320
+ entity: Literal["interest_categories"],
321
+ action: Literal["list"],
322
+ params: "InterestCategoriesListParams"
323
+ ) -> "InterestCategoriesListResult": ...
324
+
325
+ @overload
326
+ async def execute(
327
+ self,
328
+ entity: Literal["interest_categories"],
329
+ action: Literal["get"],
330
+ params: "InterestCategoriesGetParams"
331
+ ) -> "InterestCategory": ...
332
+
333
+ @overload
334
+ async def execute(
335
+ self,
336
+ entity: Literal["interests"],
337
+ action: Literal["list"],
338
+ params: "InterestsListParams"
339
+ ) -> "InterestsListResult": ...
340
+
341
+ @overload
342
+ async def execute(
343
+ self,
344
+ entity: Literal["interests"],
345
+ action: Literal["get"],
346
+ params: "InterestsGetParams"
347
+ ) -> "Interest": ...
348
+
349
+ @overload
350
+ async def execute(
351
+ self,
352
+ entity: Literal["segments"],
353
+ action: Literal["list"],
354
+ params: "SegmentsListParams"
355
+ ) -> "SegmentsListResult": ...
356
+
357
+ @overload
358
+ async def execute(
359
+ self,
360
+ entity: Literal["segments"],
361
+ action: Literal["get"],
362
+ params: "SegmentsGetParams"
363
+ ) -> "Segment": ...
364
+
365
+ @overload
366
+ async def execute(
367
+ self,
368
+ entity: Literal["segment_members"],
369
+ action: Literal["list"],
370
+ params: "SegmentMembersListParams"
371
+ ) -> "SegmentMembersListResult": ...
372
+
373
+ @overload
374
+ async def execute(
375
+ self,
376
+ entity: Literal["unsubscribes"],
377
+ action: Literal["list"],
378
+ params: "UnsubscribesListParams"
379
+ ) -> "UnsubscribesListResult": ...
380
+
381
+
382
+ @overload
383
+ async def execute(
384
+ self,
385
+ entity: str,
386
+ action: str,
387
+ params: dict[str, Any]
388
+ ) -> MailchimpExecuteResult[Any] | MailchimpExecuteResultWithMeta[Any, Any] | Any: ...
389
+
390
+ async def execute(
391
+ self,
392
+ entity: str,
393
+ action: str,
394
+ params: dict[str, Any] | None = None
395
+ ) -> Any:
396
+ """
397
+ Execute an entity operation with full type safety.
398
+
399
+ This is the recommended interface for blessed connectors as it:
400
+ - Uses the same signature as non-blessed connectors
401
+ - Provides full IDE autocomplete for entity/action/params
402
+ - Makes migration from generic to blessed connectors seamless
403
+
404
+ Args:
405
+ entity: Entity name (e.g., "customers")
406
+ action: Operation action (e.g., "create", "get", "list")
407
+ params: Operation parameters (typed based on entity+action)
408
+
409
+ Returns:
410
+ Typed response based on the operation
411
+
412
+ Example:
413
+ customer = await connector.execute(
414
+ entity="customers",
415
+ action="get",
416
+ params={"id": "cus_123"}
417
+ )
418
+ """
419
+ from ._vendored.connector_sdk.executor import ExecutionConfig
420
+
421
+ # Remap parameter names from snake_case (TypedDict keys) to API parameter names
422
+ if params:
423
+ param_map = self._PARAM_MAP.get((entity, action), {})
424
+ if param_map:
425
+ params = {param_map.get(k, k): v for k, v in params.items()}
426
+
427
+ # Use ExecutionConfig for both local and hosted executors
428
+ config = ExecutionConfig(
429
+ entity=entity,
430
+ action=action,
431
+ params=params
432
+ )
433
+
434
+ result = await self._executor.execute(config)
435
+
436
+ if not result.success:
437
+ raise RuntimeError(f"Execution failed: {result.error}")
438
+
439
+ # Check if this operation has extractors configured
440
+ has_extractors = self._ENVELOPE_MAP.get((entity, action), False)
441
+
442
+ if has_extractors:
443
+ # With extractors - return Pydantic envelope with data and meta
444
+ if result.meta is not None:
445
+ return MailchimpExecuteResultWithMeta[Any, Any](
446
+ data=result.data,
447
+ meta=result.meta
448
+ )
449
+ else:
450
+ return MailchimpExecuteResult[Any](data=result.data)
451
+ else:
452
+ # No extractors - return raw response data
453
+ return result.data
454
+
455
+ # ===== INTROSPECTION METHODS =====
456
+
457
+ @classmethod
458
+ def describe(cls, func: _F) -> _F:
459
+ """
460
+ Decorator that populates a function's docstring with connector capabilities.
461
+
462
+ This class method can be used as a decorator to automatically generate
463
+ comprehensive documentation for AI tool functions.
464
+
465
+ Usage:
466
+ @mcp.tool()
467
+ @MailchimpConnector.describe
468
+ async def execute(entity: str, action: str, params: dict):
469
+ '''Execute operations.'''
470
+ ...
471
+
472
+ The decorated function's __doc__ will be updated with:
473
+ - Available entities and their actions
474
+ - Parameter signatures with required (*) and optional (?) markers
475
+ - Response structure documentation
476
+ - Example questions (if available in OpenAPI spec)
477
+
478
+ Args:
479
+ func: The function to decorate
480
+
481
+ Returns:
482
+ The same function with updated __doc__
483
+ """
484
+ description = generate_tool_description(MailchimpConnectorModel)
485
+
486
+ original_doc = func.__doc__ or ""
487
+ if original_doc.strip():
488
+ func.__doc__ = f"{original_doc.strip()}\n{description}"
489
+ else:
490
+ func.__doc__ = description
491
+
492
+ return func
493
+
494
+ def list_entities(self) -> list[dict[str, Any]]:
495
+ """
496
+ Get structured data about available entities, actions, and parameters.
497
+
498
+ Returns a list of entity descriptions with:
499
+ - entity_name: Name of the entity (e.g., "contacts", "deals")
500
+ - description: Entity description from the first endpoint
501
+ - available_actions: List of actions (e.g., ["list", "get", "create"])
502
+ - parameters: Dict mapping action -> list of parameter dicts
503
+
504
+ Example:
505
+ entities = connector.list_entities()
506
+ for entity in entities:
507
+ print(f"{entity['entity_name']}: {entity['available_actions']}")
508
+ """
509
+ return describe_entities(MailchimpConnectorModel)
510
+
511
+ def entity_schema(self, entity: str) -> dict[str, Any] | None:
512
+ """
513
+ Get the JSON schema for an entity.
514
+
515
+ Args:
516
+ entity: Entity name (e.g., "contacts", "companies")
517
+
518
+ Returns:
519
+ JSON schema dict describing the entity structure, or None if not found.
520
+
521
+ Example:
522
+ schema = connector.entity_schema("contacts")
523
+ if schema:
524
+ print(f"Contact properties: {list(schema.get('properties', {}).keys())}")
525
+ """
526
+ entity_def = next(
527
+ (e for e in MailchimpConnectorModel.entities if e.name == entity),
528
+ None
529
+ )
530
+ if entity_def is None:
531
+ logging.getLogger(__name__).warning(
532
+ f"Entity '{entity}' not found. Available entities: "
533
+ f"{[e.name for e in MailchimpConnectorModel.entities]}"
534
+ )
535
+ return entity_def.entity_schema if entity_def else None
536
+
537
+
538
+
539
+ class CampaignsQuery:
540
+ """
541
+ Query class for Campaigns entity operations.
542
+ """
543
+
544
+ def __init__(self, connector: MailchimpConnector):
545
+ """Initialize query with connector reference."""
546
+ self._connector = connector
547
+
548
+ async def list(
549
+ self,
550
+ count: int | None = None,
551
+ offset: int | None = None,
552
+ type: str | None = None,
553
+ status: str | None = None,
554
+ before_send_time: str | None = None,
555
+ since_send_time: str | None = None,
556
+ before_create_time: str | None = None,
557
+ since_create_time: str | None = None,
558
+ list_id: str | None = None,
559
+ folder_id: str | None = None,
560
+ sort_field: str | None = None,
561
+ sort_dir: str | None = None,
562
+ **kwargs
563
+ ) -> CampaignsListResult:
564
+ """
565
+ Get all campaigns in an account
566
+
567
+ Args:
568
+ count: The number of records to return. Default is 10. Maximum is 1000.
569
+ offset: Used for pagination, this is the number of records from a collection to skip.
570
+ type: The campaign type
571
+ status: The status of the campaign
572
+ before_send_time: Restrict the response to campaigns sent before the set time
573
+ since_send_time: Restrict the response to campaigns sent after the set time
574
+ before_create_time: Restrict the response to campaigns created before the set time
575
+ since_create_time: Restrict the response to campaigns created after the set time
576
+ list_id: The unique id for the list
577
+ folder_id: The unique folder id
578
+ sort_field: Returns files sorted by the specified field
579
+ sort_dir: Determines the order direction for sorted results
580
+ **kwargs: Additional parameters
581
+
582
+ Returns:
583
+ CampaignsListResult
584
+ """
585
+ params = {k: v for k, v in {
586
+ "count": count,
587
+ "offset": offset,
588
+ "type": type,
589
+ "status": status,
590
+ "before_send_time": before_send_time,
591
+ "since_send_time": since_send_time,
592
+ "before_create_time": before_create_time,
593
+ "since_create_time": since_create_time,
594
+ "list_id": list_id,
595
+ "folder_id": folder_id,
596
+ "sort_field": sort_field,
597
+ "sort_dir": sort_dir,
598
+ **kwargs
599
+ }.items() if v is not None}
600
+
601
+ result = await self._connector.execute("campaigns", "list", params)
602
+ # Cast generic envelope to concrete typed result
603
+ return CampaignsListResult(
604
+ data=result.data,
605
+ meta=result.meta
606
+ )
607
+
608
+
609
+
610
+ async def get(
611
+ self,
612
+ campaign_id: str,
613
+ **kwargs
614
+ ) -> Campaign:
615
+ """
616
+ Get information about a specific campaign
617
+
618
+ Args:
619
+ campaign_id: The unique id for the campaign
620
+ **kwargs: Additional parameters
621
+
622
+ Returns:
623
+ Campaign
624
+ """
625
+ params = {k: v for k, v in {
626
+ "campaign_id": campaign_id,
627
+ **kwargs
628
+ }.items() if v is not None}
629
+
630
+ result = await self._connector.execute("campaigns", "get", params)
631
+ return result
632
+
633
+
634
+
635
+ class ListsQuery:
636
+ """
637
+ Query class for Lists entity operations.
638
+ """
639
+
640
+ def __init__(self, connector: MailchimpConnector):
641
+ """Initialize query with connector reference."""
642
+ self._connector = connector
643
+
644
+ async def list(
645
+ self,
646
+ count: int | None = None,
647
+ offset: int | None = None,
648
+ before_date_created: str | None = None,
649
+ since_date_created: str | None = None,
650
+ before_campaign_last_sent: str | None = None,
651
+ since_campaign_last_sent: str | None = None,
652
+ email: str | None = None,
653
+ sort_field: str | None = None,
654
+ sort_dir: str | None = None,
655
+ **kwargs
656
+ ) -> ListsListResult:
657
+ """
658
+ Get information about all lists in the account
659
+
660
+ Args:
661
+ count: The number of records to return
662
+ offset: Used for pagination
663
+ before_date_created: Restrict response to lists created before the set date
664
+ since_date_created: Restrict response to lists created after the set date
665
+ before_campaign_last_sent: Restrict results to lists created before the last campaign send date
666
+ since_campaign_last_sent: Restrict results to lists created after the last campaign send date
667
+ email: Restrict results to lists that include a specific subscriber's email address
668
+ sort_field: Returns files sorted by the specified field
669
+ sort_dir: Determines the order direction for sorted results
670
+ **kwargs: Additional parameters
671
+
672
+ Returns:
673
+ ListsListResult
674
+ """
675
+ params = {k: v for k, v in {
676
+ "count": count,
677
+ "offset": offset,
678
+ "before_date_created": before_date_created,
679
+ "since_date_created": since_date_created,
680
+ "before_campaign_last_sent": before_campaign_last_sent,
681
+ "since_campaign_last_sent": since_campaign_last_sent,
682
+ "email": email,
683
+ "sort_field": sort_field,
684
+ "sort_dir": sort_dir,
685
+ **kwargs
686
+ }.items() if v is not None}
687
+
688
+ result = await self._connector.execute("lists", "list", params)
689
+ # Cast generic envelope to concrete typed result
690
+ return ListsListResult(
691
+ data=result.data,
692
+ meta=result.meta
693
+ )
694
+
695
+
696
+
697
+ async def get(
698
+ self,
699
+ list_id: str,
700
+ **kwargs
701
+ ) -> List:
702
+ """
703
+ Get information about a specific list in your Mailchimp account
704
+
705
+ Args:
706
+ list_id: The unique ID for the list
707
+ **kwargs: Additional parameters
708
+
709
+ Returns:
710
+ List
711
+ """
712
+ params = {k: v for k, v in {
713
+ "list_id": list_id,
714
+ **kwargs
715
+ }.items() if v is not None}
716
+
717
+ result = await self._connector.execute("lists", "get", params)
718
+ return result
719
+
720
+
721
+
722
+ class ListMembersQuery:
723
+ """
724
+ Query class for ListMembers entity operations.
725
+ """
726
+
727
+ def __init__(self, connector: MailchimpConnector):
728
+ """Initialize query with connector reference."""
729
+ self._connector = connector
730
+
731
+ async def list(
732
+ self,
733
+ list_id: str,
734
+ count: int | None = None,
735
+ offset: int | None = None,
736
+ email_type: str | None = None,
737
+ status: str | None = None,
738
+ since_timestamp_opt: str | None = None,
739
+ before_timestamp_opt: str | None = None,
740
+ since_last_changed: str | None = None,
741
+ before_last_changed: str | None = None,
742
+ unique_email_id: str | None = None,
743
+ vip_only: bool | None = None,
744
+ interest_category_id: str | None = None,
745
+ interest_ids: str | None = None,
746
+ interest_match: str | None = None,
747
+ sort_field: str | None = None,
748
+ sort_dir: str | None = None,
749
+ **kwargs
750
+ ) -> ListMembersListResult:
751
+ """
752
+ Get information about members in a specific Mailchimp list
753
+
754
+ Args:
755
+ list_id: The unique ID for the list
756
+ count: The number of records to return
757
+ offset: Used for pagination
758
+ email_type: The email type
759
+ status: The subscriber's status
760
+ since_timestamp_opt: Restrict results to subscribers who opted-in after the set timeframe
761
+ before_timestamp_opt: Restrict results to subscribers who opted-in before the set timeframe
762
+ since_last_changed: Restrict results to subscribers whose information changed after the set timeframe
763
+ before_last_changed: Restrict results to subscribers whose information changed before the set timeframe
764
+ unique_email_id: A unique identifier for the email address across all Mailchimp lists
765
+ vip_only: A filter to return only the list's VIP members
766
+ interest_category_id: The unique id for the interest category
767
+ interest_ids: Used to filter list members by interests
768
+ interest_match: Used to filter list members by interests
769
+ sort_field: Returns files sorted by the specified field
770
+ sort_dir: Determines the order direction for sorted results
771
+ **kwargs: Additional parameters
772
+
773
+ Returns:
774
+ ListMembersListResult
775
+ """
776
+ params = {k: v for k, v in {
777
+ "list_id": list_id,
778
+ "count": count,
779
+ "offset": offset,
780
+ "email_type": email_type,
781
+ "status": status,
782
+ "since_timestamp_opt": since_timestamp_opt,
783
+ "before_timestamp_opt": before_timestamp_opt,
784
+ "since_last_changed": since_last_changed,
785
+ "before_last_changed": before_last_changed,
786
+ "unique_email_id": unique_email_id,
787
+ "vip_only": vip_only,
788
+ "interest_category_id": interest_category_id,
789
+ "interest_ids": interest_ids,
790
+ "interest_match": interest_match,
791
+ "sort_field": sort_field,
792
+ "sort_dir": sort_dir,
793
+ **kwargs
794
+ }.items() if v is not None}
795
+
796
+ result = await self._connector.execute("list_members", "list", params)
797
+ # Cast generic envelope to concrete typed result
798
+ return ListMembersListResult(
799
+ data=result.data,
800
+ meta=result.meta
801
+ )
802
+
803
+
804
+
805
+ async def get(
806
+ self,
807
+ list_id: str,
808
+ subscriber_hash: str,
809
+ **kwargs
810
+ ) -> ListMember:
811
+ """
812
+ Get information about a specific list member
813
+
814
+ Args:
815
+ list_id: The unique ID for the list
816
+ subscriber_hash: The MD5 hash of the lowercase version of the list member's email address
817
+ **kwargs: Additional parameters
818
+
819
+ Returns:
820
+ ListMember
821
+ """
822
+ params = {k: v for k, v in {
823
+ "list_id": list_id,
824
+ "subscriber_hash": subscriber_hash,
825
+ **kwargs
826
+ }.items() if v is not None}
827
+
828
+ result = await self._connector.execute("list_members", "get", params)
829
+ return result
830
+
831
+
832
+
833
+ class ReportsQuery:
834
+ """
835
+ Query class for Reports entity operations.
836
+ """
837
+
838
+ def __init__(self, connector: MailchimpConnector):
839
+ """Initialize query with connector reference."""
840
+ self._connector = connector
841
+
842
+ async def list(
843
+ self,
844
+ count: int | None = None,
845
+ offset: int | None = None,
846
+ type: str | None = None,
847
+ before_send_time: str | None = None,
848
+ since_send_time: str | None = None,
849
+ **kwargs
850
+ ) -> ReportsListResult:
851
+ """
852
+ Get campaign reports
853
+
854
+ Args:
855
+ count: The number of records to return
856
+ offset: Used for pagination
857
+ type: The campaign type
858
+ before_send_time: Restrict the response to campaigns sent before the set time
859
+ since_send_time: Restrict the response to campaigns sent after the set time
860
+ **kwargs: Additional parameters
861
+
862
+ Returns:
863
+ ReportsListResult
864
+ """
865
+ params = {k: v for k, v in {
866
+ "count": count,
867
+ "offset": offset,
868
+ "type": type,
869
+ "before_send_time": before_send_time,
870
+ "since_send_time": since_send_time,
871
+ **kwargs
872
+ }.items() if v is not None}
873
+
874
+ result = await self._connector.execute("reports", "list", params)
875
+ # Cast generic envelope to concrete typed result
876
+ return ReportsListResult(
877
+ data=result.data,
878
+ meta=result.meta
879
+ )
880
+
881
+
882
+
883
+ async def get(
884
+ self,
885
+ campaign_id: str,
886
+ **kwargs
887
+ ) -> Report:
888
+ """
889
+ Get report details for a specific sent campaign
890
+
891
+ Args:
892
+ campaign_id: The unique id for the campaign
893
+ **kwargs: Additional parameters
894
+
895
+ Returns:
896
+ Report
897
+ """
898
+ params = {k: v for k, v in {
899
+ "campaign_id": campaign_id,
900
+ **kwargs
901
+ }.items() if v is not None}
902
+
903
+ result = await self._connector.execute("reports", "get", params)
904
+ return result
905
+
906
+
907
+
908
+ class EmailActivityQuery:
909
+ """
910
+ Query class for EmailActivity entity operations.
911
+ """
912
+
913
+ def __init__(self, connector: MailchimpConnector):
914
+ """Initialize query with connector reference."""
915
+ self._connector = connector
916
+
917
+ async def list(
918
+ self,
919
+ campaign_id: str,
920
+ count: int | None = None,
921
+ offset: int | None = None,
922
+ since: str | None = None,
923
+ **kwargs
924
+ ) -> EmailActivityListResult:
925
+ """
926
+ Get a list of member's subscriber activity in a specific campaign
927
+
928
+ Args:
929
+ campaign_id: The unique id for the campaign
930
+ count: The number of records to return
931
+ offset: Used for pagination
932
+ since: Restrict results to email activity events that occur after a specific time
933
+ **kwargs: Additional parameters
934
+
935
+ Returns:
936
+ EmailActivityListResult
937
+ """
938
+ params = {k: v for k, v in {
939
+ "campaign_id": campaign_id,
940
+ "count": count,
941
+ "offset": offset,
942
+ "since": since,
943
+ **kwargs
944
+ }.items() if v is not None}
945
+
946
+ result = await self._connector.execute("email_activity", "list", params)
947
+ # Cast generic envelope to concrete typed result
948
+ return EmailActivityListResult(
949
+ data=result.data,
950
+ meta=result.meta
951
+ )
952
+
953
+
954
+
955
+ class AutomationsQuery:
956
+ """
957
+ Query class for Automations entity operations.
958
+ """
959
+
960
+ def __init__(self, connector: MailchimpConnector):
961
+ """Initialize query with connector reference."""
962
+ self._connector = connector
963
+
964
+ async def list(
965
+ self,
966
+ count: int | None = None,
967
+ offset: int | None = None,
968
+ before_create_time: str | None = None,
969
+ since_create_time: str | None = None,
970
+ before_start_time: str | None = None,
971
+ since_start_time: str | None = None,
972
+ status: str | None = None,
973
+ **kwargs
974
+ ) -> AutomationsListResult:
975
+ """
976
+ Get a summary of an account's classic automations
977
+
978
+ Args:
979
+ count: The number of records to return
980
+ offset: Used for pagination
981
+ before_create_time: Restrict the response to automations created before this time
982
+ since_create_time: Restrict the response to automations created after this time
983
+ before_start_time: Restrict the response to automations started before this time
984
+ since_start_time: Restrict the response to automations started after this time
985
+ status: Restrict the results to automations with the specified status
986
+ **kwargs: Additional parameters
987
+
988
+ Returns:
989
+ AutomationsListResult
990
+ """
991
+ params = {k: v for k, v in {
992
+ "count": count,
993
+ "offset": offset,
994
+ "before_create_time": before_create_time,
995
+ "since_create_time": since_create_time,
996
+ "before_start_time": before_start_time,
997
+ "since_start_time": since_start_time,
998
+ "status": status,
999
+ **kwargs
1000
+ }.items() if v is not None}
1001
+
1002
+ result = await self._connector.execute("automations", "list", params)
1003
+ # Cast generic envelope to concrete typed result
1004
+ return AutomationsListResult(
1005
+ data=result.data,
1006
+ meta=result.meta
1007
+ )
1008
+
1009
+
1010
+
1011
+ class TagsQuery:
1012
+ """
1013
+ Query class for Tags entity operations.
1014
+ """
1015
+
1016
+ def __init__(self, connector: MailchimpConnector):
1017
+ """Initialize query with connector reference."""
1018
+ self._connector = connector
1019
+
1020
+ async def list(
1021
+ self,
1022
+ list_id: str,
1023
+ name: str | None = None,
1024
+ **kwargs
1025
+ ) -> TagsListResult:
1026
+ """
1027
+ Search for tags on a list by name
1028
+
1029
+ Args:
1030
+ list_id: The unique ID for the list
1031
+ name: The search query used to filter tags
1032
+ **kwargs: Additional parameters
1033
+
1034
+ Returns:
1035
+ TagsListResult
1036
+ """
1037
+ params = {k: v for k, v in {
1038
+ "list_id": list_id,
1039
+ "name": name,
1040
+ **kwargs
1041
+ }.items() if v is not None}
1042
+
1043
+ result = await self._connector.execute("tags", "list", params)
1044
+ # Cast generic envelope to concrete typed result
1045
+ return TagsListResult(
1046
+ data=result.data,
1047
+ meta=result.meta
1048
+ )
1049
+
1050
+
1051
+
1052
+ class InterestCategoriesQuery:
1053
+ """
1054
+ Query class for InterestCategories entity operations.
1055
+ """
1056
+
1057
+ def __init__(self, connector: MailchimpConnector):
1058
+ """Initialize query with connector reference."""
1059
+ self._connector = connector
1060
+
1061
+ async def list(
1062
+ self,
1063
+ list_id: str,
1064
+ count: int | None = None,
1065
+ offset: int | None = None,
1066
+ **kwargs
1067
+ ) -> InterestCategoriesListResult:
1068
+ """
1069
+ Get information about a list's interest categories
1070
+
1071
+ Args:
1072
+ list_id: The unique ID for the list
1073
+ count: The number of records to return
1074
+ offset: Used for pagination
1075
+ **kwargs: Additional parameters
1076
+
1077
+ Returns:
1078
+ InterestCategoriesListResult
1079
+ """
1080
+ params = {k: v for k, v in {
1081
+ "list_id": list_id,
1082
+ "count": count,
1083
+ "offset": offset,
1084
+ **kwargs
1085
+ }.items() if v is not None}
1086
+
1087
+ result = await self._connector.execute("interest_categories", "list", params)
1088
+ # Cast generic envelope to concrete typed result
1089
+ return InterestCategoriesListResult(
1090
+ data=result.data,
1091
+ meta=result.meta
1092
+ )
1093
+
1094
+
1095
+
1096
+ async def get(
1097
+ self,
1098
+ list_id: str,
1099
+ interest_category_id: str,
1100
+ **kwargs
1101
+ ) -> InterestCategory:
1102
+ """
1103
+ Get information about a specific interest category
1104
+
1105
+ Args:
1106
+ list_id: The unique ID for the list
1107
+ interest_category_id: The unique ID for the interest category
1108
+ **kwargs: Additional parameters
1109
+
1110
+ Returns:
1111
+ InterestCategory
1112
+ """
1113
+ params = {k: v for k, v in {
1114
+ "list_id": list_id,
1115
+ "interest_category_id": interest_category_id,
1116
+ **kwargs
1117
+ }.items() if v is not None}
1118
+
1119
+ result = await self._connector.execute("interest_categories", "get", params)
1120
+ return result
1121
+
1122
+
1123
+
1124
+ class InterestsQuery:
1125
+ """
1126
+ Query class for Interests entity operations.
1127
+ """
1128
+
1129
+ def __init__(self, connector: MailchimpConnector):
1130
+ """Initialize query with connector reference."""
1131
+ self._connector = connector
1132
+
1133
+ async def list(
1134
+ self,
1135
+ list_id: str,
1136
+ interest_category_id: str,
1137
+ count: int | None = None,
1138
+ offset: int | None = None,
1139
+ **kwargs
1140
+ ) -> InterestsListResult:
1141
+ """
1142
+ Get a list of this category's interests
1143
+
1144
+ Args:
1145
+ list_id: The unique ID for the list
1146
+ interest_category_id: The unique ID for the interest category
1147
+ count: The number of records to return
1148
+ offset: Used for pagination
1149
+ **kwargs: Additional parameters
1150
+
1151
+ Returns:
1152
+ InterestsListResult
1153
+ """
1154
+ params = {k: v for k, v in {
1155
+ "list_id": list_id,
1156
+ "interest_category_id": interest_category_id,
1157
+ "count": count,
1158
+ "offset": offset,
1159
+ **kwargs
1160
+ }.items() if v is not None}
1161
+
1162
+ result = await self._connector.execute("interests", "list", params)
1163
+ # Cast generic envelope to concrete typed result
1164
+ return InterestsListResult(
1165
+ data=result.data,
1166
+ meta=result.meta
1167
+ )
1168
+
1169
+
1170
+
1171
+ async def get(
1172
+ self,
1173
+ list_id: str,
1174
+ interest_category_id: str,
1175
+ interest_id: str,
1176
+ **kwargs
1177
+ ) -> Interest:
1178
+ """
1179
+ Get interests or group names for a specific category
1180
+
1181
+ Args:
1182
+ list_id: The unique ID for the list
1183
+ interest_category_id: The unique ID for the interest category
1184
+ interest_id: The specific interest or group name
1185
+ **kwargs: Additional parameters
1186
+
1187
+ Returns:
1188
+ Interest
1189
+ """
1190
+ params = {k: v for k, v in {
1191
+ "list_id": list_id,
1192
+ "interest_category_id": interest_category_id,
1193
+ "interest_id": interest_id,
1194
+ **kwargs
1195
+ }.items() if v is not None}
1196
+
1197
+ result = await self._connector.execute("interests", "get", params)
1198
+ return result
1199
+
1200
+
1201
+
1202
+ class SegmentsQuery:
1203
+ """
1204
+ Query class for Segments entity operations.
1205
+ """
1206
+
1207
+ def __init__(self, connector: MailchimpConnector):
1208
+ """Initialize query with connector reference."""
1209
+ self._connector = connector
1210
+
1211
+ async def list(
1212
+ self,
1213
+ list_id: str,
1214
+ count: int | None = None,
1215
+ offset: int | None = None,
1216
+ type: str | None = None,
1217
+ since_created_at: str | None = None,
1218
+ before_created_at: str | None = None,
1219
+ since_updated_at: str | None = None,
1220
+ before_updated_at: str | None = None,
1221
+ **kwargs
1222
+ ) -> SegmentsListResult:
1223
+ """
1224
+ Get information about all available segments for a specific list
1225
+
1226
+ Args:
1227
+ list_id: The unique ID for the list
1228
+ count: The number of records to return
1229
+ offset: Used for pagination
1230
+ type: Limit results based on segment type
1231
+ since_created_at: Restrict results to segments created after the set time
1232
+ before_created_at: Restrict results to segments created before the set time
1233
+ since_updated_at: Restrict results to segments updated after the set time
1234
+ before_updated_at: Restrict results to segments updated before the set time
1235
+ **kwargs: Additional parameters
1236
+
1237
+ Returns:
1238
+ SegmentsListResult
1239
+ """
1240
+ params = {k: v for k, v in {
1241
+ "list_id": list_id,
1242
+ "count": count,
1243
+ "offset": offset,
1244
+ "type": type,
1245
+ "since_created_at": since_created_at,
1246
+ "before_created_at": before_created_at,
1247
+ "since_updated_at": since_updated_at,
1248
+ "before_updated_at": before_updated_at,
1249
+ **kwargs
1250
+ }.items() if v is not None}
1251
+
1252
+ result = await self._connector.execute("segments", "list", params)
1253
+ # Cast generic envelope to concrete typed result
1254
+ return SegmentsListResult(
1255
+ data=result.data,
1256
+ meta=result.meta
1257
+ )
1258
+
1259
+
1260
+
1261
+ async def get(
1262
+ self,
1263
+ list_id: str,
1264
+ segment_id: str,
1265
+ **kwargs
1266
+ ) -> Segment:
1267
+ """
1268
+ Get information about a specific segment
1269
+
1270
+ Args:
1271
+ list_id: The unique ID for the list
1272
+ segment_id: The unique id for the segment
1273
+ **kwargs: Additional parameters
1274
+
1275
+ Returns:
1276
+ Segment
1277
+ """
1278
+ params = {k: v for k, v in {
1279
+ "list_id": list_id,
1280
+ "segment_id": segment_id,
1281
+ **kwargs
1282
+ }.items() if v is not None}
1283
+
1284
+ result = await self._connector.execute("segments", "get", params)
1285
+ return result
1286
+
1287
+
1288
+
1289
+ class SegmentMembersQuery:
1290
+ """
1291
+ Query class for SegmentMembers entity operations.
1292
+ """
1293
+
1294
+ def __init__(self, connector: MailchimpConnector):
1295
+ """Initialize query with connector reference."""
1296
+ self._connector = connector
1297
+
1298
+ async def list(
1299
+ self,
1300
+ list_id: str,
1301
+ segment_id: str,
1302
+ count: int | None = None,
1303
+ offset: int | None = None,
1304
+ **kwargs
1305
+ ) -> SegmentMembersListResult:
1306
+ """
1307
+ Get information about members in a saved segment
1308
+
1309
+ Args:
1310
+ list_id: The unique ID for the list
1311
+ segment_id: The unique id for the segment
1312
+ count: The number of records to return
1313
+ offset: Used for pagination
1314
+ **kwargs: Additional parameters
1315
+
1316
+ Returns:
1317
+ SegmentMembersListResult
1318
+ """
1319
+ params = {k: v for k, v in {
1320
+ "list_id": list_id,
1321
+ "segment_id": segment_id,
1322
+ "count": count,
1323
+ "offset": offset,
1324
+ **kwargs
1325
+ }.items() if v is not None}
1326
+
1327
+ result = await self._connector.execute("segment_members", "list", params)
1328
+ # Cast generic envelope to concrete typed result
1329
+ return SegmentMembersListResult(
1330
+ data=result.data,
1331
+ meta=result.meta
1332
+ )
1333
+
1334
+
1335
+
1336
+ class UnsubscribesQuery:
1337
+ """
1338
+ Query class for Unsubscribes entity operations.
1339
+ """
1340
+
1341
+ def __init__(self, connector: MailchimpConnector):
1342
+ """Initialize query with connector reference."""
1343
+ self._connector = connector
1344
+
1345
+ async def list(
1346
+ self,
1347
+ campaign_id: str,
1348
+ count: int | None = None,
1349
+ offset: int | None = None,
1350
+ **kwargs
1351
+ ) -> UnsubscribesListResult:
1352
+ """
1353
+ Get information about members who have unsubscribed from a specific campaign
1354
+
1355
+ Args:
1356
+ campaign_id: The unique id for the campaign
1357
+ count: The number of records to return
1358
+ offset: Used for pagination
1359
+ **kwargs: Additional parameters
1360
+
1361
+ Returns:
1362
+ UnsubscribesListResult
1363
+ """
1364
+ params = {k: v for k, v in {
1365
+ "campaign_id": campaign_id,
1366
+ "count": count,
1367
+ "offset": offset,
1368
+ **kwargs
1369
+ }.items() if v is not None}
1370
+
1371
+ result = await self._connector.execute("unsubscribes", "list", params)
1372
+ # Cast generic envelope to concrete typed result
1373
+ return UnsubscribesListResult(
1374
+ data=result.data,
1375
+ meta=result.meta
1376
+ )
1377
+
1378
+