superposition-sdk 0.94.1__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.
@@ -0,0 +1,2744 @@
1
+ # Code generated by smithy-python-codegen DO NOT EDIT.
2
+
3
+ import asyncio
4
+ from asyncio import Future, iscoroutine, sleep
5
+ from copy import copy, deepcopy
6
+ from dataclasses import replace
7
+ import logging
8
+ import re
9
+ from typing import Any, Awaitable, Callable, cast
10
+
11
+ from smithy_core import URI
12
+ from smithy_core.deserializers import DeserializeableShape
13
+ from smithy_core.endpoints import EndpointResolverParams
14
+ from smithy_core.exceptions import SmithyRetryException
15
+ from smithy_core.interceptors import (
16
+ InputContext,
17
+ Interceptor,
18
+ InterceptorChain,
19
+ OutputContext,
20
+ RequestContext,
21
+ ResponseContext,
22
+ )
23
+ from smithy_core.interfaces.exceptions import HasFault
24
+ from smithy_core.interfaces.identity import Identity
25
+ from smithy_core.interfaces.retries import RetryErrorInfo, RetryErrorType
26
+ from smithy_core.schemas import APIOperation
27
+ from smithy_core.serializers import SerializeableShape
28
+ from smithy_core.types import PropertyKey, TypedProperties
29
+ from smithy_http.aio.interfaces import HTTPRequest, HTTPResponse
30
+ from smithy_http.aio.interfaces.auth import HTTPAuthOption, HTTPSigner
31
+ from smithy_http.interfaces import HTTPRequestConfiguration
32
+ from smithy_http.plugins import user_agent_plugin
33
+
34
+ from .auth import HTTPAuthParams
35
+ from .config import Config, Plugin
36
+ from .deserialize import (
37
+ _deserialize_add_members_to_group,
38
+ _deserialize_applicable_variants,
39
+ _deserialize_bulk_operation,
40
+ _deserialize_conclude_experiment,
41
+ _deserialize_create_context,
42
+ _deserialize_create_default_config,
43
+ _deserialize_create_dimension,
44
+ _deserialize_create_experiment,
45
+ _deserialize_create_experiment_group,
46
+ _deserialize_create_function,
47
+ _deserialize_create_organisation,
48
+ _deserialize_create_type_templates,
49
+ _deserialize_create_webhook,
50
+ _deserialize_create_workspace,
51
+ _deserialize_delete_context,
52
+ _deserialize_delete_default_config,
53
+ _deserialize_delete_dimension,
54
+ _deserialize_delete_experiment_group,
55
+ _deserialize_delete_function,
56
+ _deserialize_delete_type_templates,
57
+ _deserialize_delete_webhook,
58
+ _deserialize_discard_experiment,
59
+ _deserialize_get_config,
60
+ _deserialize_get_config_fast,
61
+ _deserialize_get_context,
62
+ _deserialize_get_context_from_condition,
63
+ _deserialize_get_default_config,
64
+ _deserialize_get_dimension,
65
+ _deserialize_get_experiment,
66
+ _deserialize_get_experiment_group,
67
+ _deserialize_get_function,
68
+ _deserialize_get_organisation,
69
+ _deserialize_get_resolved_config,
70
+ _deserialize_get_type_template,
71
+ _deserialize_get_type_templates_list,
72
+ _deserialize_get_version,
73
+ _deserialize_get_webhook,
74
+ _deserialize_get_webhook_by_event,
75
+ _deserialize_get_workspace,
76
+ _deserialize_list_audit_logs,
77
+ _deserialize_list_contexts,
78
+ _deserialize_list_default_configs,
79
+ _deserialize_list_dimensions,
80
+ _deserialize_list_experiment,
81
+ _deserialize_list_experiment_groups,
82
+ _deserialize_list_function,
83
+ _deserialize_list_organisation,
84
+ _deserialize_list_versions,
85
+ _deserialize_list_webhook,
86
+ _deserialize_list_workspace,
87
+ _deserialize_migrate_workspace_schema,
88
+ _deserialize_move_context,
89
+ _deserialize_pause_experiment,
90
+ _deserialize_publish,
91
+ _deserialize_ramp_experiment,
92
+ _deserialize_remove_members_from_group,
93
+ _deserialize_resume_experiment,
94
+ _deserialize_test,
95
+ _deserialize_update_default_config,
96
+ _deserialize_update_dimension,
97
+ _deserialize_update_experiment_group,
98
+ _deserialize_update_function,
99
+ _deserialize_update_organisation,
100
+ _deserialize_update_override,
101
+ _deserialize_update_overrides_experiment,
102
+ _deserialize_update_type_templates,
103
+ _deserialize_update_webhook,
104
+ _deserialize_update_workspace,
105
+ _deserialize_validate_context,
106
+ _deserialize_weight_recompute,
107
+ )
108
+ from .models import (
109
+ ADD_MEMBERS_TO_GROUP,
110
+ APPLICABLE_VARIANTS,
111
+ AddMembersToGroupInput,
112
+ AddMembersToGroupOutput,
113
+ ApplicableVariantsInput,
114
+ ApplicableVariantsOutput,
115
+ BULK_OPERATION,
116
+ BulkOperationInput,
117
+ BulkOperationOutput,
118
+ CONCLUDE_EXPERIMENT,
119
+ CREATE_CONTEXT,
120
+ CREATE_DEFAULT_CONFIG,
121
+ CREATE_DIMENSION,
122
+ CREATE_EXPERIMENT,
123
+ CREATE_EXPERIMENT_GROUP,
124
+ CREATE_FUNCTION,
125
+ CREATE_ORGANISATION,
126
+ CREATE_TYPE_TEMPLATES,
127
+ CREATE_WEBHOOK,
128
+ CREATE_WORKSPACE,
129
+ ConcludeExperimentInput,
130
+ ConcludeExperimentOutput,
131
+ CreateContextInput,
132
+ CreateContextOutput,
133
+ CreateDefaultConfigInput,
134
+ CreateDefaultConfigOutput,
135
+ CreateDimensionInput,
136
+ CreateDimensionOutput,
137
+ CreateExperimentGroupInput,
138
+ CreateExperimentGroupOutput,
139
+ CreateExperimentInput,
140
+ CreateExperimentOutput,
141
+ CreateFunctionInput,
142
+ CreateFunctionOutput,
143
+ CreateOrganisationInput,
144
+ CreateOrganisationOutput,
145
+ CreateTypeTemplatesInput,
146
+ CreateTypeTemplatesOutput,
147
+ CreateWebhookInput,
148
+ CreateWebhookOutput,
149
+ CreateWorkspaceInput,
150
+ CreateWorkspaceOutput,
151
+ DELETE_CONTEXT,
152
+ DELETE_DEFAULT_CONFIG,
153
+ DELETE_DIMENSION,
154
+ DELETE_EXPERIMENT_GROUP,
155
+ DELETE_FUNCTION,
156
+ DELETE_TYPE_TEMPLATES,
157
+ DELETE_WEBHOOK,
158
+ DISCARD_EXPERIMENT,
159
+ DeleteContextInput,
160
+ DeleteContextOutput,
161
+ DeleteDefaultConfigInput,
162
+ DeleteDefaultConfigOutput,
163
+ DeleteDimensionInput,
164
+ DeleteDimensionOutput,
165
+ DeleteExperimentGroupInput,
166
+ DeleteExperimentGroupOutput,
167
+ DeleteFunctionInput,
168
+ DeleteFunctionOutput,
169
+ DeleteTypeTemplatesInput,
170
+ DeleteTypeTemplatesOutput,
171
+ DeleteWebhookInput,
172
+ DeleteWebhookOutput,
173
+ DiscardExperimentInput,
174
+ DiscardExperimentOutput,
175
+ GET_CONFIG,
176
+ GET_CONFIG_FAST,
177
+ GET_CONTEXT,
178
+ GET_CONTEXT_FROM_CONDITION,
179
+ GET_DEFAULT_CONFIG,
180
+ GET_DIMENSION,
181
+ GET_EXPERIMENT,
182
+ GET_EXPERIMENT_GROUP,
183
+ GET_FUNCTION,
184
+ GET_ORGANISATION,
185
+ GET_RESOLVED_CONFIG,
186
+ GET_TYPE_TEMPLATE,
187
+ GET_TYPE_TEMPLATES_LIST,
188
+ GET_VERSION,
189
+ GET_WEBHOOK,
190
+ GET_WEBHOOK_BY_EVENT,
191
+ GET_WORKSPACE,
192
+ GetConfigFastInput,
193
+ GetConfigFastOutput,
194
+ GetConfigInput,
195
+ GetConfigOutput,
196
+ GetContextFromConditionInput,
197
+ GetContextFromConditionOutput,
198
+ GetContextInput,
199
+ GetContextOutput,
200
+ GetDefaultConfigInput,
201
+ GetDefaultConfigOutput,
202
+ GetDimensionInput,
203
+ GetDimensionOutput,
204
+ GetExperimentGroupInput,
205
+ GetExperimentGroupOutput,
206
+ GetExperimentInput,
207
+ GetExperimentOutput,
208
+ GetFunctionInput,
209
+ GetFunctionOutput,
210
+ GetOrganisationInput,
211
+ GetOrganisationOutput,
212
+ GetResolvedConfigInput,
213
+ GetResolvedConfigOutput,
214
+ GetTypeTemplateInput,
215
+ GetTypeTemplateOutput,
216
+ GetTypeTemplatesListInput,
217
+ GetTypeTemplatesListOutput,
218
+ GetVersionInput,
219
+ GetVersionOutput,
220
+ GetWebhookByEventInput,
221
+ GetWebhookByEventOutput,
222
+ GetWebhookInput,
223
+ GetWebhookOutput,
224
+ GetWorkspaceInput,
225
+ GetWorkspaceOutput,
226
+ LIST_AUDIT_LOGS,
227
+ LIST_CONTEXTS,
228
+ LIST_DEFAULT_CONFIGS,
229
+ LIST_DIMENSIONS,
230
+ LIST_EXPERIMENT,
231
+ LIST_EXPERIMENT_GROUPS,
232
+ LIST_FUNCTION,
233
+ LIST_ORGANISATION,
234
+ LIST_VERSIONS,
235
+ LIST_WEBHOOK,
236
+ LIST_WORKSPACE,
237
+ ListAuditLogsInput,
238
+ ListAuditLogsOutput,
239
+ ListContextsInput,
240
+ ListContextsOutput,
241
+ ListDefaultConfigsInput,
242
+ ListDefaultConfigsOutput,
243
+ ListDimensionsInput,
244
+ ListDimensionsOutput,
245
+ ListExperimentGroupsInput,
246
+ ListExperimentGroupsOutput,
247
+ ListExperimentInput,
248
+ ListExperimentOutput,
249
+ ListFunctionInput,
250
+ ListFunctionOutput,
251
+ ListOrganisationInput,
252
+ ListOrganisationOutput,
253
+ ListVersionsInput,
254
+ ListVersionsOutput,
255
+ ListWebhookInput,
256
+ ListWebhookOutput,
257
+ ListWorkspaceInput,
258
+ ListWorkspaceOutput,
259
+ MIGRATE_WORKSPACE_SCHEMA,
260
+ MOVE_CONTEXT,
261
+ MigrateWorkspaceSchemaInput,
262
+ MigrateWorkspaceSchemaOutput,
263
+ MoveContextInput,
264
+ MoveContextOutput,
265
+ PAUSE_EXPERIMENT,
266
+ PUBLISH,
267
+ PauseExperimentInput,
268
+ PauseExperimentOutput,
269
+ PublishInput,
270
+ PublishOutput,
271
+ RAMP_EXPERIMENT,
272
+ REMOVE_MEMBERS_FROM_GROUP,
273
+ RESUME_EXPERIMENT,
274
+ RampExperimentInput,
275
+ RampExperimentOutput,
276
+ RemoveMembersFromGroupInput,
277
+ RemoveMembersFromGroupOutput,
278
+ ResumeExperimentInput,
279
+ ResumeExperimentOutput,
280
+ ServiceError,
281
+ TEST,
282
+ TestInput,
283
+ TestOutput,
284
+ UPDATE_DEFAULT_CONFIG,
285
+ UPDATE_DIMENSION,
286
+ UPDATE_EXPERIMENT_GROUP,
287
+ UPDATE_FUNCTION,
288
+ UPDATE_ORGANISATION,
289
+ UPDATE_OVERRIDE,
290
+ UPDATE_OVERRIDES_EXPERIMENT,
291
+ UPDATE_TYPE_TEMPLATES,
292
+ UPDATE_WEBHOOK,
293
+ UPDATE_WORKSPACE,
294
+ UpdateDefaultConfigInput,
295
+ UpdateDefaultConfigOutput,
296
+ UpdateDimensionInput,
297
+ UpdateDimensionOutput,
298
+ UpdateExperimentGroupInput,
299
+ UpdateExperimentGroupOutput,
300
+ UpdateFunctionInput,
301
+ UpdateFunctionOutput,
302
+ UpdateOrganisationInput,
303
+ UpdateOrganisationOutput,
304
+ UpdateOverrideInput,
305
+ UpdateOverrideOutput,
306
+ UpdateOverridesExperimentInput,
307
+ UpdateOverridesExperimentOutput,
308
+ UpdateTypeTemplatesInput,
309
+ UpdateTypeTemplatesOutput,
310
+ UpdateWebhookInput,
311
+ UpdateWebhookOutput,
312
+ UpdateWorkspaceInput,
313
+ UpdateWorkspaceOutput,
314
+ VALIDATE_CONTEXT,
315
+ ValidateContextInput,
316
+ ValidateContextOutput,
317
+ WEIGHT_RECOMPUTE,
318
+ WeightRecomputeInput,
319
+ WeightRecomputeOutput,
320
+ )
321
+ from .serialize import (
322
+ _serialize_add_members_to_group,
323
+ _serialize_applicable_variants,
324
+ _serialize_bulk_operation,
325
+ _serialize_conclude_experiment,
326
+ _serialize_create_context,
327
+ _serialize_create_default_config,
328
+ _serialize_create_dimension,
329
+ _serialize_create_experiment,
330
+ _serialize_create_experiment_group,
331
+ _serialize_create_function,
332
+ _serialize_create_organisation,
333
+ _serialize_create_type_templates,
334
+ _serialize_create_webhook,
335
+ _serialize_create_workspace,
336
+ _serialize_delete_context,
337
+ _serialize_delete_default_config,
338
+ _serialize_delete_dimension,
339
+ _serialize_delete_experiment_group,
340
+ _serialize_delete_function,
341
+ _serialize_delete_type_templates,
342
+ _serialize_delete_webhook,
343
+ _serialize_discard_experiment,
344
+ _serialize_get_config,
345
+ _serialize_get_config_fast,
346
+ _serialize_get_context,
347
+ _serialize_get_context_from_condition,
348
+ _serialize_get_default_config,
349
+ _serialize_get_dimension,
350
+ _serialize_get_experiment,
351
+ _serialize_get_experiment_group,
352
+ _serialize_get_function,
353
+ _serialize_get_organisation,
354
+ _serialize_get_resolved_config,
355
+ _serialize_get_type_template,
356
+ _serialize_get_type_templates_list,
357
+ _serialize_get_version,
358
+ _serialize_get_webhook,
359
+ _serialize_get_webhook_by_event,
360
+ _serialize_get_workspace,
361
+ _serialize_list_audit_logs,
362
+ _serialize_list_contexts,
363
+ _serialize_list_default_configs,
364
+ _serialize_list_dimensions,
365
+ _serialize_list_experiment,
366
+ _serialize_list_experiment_groups,
367
+ _serialize_list_function,
368
+ _serialize_list_organisation,
369
+ _serialize_list_versions,
370
+ _serialize_list_webhook,
371
+ _serialize_list_workspace,
372
+ _serialize_migrate_workspace_schema,
373
+ _serialize_move_context,
374
+ _serialize_pause_experiment,
375
+ _serialize_publish,
376
+ _serialize_ramp_experiment,
377
+ _serialize_remove_members_from_group,
378
+ _serialize_resume_experiment,
379
+ _serialize_test,
380
+ _serialize_update_default_config,
381
+ _serialize_update_dimension,
382
+ _serialize_update_experiment_group,
383
+ _serialize_update_function,
384
+ _serialize_update_organisation,
385
+ _serialize_update_override,
386
+ _serialize_update_overrides_experiment,
387
+ _serialize_update_type_templates,
388
+ _serialize_update_webhook,
389
+ _serialize_update_workspace,
390
+ _serialize_validate_context,
391
+ _serialize_weight_recompute,
392
+ )
393
+
394
+
395
+
396
+ logger = logging.getLogger(__name__)
397
+
398
+ class Superposition:
399
+ """
400
+ Client for Superposition
401
+
402
+ :param config: Optional configuration for the client. Here you can set things like the
403
+ endpoint for HTTP services or auth credentials.
404
+
405
+ :param plugins: A list of callables that modify the configuration dynamically. These
406
+ can be used to set defaults, for example.
407
+ """
408
+ def __init__(self, config: Config | None = None, plugins: list[Plugin] | None = None):
409
+ self._config = config or Config()
410
+
411
+ client_plugins: list[Plugin] = [
412
+ user_agent_plugin,
413
+ ]
414
+ if plugins:
415
+ client_plugins.extend(plugins)
416
+
417
+ for plugin in client_plugins:
418
+ plugin(self._config)
419
+
420
+ async def add_members_to_group(self, input: AddMembersToGroupInput, plugins: list[Plugin] | None = None) -> AddMembersToGroupOutput:
421
+ """
422
+ Adds members to an existing experiment group.
423
+
424
+ :param input: Input structure for adding members to an experiment group.
425
+
426
+ :param plugins: A list of callables that modify the configuration dynamically.
427
+ Changes made by these plugins only apply for the duration of the operation
428
+ execution and will not affect any other operation invocations.
429
+
430
+ """
431
+ operation_plugins: list[Plugin] = [
432
+
433
+ ]
434
+ if plugins:
435
+ operation_plugins.extend(plugins)
436
+
437
+ return await self._execute_operation(
438
+ input=input,
439
+ plugins=operation_plugins,
440
+ serialize=_serialize_add_members_to_group,
441
+ deserialize=_deserialize_add_members_to_group,
442
+ config=self._config,
443
+ operation=ADD_MEMBERS_TO_GROUP,
444
+ )
445
+
446
+ async def applicable_variants(self, input: ApplicableVariantsInput, plugins: list[Plugin] | None = None) -> ApplicableVariantsOutput:
447
+ """
448
+ Determines which experiment variants are applicable to a given context, used for
449
+ experiment evaluation and variant selection.
450
+
451
+ :param input: The operation's input.
452
+
453
+ :param plugins: A list of callables that modify the configuration dynamically.
454
+ Changes made by these plugins only apply for the duration of the operation
455
+ execution and will not affect any other operation invocations.
456
+
457
+ """
458
+ operation_plugins: list[Plugin] = [
459
+
460
+ ]
461
+ if plugins:
462
+ operation_plugins.extend(plugins)
463
+
464
+ return await self._execute_operation(
465
+ input=input,
466
+ plugins=operation_plugins,
467
+ serialize=_serialize_applicable_variants,
468
+ deserialize=_deserialize_applicable_variants,
469
+ config=self._config,
470
+ operation=APPLICABLE_VARIANTS,
471
+ )
472
+
473
+ async def bulk_operation(self, input: BulkOperationInput, plugins: list[Plugin] | None = None) -> BulkOperationOutput:
474
+ """
475
+ Executes multiple context operations (PUT, REPLACE, DELETE, MOVE) in a single
476
+ atomic transaction for efficient batch processing.
477
+
478
+ :param input: The operation's input.
479
+
480
+ :param plugins: A list of callables that modify the configuration dynamically.
481
+ Changes made by these plugins only apply for the duration of the operation
482
+ execution and will not affect any other operation invocations.
483
+
484
+ """
485
+ operation_plugins: list[Plugin] = [
486
+
487
+ ]
488
+ if plugins:
489
+ operation_plugins.extend(plugins)
490
+
491
+ return await self._execute_operation(
492
+ input=input,
493
+ plugins=operation_plugins,
494
+ serialize=_serialize_bulk_operation,
495
+ deserialize=_deserialize_bulk_operation,
496
+ config=self._config,
497
+ operation=BULK_OPERATION,
498
+ )
499
+
500
+ async def conclude_experiment(self, input: ConcludeExperimentInput, plugins: list[Plugin] | None = None) -> ConcludeExperimentOutput:
501
+ """
502
+ Concludes an inprogress experiment by selecting a winning variant and
503
+ transitioning the experiment to a concluded state.
504
+
505
+ :param input: The operation's input.
506
+
507
+ :param plugins: A list of callables that modify the configuration dynamically.
508
+ Changes made by these plugins only apply for the duration of the operation
509
+ execution and will not affect any other operation invocations.
510
+
511
+ """
512
+ operation_plugins: list[Plugin] = [
513
+
514
+ ]
515
+ if plugins:
516
+ operation_plugins.extend(plugins)
517
+
518
+ return await self._execute_operation(
519
+ input=input,
520
+ plugins=operation_plugins,
521
+ serialize=_serialize_conclude_experiment,
522
+ deserialize=_deserialize_conclude_experiment,
523
+ config=self._config,
524
+ operation=CONCLUDE_EXPERIMENT,
525
+ )
526
+
527
+ async def create_context(self, input: CreateContextInput, plugins: list[Plugin] | None = None) -> CreateContextOutput:
528
+ """
529
+ Creates a new context with specified conditions and overrides. Contexts define
530
+ conditional rules for config management.
531
+
532
+ :param input: The operation's input.
533
+
534
+ :param plugins: A list of callables that modify the configuration dynamically.
535
+ Changes made by these plugins only apply for the duration of the operation
536
+ execution and will not affect any other operation invocations.
537
+
538
+ """
539
+ operation_plugins: list[Plugin] = [
540
+
541
+ ]
542
+ if plugins:
543
+ operation_plugins.extend(plugins)
544
+
545
+ return await self._execute_operation(
546
+ input=input,
547
+ plugins=operation_plugins,
548
+ serialize=_serialize_create_context,
549
+ deserialize=_deserialize_create_context,
550
+ config=self._config,
551
+ operation=CREATE_CONTEXT,
552
+ )
553
+
554
+ async def create_default_config(self, input: CreateDefaultConfigInput, plugins: list[Plugin] | None = None) -> CreateDefaultConfigOutput:
555
+ """
556
+ Creates a new default config entry with specified key, value, schema, and
557
+ metadata. Default configs serve as fallback values when no specific context
558
+ matches.
559
+
560
+ :param input: The operation's input.
561
+
562
+ :param plugins: A list of callables that modify the configuration dynamically.
563
+ Changes made by these plugins only apply for the duration of the operation
564
+ execution and will not affect any other operation invocations.
565
+
566
+ """
567
+ operation_plugins: list[Plugin] = [
568
+
569
+ ]
570
+ if plugins:
571
+ operation_plugins.extend(plugins)
572
+
573
+ return await self._execute_operation(
574
+ input=input,
575
+ plugins=operation_plugins,
576
+ serialize=_serialize_create_default_config,
577
+ deserialize=_deserialize_create_default_config,
578
+ config=self._config,
579
+ operation=CREATE_DEFAULT_CONFIG,
580
+ )
581
+
582
+ async def create_dimension(self, input: CreateDimensionInput, plugins: list[Plugin] | None = None) -> CreateDimensionOutput:
583
+ """
584
+ Creates a new dimension with the specified json schema. Dimensions define
585
+ categorical attributes used for context-based config management.
586
+
587
+ :param input: The operation's input.
588
+
589
+ :param plugins: A list of callables that modify the configuration dynamically.
590
+ Changes made by these plugins only apply for the duration of the operation
591
+ execution and will not affect any other operation invocations.
592
+
593
+ """
594
+ operation_plugins: list[Plugin] = [
595
+
596
+ ]
597
+ if plugins:
598
+ operation_plugins.extend(plugins)
599
+
600
+ return await self._execute_operation(
601
+ input=input,
602
+ plugins=operation_plugins,
603
+ serialize=_serialize_create_dimension,
604
+ deserialize=_deserialize_create_dimension,
605
+ config=self._config,
606
+ operation=CREATE_DIMENSION,
607
+ )
608
+
609
+ async def create_experiment(self, input: CreateExperimentInput, plugins: list[Plugin] | None = None) -> CreateExperimentOutput:
610
+ """
611
+ Creates a new experiment with variants, context and conditions. You can
612
+ optionally specify metrics and experiment group for tracking and analysis.
613
+
614
+ :param input: The operation's input.
615
+
616
+ :param plugins: A list of callables that modify the configuration dynamically.
617
+ Changes made by these plugins only apply for the duration of the operation
618
+ execution and will not affect any other operation invocations.
619
+
620
+ """
621
+ operation_plugins: list[Plugin] = [
622
+
623
+ ]
624
+ if plugins:
625
+ operation_plugins.extend(plugins)
626
+
627
+ return await self._execute_operation(
628
+ input=input,
629
+ plugins=operation_plugins,
630
+ serialize=_serialize_create_experiment,
631
+ deserialize=_deserialize_create_experiment,
632
+ config=self._config,
633
+ operation=CREATE_EXPERIMENT,
634
+ )
635
+
636
+ async def create_experiment_group(self, input: CreateExperimentGroupInput, plugins: list[Plugin] | None = None) -> CreateExperimentGroupOutput:
637
+ """
638
+ Creates a new experiment group.
639
+
640
+ :param input: Input structure for creating a new experiment group.
641
+
642
+ :param plugins: A list of callables that modify the configuration dynamically.
643
+ Changes made by these plugins only apply for the duration of the operation
644
+ execution and will not affect any other operation invocations.
645
+
646
+ """
647
+ operation_plugins: list[Plugin] = [
648
+
649
+ ]
650
+ if plugins:
651
+ operation_plugins.extend(plugins)
652
+
653
+ return await self._execute_operation(
654
+ input=input,
655
+ plugins=operation_plugins,
656
+ serialize=_serialize_create_experiment_group,
657
+ deserialize=_deserialize_create_experiment_group,
658
+ config=self._config,
659
+ operation=CREATE_EXPERIMENT_GROUP,
660
+ )
661
+
662
+ async def create_function(self, input: CreateFunctionInput, plugins: list[Plugin] | None = None) -> CreateFunctionOutput:
663
+ """
664
+ Creates a new custom function for validation or autocompletion with specified
665
+ code, runtime version, and function type.
666
+
667
+ :param input: The operation's input.
668
+
669
+ :param plugins: A list of callables that modify the configuration dynamically.
670
+ Changes made by these plugins only apply for the duration of the operation
671
+ execution and will not affect any other operation invocations.
672
+
673
+ """
674
+ operation_plugins: list[Plugin] = [
675
+
676
+ ]
677
+ if plugins:
678
+ operation_plugins.extend(plugins)
679
+
680
+ return await self._execute_operation(
681
+ input=input,
682
+ plugins=operation_plugins,
683
+ serialize=_serialize_create_function,
684
+ deserialize=_deserialize_create_function,
685
+ config=self._config,
686
+ operation=CREATE_FUNCTION,
687
+ )
688
+
689
+ async def create_organisation(self, input: CreateOrganisationInput, plugins: list[Plugin] | None = None) -> CreateOrganisationOutput:
690
+ """
691
+ Creates a new organisation with specified name and administrator email. This is
692
+ the top-level entity that contains workspaces and manages organizational-level
693
+ settings.
694
+
695
+ :param input: The operation's input.
696
+
697
+ :param plugins: A list of callables that modify the configuration dynamically.
698
+ Changes made by these plugins only apply for the duration of the operation
699
+ execution and will not affect any other operation invocations.
700
+
701
+ """
702
+ operation_plugins: list[Plugin] = [
703
+
704
+ ]
705
+ if plugins:
706
+ operation_plugins.extend(plugins)
707
+
708
+ return await self._execute_operation(
709
+ input=input,
710
+ plugins=operation_plugins,
711
+ serialize=_serialize_create_organisation,
712
+ deserialize=_deserialize_create_organisation,
713
+ config=self._config,
714
+ operation=CREATE_ORGANISATION,
715
+ )
716
+
717
+ async def create_type_templates(self, input: CreateTypeTemplatesInput, plugins: list[Plugin] | None = None) -> CreateTypeTemplatesOutput:
718
+ """
719
+ Creates a new type template with specified schema definition, providing reusable
720
+ type definitions for config validation.
721
+
722
+ :param input: The operation's input.
723
+
724
+ :param plugins: A list of callables that modify the configuration dynamically.
725
+ Changes made by these plugins only apply for the duration of the operation
726
+ execution and will not affect any other operation invocations.
727
+
728
+ """
729
+ operation_plugins: list[Plugin] = [
730
+
731
+ ]
732
+ if plugins:
733
+ operation_plugins.extend(plugins)
734
+
735
+ return await self._execute_operation(
736
+ input=input,
737
+ plugins=operation_plugins,
738
+ serialize=_serialize_create_type_templates,
739
+ deserialize=_deserialize_create_type_templates,
740
+ config=self._config,
741
+ operation=CREATE_TYPE_TEMPLATES,
742
+ )
743
+
744
+ async def create_webhook(self, input: CreateWebhookInput, plugins: list[Plugin] | None = None) -> CreateWebhookOutput:
745
+ """
746
+ Creates a new webhook config to receive HTTP notifications when specified events
747
+ occur in the system.
748
+
749
+ :param input: The operation's input.
750
+
751
+ :param plugins: A list of callables that modify the configuration dynamically.
752
+ Changes made by these plugins only apply for the duration of the operation
753
+ execution and will not affect any other operation invocations.
754
+
755
+ """
756
+ operation_plugins: list[Plugin] = [
757
+
758
+ ]
759
+ if plugins:
760
+ operation_plugins.extend(plugins)
761
+
762
+ return await self._execute_operation(
763
+ input=input,
764
+ plugins=operation_plugins,
765
+ serialize=_serialize_create_webhook,
766
+ deserialize=_deserialize_create_webhook,
767
+ config=self._config,
768
+ operation=CREATE_WEBHOOK,
769
+ )
770
+
771
+ async def create_workspace(self, input: CreateWorkspaceInput, plugins: list[Plugin] | None = None) -> CreateWorkspaceOutput:
772
+ """
773
+ Creates a new workspace within an organisation, including database schema setup
774
+ and isolated environment for config management with specified admin and
775
+ settings.
776
+
777
+ :param input: The operation's input.
778
+
779
+ :param plugins: A list of callables that modify the configuration dynamically.
780
+ Changes made by these plugins only apply for the duration of the operation
781
+ execution and will not affect any other operation invocations.
782
+
783
+ """
784
+ operation_plugins: list[Plugin] = [
785
+
786
+ ]
787
+ if plugins:
788
+ operation_plugins.extend(plugins)
789
+
790
+ return await self._execute_operation(
791
+ input=input,
792
+ plugins=operation_plugins,
793
+ serialize=_serialize_create_workspace,
794
+ deserialize=_deserialize_create_workspace,
795
+ config=self._config,
796
+ operation=CREATE_WORKSPACE,
797
+ )
798
+
799
+ async def delete_context(self, input: DeleteContextInput, plugins: list[Plugin] | None = None) -> DeleteContextOutput:
800
+ """
801
+ Permanently removes a context from the workspace. This operation cannot be
802
+ undone and will affect config resolution.
803
+
804
+ :param input: The operation's input.
805
+
806
+ :param plugins: A list of callables that modify the configuration dynamically.
807
+ Changes made by these plugins only apply for the duration of the operation
808
+ execution and will not affect any other operation invocations.
809
+
810
+ """
811
+ operation_plugins: list[Plugin] = [
812
+
813
+ ]
814
+ if plugins:
815
+ operation_plugins.extend(plugins)
816
+
817
+ return await self._execute_operation(
818
+ input=input,
819
+ plugins=operation_plugins,
820
+ serialize=_serialize_delete_context,
821
+ deserialize=_deserialize_delete_context,
822
+ config=self._config,
823
+ operation=DELETE_CONTEXT,
824
+ )
825
+
826
+ async def delete_default_config(self, input: DeleteDefaultConfigInput, plugins: list[Plugin] | None = None) -> DeleteDefaultConfigOutput:
827
+ """
828
+ Permanently removes a default config entry from the workspace. This operation
829
+ cannot be performed if it affects config resolution for contexts that rely on
830
+ this fallback value.
831
+
832
+ :param input: The operation's input.
833
+
834
+ :param plugins: A list of callables that modify the configuration dynamically.
835
+ Changes made by these plugins only apply for the duration of the operation
836
+ execution and will not affect any other operation invocations.
837
+
838
+ """
839
+ operation_plugins: list[Plugin] = [
840
+
841
+ ]
842
+ if plugins:
843
+ operation_plugins.extend(plugins)
844
+
845
+ return await self._execute_operation(
846
+ input=input,
847
+ plugins=operation_plugins,
848
+ serialize=_serialize_delete_default_config,
849
+ deserialize=_deserialize_delete_default_config,
850
+ config=self._config,
851
+ operation=DELETE_DEFAULT_CONFIG,
852
+ )
853
+
854
+ async def delete_dimension(self, input: DeleteDimensionInput, plugins: list[Plugin] | None = None) -> DeleteDimensionOutput:
855
+ """
856
+ Permanently removes a dimension from the workspace. This operation will fail if
857
+ the dimension has active dependencies or is referenced by existing
858
+ configurations.
859
+
860
+ :param input: The operation's input.
861
+
862
+ :param plugins: A list of callables that modify the configuration dynamically.
863
+ Changes made by these plugins only apply for the duration of the operation
864
+ execution and will not affect any other operation invocations.
865
+
866
+ """
867
+ operation_plugins: list[Plugin] = [
868
+
869
+ ]
870
+ if plugins:
871
+ operation_plugins.extend(plugins)
872
+
873
+ return await self._execute_operation(
874
+ input=input,
875
+ plugins=operation_plugins,
876
+ serialize=_serialize_delete_dimension,
877
+ deserialize=_deserialize_delete_dimension,
878
+ config=self._config,
879
+ operation=DELETE_DIMENSION,
880
+ )
881
+
882
+ async def delete_experiment_group(self, input: DeleteExperimentGroupInput, plugins: list[Plugin] | None = None) -> DeleteExperimentGroupOutput:
883
+ """
884
+ Deletes an experiment group.
885
+
886
+ :param input: The operation's input.
887
+
888
+ :param plugins: A list of callables that modify the configuration dynamically.
889
+ Changes made by these plugins only apply for the duration of the operation
890
+ execution and will not affect any other operation invocations.
891
+
892
+ """
893
+ operation_plugins: list[Plugin] = [
894
+
895
+ ]
896
+ if plugins:
897
+ operation_plugins.extend(plugins)
898
+
899
+ return await self._execute_operation(
900
+ input=input,
901
+ plugins=operation_plugins,
902
+ serialize=_serialize_delete_experiment_group,
903
+ deserialize=_deserialize_delete_experiment_group,
904
+ config=self._config,
905
+ operation=DELETE_EXPERIMENT_GROUP,
906
+ )
907
+
908
+ async def delete_function(self, input: DeleteFunctionInput, plugins: list[Plugin] | None = None) -> DeleteFunctionOutput:
909
+ """
910
+ Permanently removes a function from the workspace, deleting both draft and
911
+ published versions along with all associated code. It fails if already in use
912
+
913
+ :param input: The operation's input.
914
+
915
+ :param plugins: A list of callables that modify the configuration dynamically.
916
+ Changes made by these plugins only apply for the duration of the operation
917
+ execution and will not affect any other operation invocations.
918
+
919
+ """
920
+ operation_plugins: list[Plugin] = [
921
+
922
+ ]
923
+ if plugins:
924
+ operation_plugins.extend(plugins)
925
+
926
+ return await self._execute_operation(
927
+ input=input,
928
+ plugins=operation_plugins,
929
+ serialize=_serialize_delete_function,
930
+ deserialize=_deserialize_delete_function,
931
+ config=self._config,
932
+ operation=DELETE_FUNCTION,
933
+ )
934
+
935
+ async def delete_type_templates(self, input: DeleteTypeTemplatesInput, plugins: list[Plugin] | None = None) -> DeleteTypeTemplatesOutput:
936
+ """
937
+ Permanently removes a type template from the workspace. No checks performed
938
+ while deleting
939
+
940
+ :param input: The operation's input.
941
+
942
+ :param plugins: A list of callables that modify the configuration dynamically.
943
+ Changes made by these plugins only apply for the duration of the operation
944
+ execution and will not affect any other operation invocations.
945
+
946
+ """
947
+ operation_plugins: list[Plugin] = [
948
+
949
+ ]
950
+ if plugins:
951
+ operation_plugins.extend(plugins)
952
+
953
+ return await self._execute_operation(
954
+ input=input,
955
+ plugins=operation_plugins,
956
+ serialize=_serialize_delete_type_templates,
957
+ deserialize=_deserialize_delete_type_templates,
958
+ config=self._config,
959
+ operation=DELETE_TYPE_TEMPLATES,
960
+ )
961
+
962
+ async def delete_webhook(self, input: DeleteWebhookInput, plugins: list[Plugin] | None = None) -> DeleteWebhookOutput:
963
+ """
964
+ Permanently removes a webhook config from the workspace, stopping all future
965
+ event notifications to that endpoint.
966
+
967
+ :param input: The operation's input.
968
+
969
+ :param plugins: A list of callables that modify the configuration dynamically.
970
+ Changes made by these plugins only apply for the duration of the operation
971
+ execution and will not affect any other operation invocations.
972
+
973
+ """
974
+ operation_plugins: list[Plugin] = [
975
+
976
+ ]
977
+ if plugins:
978
+ operation_plugins.extend(plugins)
979
+
980
+ return await self._execute_operation(
981
+ input=input,
982
+ plugins=operation_plugins,
983
+ serialize=_serialize_delete_webhook,
984
+ deserialize=_deserialize_delete_webhook,
985
+ config=self._config,
986
+ operation=DELETE_WEBHOOK,
987
+ )
988
+
989
+ async def discard_experiment(self, input: DiscardExperimentInput, plugins: list[Plugin] | None = None) -> DiscardExperimentOutput:
990
+ """
991
+ Discards an experiment without selecting a winner, effectively canceling the
992
+ experiment and removing its effects.
993
+
994
+ :param input: The operation's input.
995
+
996
+ :param plugins: A list of callables that modify the configuration dynamically.
997
+ Changes made by these plugins only apply for the duration of the operation
998
+ execution and will not affect any other operation invocations.
999
+
1000
+ """
1001
+ operation_plugins: list[Plugin] = [
1002
+
1003
+ ]
1004
+ if plugins:
1005
+ operation_plugins.extend(plugins)
1006
+
1007
+ return await self._execute_operation(
1008
+ input=input,
1009
+ plugins=operation_plugins,
1010
+ serialize=_serialize_discard_experiment,
1011
+ deserialize=_deserialize_discard_experiment,
1012
+ config=self._config,
1013
+ operation=DISCARD_EXPERIMENT,
1014
+ )
1015
+
1016
+ async def get_config(self, input: GetConfigInput, plugins: list[Plugin] | None = None) -> GetConfigOutput:
1017
+ """
1018
+ Retrieves config data with context evaluation, including applicable contexts,
1019
+ overrides, and default values based on provided conditions.
1020
+
1021
+ :param input: The operation's input.
1022
+
1023
+ :param plugins: A list of callables that modify the configuration dynamically.
1024
+ Changes made by these plugins only apply for the duration of the operation
1025
+ execution and will not affect any other operation invocations.
1026
+
1027
+ """
1028
+ operation_plugins: list[Plugin] = [
1029
+
1030
+ ]
1031
+ if plugins:
1032
+ operation_plugins.extend(plugins)
1033
+
1034
+ return await self._execute_operation(
1035
+ input=input,
1036
+ plugins=operation_plugins,
1037
+ serialize=_serialize_get_config,
1038
+ deserialize=_deserialize_get_config,
1039
+ config=self._config,
1040
+ operation=GET_CONFIG,
1041
+ )
1042
+
1043
+ async def get_config_fast(self, input: GetConfigFastInput, plugins: list[Plugin] | None = None) -> GetConfigFastOutput:
1044
+ """
1045
+ Retrieves the latest config with no processing for high-performance access.
1046
+
1047
+ :param input: The operation's input.
1048
+
1049
+ :param plugins: A list of callables that modify the configuration dynamically.
1050
+ Changes made by these plugins only apply for the duration of the operation
1051
+ execution and will not affect any other operation invocations.
1052
+
1053
+ """
1054
+ operation_plugins: list[Plugin] = [
1055
+
1056
+ ]
1057
+ if plugins:
1058
+ operation_plugins.extend(plugins)
1059
+
1060
+ return await self._execute_operation(
1061
+ input=input,
1062
+ plugins=operation_plugins,
1063
+ serialize=_serialize_get_config_fast,
1064
+ deserialize=_deserialize_get_config_fast,
1065
+ config=self._config,
1066
+ operation=GET_CONFIG_FAST,
1067
+ )
1068
+
1069
+ async def get_context(self, input: GetContextInput, plugins: list[Plugin] | None = None) -> GetContextOutput:
1070
+ """
1071
+ Retrieves detailed information about a specific context by its unique
1072
+ identifier, including conditions, overrides, and metadata.
1073
+
1074
+ :param input: The operation's input.
1075
+
1076
+ :param plugins: A list of callables that modify the configuration dynamically.
1077
+ Changes made by these plugins only apply for the duration of the operation
1078
+ execution and will not affect any other operation invocations.
1079
+
1080
+ """
1081
+ operation_plugins: list[Plugin] = [
1082
+
1083
+ ]
1084
+ if plugins:
1085
+ operation_plugins.extend(plugins)
1086
+
1087
+ return await self._execute_operation(
1088
+ input=input,
1089
+ plugins=operation_plugins,
1090
+ serialize=_serialize_get_context,
1091
+ deserialize=_deserialize_get_context,
1092
+ config=self._config,
1093
+ operation=GET_CONTEXT,
1094
+ )
1095
+
1096
+ async def get_context_from_condition(self, input: GetContextFromConditionInput, plugins: list[Plugin] | None = None) -> GetContextFromConditionOutput:
1097
+ """
1098
+ Retrieves context information by matching against provided conditions. Used to
1099
+ find contexts that would apply to specific scenarios.
1100
+
1101
+ :param input: The operation's input.
1102
+
1103
+ :param plugins: A list of callables that modify the configuration dynamically.
1104
+ Changes made by these plugins only apply for the duration of the operation
1105
+ execution and will not affect any other operation invocations.
1106
+
1107
+ """
1108
+ operation_plugins: list[Plugin] = [
1109
+
1110
+ ]
1111
+ if plugins:
1112
+ operation_plugins.extend(plugins)
1113
+
1114
+ return await self._execute_operation(
1115
+ input=input,
1116
+ plugins=operation_plugins,
1117
+ serialize=_serialize_get_context_from_condition,
1118
+ deserialize=_deserialize_get_context_from_condition,
1119
+ config=self._config,
1120
+ operation=GET_CONTEXT_FROM_CONDITION,
1121
+ )
1122
+
1123
+ async def get_default_config(self, input: GetDefaultConfigInput, plugins: list[Plugin] | None = None) -> GetDefaultConfigOutput:
1124
+ """
1125
+ Retrieves a specific default config entry by its key, including its value,
1126
+ schema, function mappings, and metadata.
1127
+
1128
+ :param input: The operation's input.
1129
+
1130
+ :param plugins: A list of callables that modify the configuration dynamically.
1131
+ Changes made by these plugins only apply for the duration of the operation
1132
+ execution and will not affect any other operation invocations.
1133
+
1134
+ """
1135
+ operation_plugins: list[Plugin] = [
1136
+
1137
+ ]
1138
+ if plugins:
1139
+ operation_plugins.extend(plugins)
1140
+
1141
+ return await self._execute_operation(
1142
+ input=input,
1143
+ plugins=operation_plugins,
1144
+ serialize=_serialize_get_default_config,
1145
+ deserialize=_deserialize_get_default_config,
1146
+ config=self._config,
1147
+ operation=GET_DEFAULT_CONFIG,
1148
+ )
1149
+
1150
+ async def get_dimension(self, input: GetDimensionInput, plugins: list[Plugin] | None = None) -> GetDimensionOutput:
1151
+ """
1152
+ Retrieves detailed information about a specific dimension, including its schema,
1153
+ cohort dependency graph, and configuration metadata.
1154
+
1155
+ :param input: The operation's input.
1156
+
1157
+ :param plugins: A list of callables that modify the configuration dynamically.
1158
+ Changes made by these plugins only apply for the duration of the operation
1159
+ execution and will not affect any other operation invocations.
1160
+
1161
+ """
1162
+ operation_plugins: list[Plugin] = [
1163
+
1164
+ ]
1165
+ if plugins:
1166
+ operation_plugins.extend(plugins)
1167
+
1168
+ return await self._execute_operation(
1169
+ input=input,
1170
+ plugins=operation_plugins,
1171
+ serialize=_serialize_get_dimension,
1172
+ deserialize=_deserialize_get_dimension,
1173
+ config=self._config,
1174
+ operation=GET_DIMENSION,
1175
+ )
1176
+
1177
+ async def get_experiment(self, input: GetExperimentInput, plugins: list[Plugin] | None = None) -> GetExperimentOutput:
1178
+ """
1179
+ Retrieves detailed information about a specific experiment, including its
1180
+ config, variants, status, and metrics.
1181
+
1182
+ :param input: The operation's input.
1183
+
1184
+ :param plugins: A list of callables that modify the configuration dynamically.
1185
+ Changes made by these plugins only apply for the duration of the operation
1186
+ execution and will not affect any other operation invocations.
1187
+
1188
+ """
1189
+ operation_plugins: list[Plugin] = [
1190
+
1191
+ ]
1192
+ if plugins:
1193
+ operation_plugins.extend(plugins)
1194
+
1195
+ return await self._execute_operation(
1196
+ input=input,
1197
+ plugins=operation_plugins,
1198
+ serialize=_serialize_get_experiment,
1199
+ deserialize=_deserialize_get_experiment,
1200
+ config=self._config,
1201
+ operation=GET_EXPERIMENT,
1202
+ )
1203
+
1204
+ async def get_experiment_group(self, input: GetExperimentGroupInput, plugins: list[Plugin] | None = None) -> GetExperimentGroupOutput:
1205
+ """
1206
+ Retrieves an existing experiment group by its ID.
1207
+
1208
+ :param input: The operation's input.
1209
+
1210
+ :param plugins: A list of callables that modify the configuration dynamically.
1211
+ Changes made by these plugins only apply for the duration of the operation
1212
+ execution and will not affect any other operation invocations.
1213
+
1214
+ """
1215
+ operation_plugins: list[Plugin] = [
1216
+
1217
+ ]
1218
+ if plugins:
1219
+ operation_plugins.extend(plugins)
1220
+
1221
+ return await self._execute_operation(
1222
+ input=input,
1223
+ plugins=operation_plugins,
1224
+ serialize=_serialize_get_experiment_group,
1225
+ deserialize=_deserialize_get_experiment_group,
1226
+ config=self._config,
1227
+ operation=GET_EXPERIMENT_GROUP,
1228
+ )
1229
+
1230
+ async def get_function(self, input: GetFunctionInput, plugins: list[Plugin] | None = None) -> GetFunctionOutput:
1231
+ """
1232
+ Retrieves detailed information about a specific function including its published
1233
+ and draft versions, code, and metadata.
1234
+
1235
+ :param input: The operation's input.
1236
+
1237
+ :param plugins: A list of callables that modify the configuration dynamically.
1238
+ Changes made by these plugins only apply for the duration of the operation
1239
+ execution and will not affect any other operation invocations.
1240
+
1241
+ """
1242
+ operation_plugins: list[Plugin] = [
1243
+
1244
+ ]
1245
+ if plugins:
1246
+ operation_plugins.extend(plugins)
1247
+
1248
+ return await self._execute_operation(
1249
+ input=input,
1250
+ plugins=operation_plugins,
1251
+ serialize=_serialize_get_function,
1252
+ deserialize=_deserialize_get_function,
1253
+ config=self._config,
1254
+ operation=GET_FUNCTION,
1255
+ )
1256
+
1257
+ async def get_organisation(self, input: GetOrganisationInput, plugins: list[Plugin] | None = None) -> GetOrganisationOutput:
1258
+ """
1259
+ Retrieves detailed information about a specific organisation including its
1260
+ status, contact details, and administrative metadata.
1261
+
1262
+ :param input: The operation's input.
1263
+
1264
+ :param plugins: A list of callables that modify the configuration dynamically.
1265
+ Changes made by these plugins only apply for the duration of the operation
1266
+ execution and will not affect any other operation invocations.
1267
+
1268
+ """
1269
+ operation_plugins: list[Plugin] = [
1270
+
1271
+ ]
1272
+ if plugins:
1273
+ operation_plugins.extend(plugins)
1274
+
1275
+ return await self._execute_operation(
1276
+ input=input,
1277
+ plugins=operation_plugins,
1278
+ serialize=_serialize_get_organisation,
1279
+ deserialize=_deserialize_get_organisation,
1280
+ config=self._config,
1281
+ operation=GET_ORGANISATION,
1282
+ )
1283
+
1284
+ async def get_resolved_config(self, input: GetResolvedConfigInput, plugins: list[Plugin] | None = None) -> GetResolvedConfigOutput:
1285
+ """
1286
+ Resolves and merges config values based on context conditions, applying
1287
+ overrides and merge strategies to produce the final configuration.
1288
+
1289
+ :param input: The operation's input.
1290
+
1291
+ :param plugins: A list of callables that modify the configuration dynamically.
1292
+ Changes made by these plugins only apply for the duration of the operation
1293
+ execution and will not affect any other operation invocations.
1294
+
1295
+ """
1296
+ operation_plugins: list[Plugin] = [
1297
+
1298
+ ]
1299
+ if plugins:
1300
+ operation_plugins.extend(plugins)
1301
+
1302
+ return await self._execute_operation(
1303
+ input=input,
1304
+ plugins=operation_plugins,
1305
+ serialize=_serialize_get_resolved_config,
1306
+ deserialize=_deserialize_get_resolved_config,
1307
+ config=self._config,
1308
+ operation=GET_RESOLVED_CONFIG,
1309
+ )
1310
+
1311
+ async def get_type_template(self, input: GetTypeTemplateInput, plugins: list[Plugin] | None = None) -> GetTypeTemplateOutput:
1312
+ """
1313
+ Retrieves detailed information about a specific type template including its
1314
+ schema and metadata.
1315
+
1316
+ :param input: The operation's input.
1317
+
1318
+ :param plugins: A list of callables that modify the configuration dynamically.
1319
+ Changes made by these plugins only apply for the duration of the operation
1320
+ execution and will not affect any other operation invocations.
1321
+
1322
+ """
1323
+ operation_plugins: list[Plugin] = [
1324
+
1325
+ ]
1326
+ if plugins:
1327
+ operation_plugins.extend(plugins)
1328
+
1329
+ return await self._execute_operation(
1330
+ input=input,
1331
+ plugins=operation_plugins,
1332
+ serialize=_serialize_get_type_template,
1333
+ deserialize=_deserialize_get_type_template,
1334
+ config=self._config,
1335
+ operation=GET_TYPE_TEMPLATE,
1336
+ )
1337
+
1338
+ async def get_type_templates_list(self, input: GetTypeTemplatesListInput, plugins: list[Plugin] | None = None) -> GetTypeTemplatesListOutput:
1339
+ """
1340
+ Retrieves a paginated list of all type templates in the workspace, including
1341
+ their schemas and metadata for type management.
1342
+
1343
+ :param input: The operation's input.
1344
+
1345
+ :param plugins: A list of callables that modify the configuration dynamically.
1346
+ Changes made by these plugins only apply for the duration of the operation
1347
+ execution and will not affect any other operation invocations.
1348
+
1349
+ """
1350
+ operation_plugins: list[Plugin] = [
1351
+
1352
+ ]
1353
+ if plugins:
1354
+ operation_plugins.extend(plugins)
1355
+
1356
+ return await self._execute_operation(
1357
+ input=input,
1358
+ plugins=operation_plugins,
1359
+ serialize=_serialize_get_type_templates_list,
1360
+ deserialize=_deserialize_get_type_templates_list,
1361
+ config=self._config,
1362
+ operation=GET_TYPE_TEMPLATES_LIST,
1363
+ )
1364
+
1365
+ async def get_version(self, input: GetVersionInput, plugins: list[Plugin] | None = None) -> GetVersionOutput:
1366
+ """
1367
+ Retrieves a specific config version along with its metadata for audit and
1368
+ rollback purposes.
1369
+
1370
+ :param input: The operation's input.
1371
+
1372
+ :param plugins: A list of callables that modify the configuration dynamically.
1373
+ Changes made by these plugins only apply for the duration of the operation
1374
+ execution and will not affect any other operation invocations.
1375
+
1376
+ """
1377
+ operation_plugins: list[Plugin] = [
1378
+
1379
+ ]
1380
+ if plugins:
1381
+ operation_plugins.extend(plugins)
1382
+
1383
+ return await self._execute_operation(
1384
+ input=input,
1385
+ plugins=operation_plugins,
1386
+ serialize=_serialize_get_version,
1387
+ deserialize=_deserialize_get_version,
1388
+ config=self._config,
1389
+ operation=GET_VERSION,
1390
+ )
1391
+
1392
+ async def get_webhook(self, input: GetWebhookInput, plugins: list[Plugin] | None = None) -> GetWebhookOutput:
1393
+ """
1394
+ Retrieves detailed information about a specific webhook config, including its
1395
+ events, headers, and trigger history.
1396
+
1397
+ :param input: The operation's input.
1398
+
1399
+ :param plugins: A list of callables that modify the configuration dynamically.
1400
+ Changes made by these plugins only apply for the duration of the operation
1401
+ execution and will not affect any other operation invocations.
1402
+
1403
+ """
1404
+ operation_plugins: list[Plugin] = [
1405
+
1406
+ ]
1407
+ if plugins:
1408
+ operation_plugins.extend(plugins)
1409
+
1410
+ return await self._execute_operation(
1411
+ input=input,
1412
+ plugins=operation_plugins,
1413
+ serialize=_serialize_get_webhook,
1414
+ deserialize=_deserialize_get_webhook,
1415
+ config=self._config,
1416
+ operation=GET_WEBHOOK,
1417
+ )
1418
+
1419
+ async def get_webhook_by_event(self, input: GetWebhookByEventInput, plugins: list[Plugin] | None = None) -> GetWebhookByEventOutput:
1420
+ """
1421
+ Retrieves a webhook configuration based on a specific event type, allowing users
1422
+ to find which webhook is set to trigger for that event.
1423
+
1424
+ :param input: The operation's input.
1425
+
1426
+ :param plugins: A list of callables that modify the configuration dynamically.
1427
+ Changes made by these plugins only apply for the duration of the operation
1428
+ execution and will not affect any other operation invocations.
1429
+
1430
+ """
1431
+ operation_plugins: list[Plugin] = [
1432
+
1433
+ ]
1434
+ if plugins:
1435
+ operation_plugins.extend(plugins)
1436
+
1437
+ return await self._execute_operation(
1438
+ input=input,
1439
+ plugins=operation_plugins,
1440
+ serialize=_serialize_get_webhook_by_event,
1441
+ deserialize=_deserialize_get_webhook_by_event,
1442
+ config=self._config,
1443
+ operation=GET_WEBHOOK_BY_EVENT,
1444
+ )
1445
+
1446
+ async def get_workspace(self, input: GetWorkspaceInput, plugins: list[Plugin] | None = None) -> GetWorkspaceOutput:
1447
+ """
1448
+ Retrieves detailed information about a specific workspace including its
1449
+ configuration and metadata.
1450
+
1451
+ :param input: The operation's input.
1452
+
1453
+ :param plugins: A list of callables that modify the configuration dynamically.
1454
+ Changes made by these plugins only apply for the duration of the operation
1455
+ execution and will not affect any other operation invocations.
1456
+
1457
+ """
1458
+ operation_plugins: list[Plugin] = [
1459
+
1460
+ ]
1461
+ if plugins:
1462
+ operation_plugins.extend(plugins)
1463
+
1464
+ return await self._execute_operation(
1465
+ input=input,
1466
+ plugins=operation_plugins,
1467
+ serialize=_serialize_get_workspace,
1468
+ deserialize=_deserialize_get_workspace,
1469
+ config=self._config,
1470
+ operation=GET_WORKSPACE,
1471
+ )
1472
+
1473
+ async def list_audit_logs(self, input: ListAuditLogsInput, plugins: list[Plugin] | None = None) -> ListAuditLogsOutput:
1474
+ """
1475
+ Retrieves a paginated list of audit logs with support for filtering by date
1476
+ range, table names, actions, and usernames for compliance and monitoring
1477
+ purposes.
1478
+
1479
+ :param input: The operation's input.
1480
+
1481
+ :param plugins: A list of callables that modify the configuration dynamically.
1482
+ Changes made by these plugins only apply for the duration of the operation
1483
+ execution and will not affect any other operation invocations.
1484
+
1485
+ """
1486
+ operation_plugins: list[Plugin] = [
1487
+
1488
+ ]
1489
+ if plugins:
1490
+ operation_plugins.extend(plugins)
1491
+
1492
+ return await self._execute_operation(
1493
+ input=input,
1494
+ plugins=operation_plugins,
1495
+ serialize=_serialize_list_audit_logs,
1496
+ deserialize=_deserialize_list_audit_logs,
1497
+ config=self._config,
1498
+ operation=LIST_AUDIT_LOGS,
1499
+ )
1500
+
1501
+ async def list_contexts(self, input: ListContextsInput, plugins: list[Plugin] | None = None) -> ListContextsOutput:
1502
+ """
1503
+ Retrieves a paginated list of contexts with support for filtering by creation
1504
+ date, modification date, weight, and other criteria.
1505
+
1506
+ :param input: The operation's input.
1507
+
1508
+ :param plugins: A list of callables that modify the configuration dynamically.
1509
+ Changes made by these plugins only apply for the duration of the operation
1510
+ execution and will not affect any other operation invocations.
1511
+
1512
+ """
1513
+ operation_plugins: list[Plugin] = [
1514
+
1515
+ ]
1516
+ if plugins:
1517
+ operation_plugins.extend(plugins)
1518
+
1519
+ return await self._execute_operation(
1520
+ input=input,
1521
+ plugins=operation_plugins,
1522
+ serialize=_serialize_list_contexts,
1523
+ deserialize=_deserialize_list_contexts,
1524
+ config=self._config,
1525
+ operation=LIST_CONTEXTS,
1526
+ )
1527
+
1528
+ async def list_default_configs(self, input: ListDefaultConfigsInput, plugins: list[Plugin] | None = None) -> ListDefaultConfigsOutput:
1529
+ """
1530
+ Retrieves a paginated list of all default config entries in the workspace,
1531
+ including their values, schemas, and metadata.
1532
+
1533
+ :param input: The operation's input.
1534
+
1535
+ :param plugins: A list of callables that modify the configuration dynamically.
1536
+ Changes made by these plugins only apply for the duration of the operation
1537
+ execution and will not affect any other operation invocations.
1538
+
1539
+ """
1540
+ operation_plugins: list[Plugin] = [
1541
+
1542
+ ]
1543
+ if plugins:
1544
+ operation_plugins.extend(plugins)
1545
+
1546
+ return await self._execute_operation(
1547
+ input=input,
1548
+ plugins=operation_plugins,
1549
+ serialize=_serialize_list_default_configs,
1550
+ deserialize=_deserialize_list_default_configs,
1551
+ config=self._config,
1552
+ operation=LIST_DEFAULT_CONFIGS,
1553
+ )
1554
+
1555
+ async def list_dimensions(self, input: ListDimensionsInput, plugins: list[Plugin] | None = None) -> ListDimensionsOutput:
1556
+ """
1557
+ Retrieves a paginated list of all dimensions in the workspace. Dimensions are
1558
+ returned with their details and metadata.
1559
+
1560
+ :param input: The operation's input.
1561
+
1562
+ :param plugins: A list of callables that modify the configuration dynamically.
1563
+ Changes made by these plugins only apply for the duration of the operation
1564
+ execution and will not affect any other operation invocations.
1565
+
1566
+ """
1567
+ operation_plugins: list[Plugin] = [
1568
+
1569
+ ]
1570
+ if plugins:
1571
+ operation_plugins.extend(plugins)
1572
+
1573
+ return await self._execute_operation(
1574
+ input=input,
1575
+ plugins=operation_plugins,
1576
+ serialize=_serialize_list_dimensions,
1577
+ deserialize=_deserialize_list_dimensions,
1578
+ config=self._config,
1579
+ operation=LIST_DIMENSIONS,
1580
+ )
1581
+
1582
+ async def list_experiment(self, input: ListExperimentInput, plugins: list[Plugin] | None = None) -> ListExperimentOutput:
1583
+ """
1584
+ Retrieves a paginated list of experiments with support for filtering by status,
1585
+ date range, name, creator, and experiment group.
1586
+
1587
+ :param input: The operation's input.
1588
+
1589
+ :param plugins: A list of callables that modify the configuration dynamically.
1590
+ Changes made by these plugins only apply for the duration of the operation
1591
+ execution and will not affect any other operation invocations.
1592
+
1593
+ """
1594
+ operation_plugins: list[Plugin] = [
1595
+
1596
+ ]
1597
+ if plugins:
1598
+ operation_plugins.extend(plugins)
1599
+
1600
+ return await self._execute_operation(
1601
+ input=input,
1602
+ plugins=operation_plugins,
1603
+ serialize=_serialize_list_experiment,
1604
+ deserialize=_deserialize_list_experiment,
1605
+ config=self._config,
1606
+ operation=LIST_EXPERIMENT,
1607
+ )
1608
+
1609
+ async def list_experiment_groups(self, input: ListExperimentGroupsInput, plugins: list[Plugin] | None = None) -> ListExperimentGroupsOutput:
1610
+ """
1611
+ Lists experiment groups, with support for filtering and pagination.
1612
+
1613
+ :param input: The operation's input.
1614
+
1615
+ :param plugins: A list of callables that modify the configuration dynamically.
1616
+ Changes made by these plugins only apply for the duration of the operation
1617
+ execution and will not affect any other operation invocations.
1618
+
1619
+ """
1620
+ operation_plugins: list[Plugin] = [
1621
+
1622
+ ]
1623
+ if plugins:
1624
+ operation_plugins.extend(plugins)
1625
+
1626
+ return await self._execute_operation(
1627
+ input=input,
1628
+ plugins=operation_plugins,
1629
+ serialize=_serialize_list_experiment_groups,
1630
+ deserialize=_deserialize_list_experiment_groups,
1631
+ config=self._config,
1632
+ operation=LIST_EXPERIMENT_GROUPS,
1633
+ )
1634
+
1635
+ async def list_function(self, input: ListFunctionInput, plugins: list[Plugin] | None = None) -> ListFunctionOutput:
1636
+ """
1637
+ Retrieves a paginated list of all functions in the workspace with their basic
1638
+ information and current status.
1639
+
1640
+ :param input: The operation's input.
1641
+
1642
+ :param plugins: A list of callables that modify the configuration dynamically.
1643
+ Changes made by these plugins only apply for the duration of the operation
1644
+ execution and will not affect any other operation invocations.
1645
+
1646
+ """
1647
+ operation_plugins: list[Plugin] = [
1648
+
1649
+ ]
1650
+ if plugins:
1651
+ operation_plugins.extend(plugins)
1652
+
1653
+ return await self._execute_operation(
1654
+ input=input,
1655
+ plugins=operation_plugins,
1656
+ serialize=_serialize_list_function,
1657
+ deserialize=_deserialize_list_function,
1658
+ config=self._config,
1659
+ operation=LIST_FUNCTION,
1660
+ )
1661
+
1662
+ async def list_organisation(self, input: ListOrganisationInput, plugins: list[Plugin] | None = None) -> ListOrganisationOutput:
1663
+ """
1664
+ Retrieves a paginated list of all organisations with their basic information,
1665
+ creation details, and current status.
1666
+
1667
+ :param input: The operation's input.
1668
+
1669
+ :param plugins: A list of callables that modify the configuration dynamically.
1670
+ Changes made by these plugins only apply for the duration of the operation
1671
+ execution and will not affect any other operation invocations.
1672
+
1673
+ """
1674
+ operation_plugins: list[Plugin] = [
1675
+
1676
+ ]
1677
+ if plugins:
1678
+ operation_plugins.extend(plugins)
1679
+
1680
+ return await self._execute_operation(
1681
+ input=input,
1682
+ plugins=operation_plugins,
1683
+ serialize=_serialize_list_organisation,
1684
+ deserialize=_deserialize_list_organisation,
1685
+ config=self._config,
1686
+ operation=LIST_ORGANISATION,
1687
+ )
1688
+
1689
+ async def list_versions(self, input: ListVersionsInput, plugins: list[Plugin] | None = None) -> ListVersionsOutput:
1690
+ """
1691
+ Retrieves a paginated list of config versions with their metadata, hash values,
1692
+ and creation timestamps for audit and rollback purposes.
1693
+
1694
+ :param input: The operation's input.
1695
+
1696
+ :param plugins: A list of callables that modify the configuration dynamically.
1697
+ Changes made by these plugins only apply for the duration of the operation
1698
+ execution and will not affect any other operation invocations.
1699
+
1700
+ """
1701
+ operation_plugins: list[Plugin] = [
1702
+
1703
+ ]
1704
+ if plugins:
1705
+ operation_plugins.extend(plugins)
1706
+
1707
+ return await self._execute_operation(
1708
+ input=input,
1709
+ plugins=operation_plugins,
1710
+ serialize=_serialize_list_versions,
1711
+ deserialize=_deserialize_list_versions,
1712
+ config=self._config,
1713
+ operation=LIST_VERSIONS,
1714
+ )
1715
+
1716
+ async def list_webhook(self, input: ListWebhookInput, plugins: list[Plugin] | None = None) -> ListWebhookOutput:
1717
+ """
1718
+ Retrieves a paginated list of all webhook configs in the workspace, including
1719
+ their status and config details.
1720
+
1721
+ :param input: The operation's input.
1722
+
1723
+ :param plugins: A list of callables that modify the configuration dynamically.
1724
+ Changes made by these plugins only apply for the duration of the operation
1725
+ execution and will not affect any other operation invocations.
1726
+
1727
+ """
1728
+ operation_plugins: list[Plugin] = [
1729
+
1730
+ ]
1731
+ if plugins:
1732
+ operation_plugins.extend(plugins)
1733
+
1734
+ return await self._execute_operation(
1735
+ input=input,
1736
+ plugins=operation_plugins,
1737
+ serialize=_serialize_list_webhook,
1738
+ deserialize=_deserialize_list_webhook,
1739
+ config=self._config,
1740
+ operation=LIST_WEBHOOK,
1741
+ )
1742
+
1743
+ async def list_workspace(self, input: ListWorkspaceInput, plugins: list[Plugin] | None = None) -> ListWorkspaceOutput:
1744
+ """
1745
+ Retrieves a paginated list of all workspaces with optional filtering by
1746
+ workspace name, including their status, config details, and administrative
1747
+ information.
1748
+
1749
+ :param input: The operation's input.
1750
+
1751
+ :param plugins: A list of callables that modify the configuration dynamically.
1752
+ Changes made by these plugins only apply for the duration of the operation
1753
+ execution and will not affect any other operation invocations.
1754
+
1755
+ """
1756
+ operation_plugins: list[Plugin] = [
1757
+
1758
+ ]
1759
+ if plugins:
1760
+ operation_plugins.extend(plugins)
1761
+
1762
+ return await self._execute_operation(
1763
+ input=input,
1764
+ plugins=operation_plugins,
1765
+ serialize=_serialize_list_workspace,
1766
+ deserialize=_deserialize_list_workspace,
1767
+ config=self._config,
1768
+ operation=LIST_WORKSPACE,
1769
+ )
1770
+
1771
+ async def migrate_workspace_schema(self, input: MigrateWorkspaceSchemaInput, plugins: list[Plugin] | None = None) -> MigrateWorkspaceSchemaOutput:
1772
+ """
1773
+ Migrates the workspace database schema to the new version of the template
1774
+
1775
+ :param input: The operation's input.
1776
+
1777
+ :param plugins: A list of callables that modify the configuration dynamically.
1778
+ Changes made by these plugins only apply for the duration of the operation
1779
+ execution and will not affect any other operation invocations.
1780
+
1781
+ """
1782
+ operation_plugins: list[Plugin] = [
1783
+
1784
+ ]
1785
+ if plugins:
1786
+ operation_plugins.extend(plugins)
1787
+
1788
+ return await self._execute_operation(
1789
+ input=input,
1790
+ plugins=operation_plugins,
1791
+ serialize=_serialize_migrate_workspace_schema,
1792
+ deserialize=_deserialize_migrate_workspace_schema,
1793
+ config=self._config,
1794
+ operation=MIGRATE_WORKSPACE_SCHEMA,
1795
+ )
1796
+
1797
+ async def move_context(self, input: MoveContextInput, plugins: list[Plugin] | None = None) -> MoveContextOutput:
1798
+ """
1799
+ Updates the condition of the mentioned context, if a context with the new
1800
+ condition already exists, it merges the override and effectively deleting the
1801
+ old context
1802
+
1803
+ :param input: The operation's input.
1804
+
1805
+ :param plugins: A list of callables that modify the configuration dynamically.
1806
+ Changes made by these plugins only apply for the duration of the operation
1807
+ execution and will not affect any other operation invocations.
1808
+
1809
+ """
1810
+ operation_plugins: list[Plugin] = [
1811
+
1812
+ ]
1813
+ if plugins:
1814
+ operation_plugins.extend(plugins)
1815
+
1816
+ return await self._execute_operation(
1817
+ input=input,
1818
+ plugins=operation_plugins,
1819
+ serialize=_serialize_move_context,
1820
+ deserialize=_deserialize_move_context,
1821
+ config=self._config,
1822
+ operation=MOVE_CONTEXT,
1823
+ )
1824
+
1825
+ async def pause_experiment(self, input: PauseExperimentInput, plugins: list[Plugin] | None = None) -> PauseExperimentOutput:
1826
+ """
1827
+ Temporarily pauses an inprogress experiment, suspending its effects while
1828
+ preserving the experiment config for later resumption.
1829
+
1830
+ :param input: The operation's input.
1831
+
1832
+ :param plugins: A list of callables that modify the configuration dynamically.
1833
+ Changes made by these plugins only apply for the duration of the operation
1834
+ execution and will not affect any other operation invocations.
1835
+
1836
+ """
1837
+ operation_plugins: list[Plugin] = [
1838
+
1839
+ ]
1840
+ if plugins:
1841
+ operation_plugins.extend(plugins)
1842
+
1843
+ return await self._execute_operation(
1844
+ input=input,
1845
+ plugins=operation_plugins,
1846
+ serialize=_serialize_pause_experiment,
1847
+ deserialize=_deserialize_pause_experiment,
1848
+ config=self._config,
1849
+ operation=PAUSE_EXPERIMENT,
1850
+ )
1851
+
1852
+ async def publish(self, input: PublishInput, plugins: list[Plugin] | None = None) -> PublishOutput:
1853
+ """
1854
+ Publishes the draft version of a function, making it the active version used for
1855
+ validation or autocompletion in the system.
1856
+
1857
+ :param input: The operation's input.
1858
+
1859
+ :param plugins: A list of callables that modify the configuration dynamically.
1860
+ Changes made by these plugins only apply for the duration of the operation
1861
+ execution and will not affect any other operation invocations.
1862
+
1863
+ """
1864
+ operation_plugins: list[Plugin] = [
1865
+
1866
+ ]
1867
+ if plugins:
1868
+ operation_plugins.extend(plugins)
1869
+
1870
+ return await self._execute_operation(
1871
+ input=input,
1872
+ plugins=operation_plugins,
1873
+ serialize=_serialize_publish,
1874
+ deserialize=_deserialize_publish,
1875
+ config=self._config,
1876
+ operation=PUBLISH,
1877
+ )
1878
+
1879
+ async def ramp_experiment(self, input: RampExperimentInput, plugins: list[Plugin] | None = None) -> RampExperimentOutput:
1880
+ """
1881
+ Adjusts the traffic percentage allocation for an in-progress experiment,
1882
+ allowing gradual rollout or rollback of experimental features.
1883
+
1884
+ :param input: The operation's input.
1885
+
1886
+ :param plugins: A list of callables that modify the configuration dynamically.
1887
+ Changes made by these plugins only apply for the duration of the operation
1888
+ execution and will not affect any other operation invocations.
1889
+
1890
+ """
1891
+ operation_plugins: list[Plugin] = [
1892
+
1893
+ ]
1894
+ if plugins:
1895
+ operation_plugins.extend(plugins)
1896
+
1897
+ return await self._execute_operation(
1898
+ input=input,
1899
+ plugins=operation_plugins,
1900
+ serialize=_serialize_ramp_experiment,
1901
+ deserialize=_deserialize_ramp_experiment,
1902
+ config=self._config,
1903
+ operation=RAMP_EXPERIMENT,
1904
+ )
1905
+
1906
+ async def remove_members_from_group(self, input: RemoveMembersFromGroupInput, plugins: list[Plugin] | None = None) -> RemoveMembersFromGroupOutput:
1907
+ """
1908
+ Removes members from an existing experiment group.
1909
+
1910
+ :param input: Input structure for adding members to an experiment group.
1911
+
1912
+ :param plugins: A list of callables that modify the configuration dynamically.
1913
+ Changes made by these plugins only apply for the duration of the operation
1914
+ execution and will not affect any other operation invocations.
1915
+
1916
+ """
1917
+ operation_plugins: list[Plugin] = [
1918
+
1919
+ ]
1920
+ if plugins:
1921
+ operation_plugins.extend(plugins)
1922
+
1923
+ return await self._execute_operation(
1924
+ input=input,
1925
+ plugins=operation_plugins,
1926
+ serialize=_serialize_remove_members_from_group,
1927
+ deserialize=_deserialize_remove_members_from_group,
1928
+ config=self._config,
1929
+ operation=REMOVE_MEMBERS_FROM_GROUP,
1930
+ )
1931
+
1932
+ async def resume_experiment(self, input: ResumeExperimentInput, plugins: list[Plugin] | None = None) -> ResumeExperimentOutput:
1933
+ """
1934
+ Resumes a previously paused experiment, restoring its in-progress state and
1935
+ re-enabling variant evaluation.
1936
+
1937
+ :param input: The operation's input.
1938
+
1939
+ :param plugins: A list of callables that modify the configuration dynamically.
1940
+ Changes made by these plugins only apply for the duration of the operation
1941
+ execution and will not affect any other operation invocations.
1942
+
1943
+ """
1944
+ operation_plugins: list[Plugin] = [
1945
+
1946
+ ]
1947
+ if plugins:
1948
+ operation_plugins.extend(plugins)
1949
+
1950
+ return await self._execute_operation(
1951
+ input=input,
1952
+ plugins=operation_plugins,
1953
+ serialize=_serialize_resume_experiment,
1954
+ deserialize=_deserialize_resume_experiment,
1955
+ config=self._config,
1956
+ operation=RESUME_EXPERIMENT,
1957
+ )
1958
+
1959
+ async def test(self, input: TestInput, plugins: list[Plugin] | None = None) -> TestOutput:
1960
+ """
1961
+ Executes a function in test mode with provided input parameters to validate its
1962
+ behavior before publishing or deployment.
1963
+
1964
+ :param input: The operation's input.
1965
+
1966
+ :param plugins: A list of callables that modify the configuration dynamically.
1967
+ Changes made by these plugins only apply for the duration of the operation
1968
+ execution and will not affect any other operation invocations.
1969
+
1970
+ """
1971
+ operation_plugins: list[Plugin] = [
1972
+
1973
+ ]
1974
+ if plugins:
1975
+ operation_plugins.extend(plugins)
1976
+
1977
+ return await self._execute_operation(
1978
+ input=input,
1979
+ plugins=operation_plugins,
1980
+ serialize=_serialize_test,
1981
+ deserialize=_deserialize_test,
1982
+ config=self._config,
1983
+ operation=TEST,
1984
+ )
1985
+
1986
+ async def update_default_config(self, input: UpdateDefaultConfigInput, plugins: list[Plugin] | None = None) -> UpdateDefaultConfigOutput:
1987
+ """
1988
+ Updates an existing default config entry. Allows modification of value, schema,
1989
+ function mappings, and description while preserving the key identifier.
1990
+
1991
+ :param input: The operation's input.
1992
+
1993
+ :param plugins: A list of callables that modify the configuration dynamically.
1994
+ Changes made by these plugins only apply for the duration of the operation
1995
+ execution and will not affect any other operation invocations.
1996
+
1997
+ """
1998
+ operation_plugins: list[Plugin] = [
1999
+
2000
+ ]
2001
+ if plugins:
2002
+ operation_plugins.extend(plugins)
2003
+
2004
+ return await self._execute_operation(
2005
+ input=input,
2006
+ plugins=operation_plugins,
2007
+ serialize=_serialize_update_default_config,
2008
+ deserialize=_deserialize_update_default_config,
2009
+ config=self._config,
2010
+ operation=UPDATE_DEFAULT_CONFIG,
2011
+ )
2012
+
2013
+ async def update_dimension(self, input: UpdateDimensionInput, plugins: list[Plugin] | None = None) -> UpdateDimensionOutput:
2014
+ """
2015
+ Updates an existing dimension's configuration. Allows modification of schema,
2016
+ position, function mappings, and other properties while maintaining dependency
2017
+ relationships.
2018
+
2019
+ :param input: The operation's input.
2020
+
2021
+ :param plugins: A list of callables that modify the configuration dynamically.
2022
+ Changes made by these plugins only apply for the duration of the operation
2023
+ execution and will not affect any other operation invocations.
2024
+
2025
+ """
2026
+ operation_plugins: list[Plugin] = [
2027
+
2028
+ ]
2029
+ if plugins:
2030
+ operation_plugins.extend(plugins)
2031
+
2032
+ return await self._execute_operation(
2033
+ input=input,
2034
+ plugins=operation_plugins,
2035
+ serialize=_serialize_update_dimension,
2036
+ deserialize=_deserialize_update_dimension,
2037
+ config=self._config,
2038
+ operation=UPDATE_DIMENSION,
2039
+ )
2040
+
2041
+ async def update_experiment_group(self, input: UpdateExperimentGroupInput, plugins: list[Plugin] | None = None) -> UpdateExperimentGroupOutput:
2042
+ """
2043
+ Updates an existing experiment group. Allows partial updates to specified
2044
+ fields.
2045
+
2046
+ :param input: Input structure for updating an existing experiment group.
2047
+
2048
+ :param plugins: A list of callables that modify the configuration dynamically.
2049
+ Changes made by these plugins only apply for the duration of the operation
2050
+ execution and will not affect any other operation invocations.
2051
+
2052
+ """
2053
+ operation_plugins: list[Plugin] = [
2054
+
2055
+ ]
2056
+ if plugins:
2057
+ operation_plugins.extend(plugins)
2058
+
2059
+ return await self._execute_operation(
2060
+ input=input,
2061
+ plugins=operation_plugins,
2062
+ serialize=_serialize_update_experiment_group,
2063
+ deserialize=_deserialize_update_experiment_group,
2064
+ config=self._config,
2065
+ operation=UPDATE_EXPERIMENT_GROUP,
2066
+ )
2067
+
2068
+ async def update_function(self, input: UpdateFunctionInput, plugins: list[Plugin] | None = None) -> UpdateFunctionOutput:
2069
+ """
2070
+ Updates the draft version of an existing function with new code, runtime
2071
+ version, or description while preserving the published version.
2072
+
2073
+ :param input: The operation's input.
2074
+
2075
+ :param plugins: A list of callables that modify the configuration dynamically.
2076
+ Changes made by these plugins only apply for the duration of the operation
2077
+ execution and will not affect any other operation invocations.
2078
+
2079
+ """
2080
+ operation_plugins: list[Plugin] = [
2081
+
2082
+ ]
2083
+ if plugins:
2084
+ operation_plugins.extend(plugins)
2085
+
2086
+ return await self._execute_operation(
2087
+ input=input,
2088
+ plugins=operation_plugins,
2089
+ serialize=_serialize_update_function,
2090
+ deserialize=_deserialize_update_function,
2091
+ config=self._config,
2092
+ operation=UPDATE_FUNCTION,
2093
+ )
2094
+
2095
+ async def update_organisation(self, input: UpdateOrganisationInput, plugins: list[Plugin] | None = None) -> UpdateOrganisationOutput:
2096
+ """
2097
+ Updates an existing organisation's information including contact details,
2098
+ status, and administrative properties.
2099
+
2100
+ :param input: The operation's input.
2101
+
2102
+ :param plugins: A list of callables that modify the configuration dynamically.
2103
+ Changes made by these plugins only apply for the duration of the operation
2104
+ execution and will not affect any other operation invocations.
2105
+
2106
+ """
2107
+ operation_plugins: list[Plugin] = [
2108
+
2109
+ ]
2110
+ if plugins:
2111
+ operation_plugins.extend(plugins)
2112
+
2113
+ return await self._execute_operation(
2114
+ input=input,
2115
+ plugins=operation_plugins,
2116
+ serialize=_serialize_update_organisation,
2117
+ deserialize=_deserialize_update_organisation,
2118
+ config=self._config,
2119
+ operation=UPDATE_ORGANISATION,
2120
+ )
2121
+
2122
+ async def update_override(self, input: UpdateOverrideInput, plugins: list[Plugin] | None = None) -> UpdateOverrideOutput:
2123
+ """
2124
+ Updates the overrides for an existing context. Allows modification of override
2125
+ values while maintaining the context's conditions.
2126
+
2127
+ :param input: The operation's input.
2128
+
2129
+ :param plugins: A list of callables that modify the configuration dynamically.
2130
+ Changes made by these plugins only apply for the duration of the operation
2131
+ execution and will not affect any other operation invocations.
2132
+
2133
+ """
2134
+ operation_plugins: list[Plugin] = [
2135
+
2136
+ ]
2137
+ if plugins:
2138
+ operation_plugins.extend(plugins)
2139
+
2140
+ return await self._execute_operation(
2141
+ input=input,
2142
+ plugins=operation_plugins,
2143
+ serialize=_serialize_update_override,
2144
+ deserialize=_deserialize_update_override,
2145
+ config=self._config,
2146
+ operation=UPDATE_OVERRIDE,
2147
+ )
2148
+
2149
+ async def update_overrides_experiment(self, input: UpdateOverridesExperimentInput, plugins: list[Plugin] | None = None) -> UpdateOverridesExperimentOutput:
2150
+ """
2151
+ Updates the overrides for specific variants within an experiment, allowing
2152
+ modification of experiment behavior Updates the overrides for specific variants
2153
+ within an experiment, allowing modification of experiment behavior while it is
2154
+ in the created state.
2155
+
2156
+ :param input: The operation's input.
2157
+
2158
+ :param plugins: A list of callables that modify the configuration dynamically.
2159
+ Changes made by these plugins only apply for the duration of the operation
2160
+ execution and will not affect any other operation invocations.
2161
+
2162
+ """
2163
+ operation_plugins: list[Plugin] = [
2164
+
2165
+ ]
2166
+ if plugins:
2167
+ operation_plugins.extend(plugins)
2168
+
2169
+ return await self._execute_operation(
2170
+ input=input,
2171
+ plugins=operation_plugins,
2172
+ serialize=_serialize_update_overrides_experiment,
2173
+ deserialize=_deserialize_update_overrides_experiment,
2174
+ config=self._config,
2175
+ operation=UPDATE_OVERRIDES_EXPERIMENT,
2176
+ )
2177
+
2178
+ async def update_type_templates(self, input: UpdateTypeTemplatesInput, plugins: list[Plugin] | None = None) -> UpdateTypeTemplatesOutput:
2179
+ """
2180
+ Updates an existing type template's schema definition and metadata while
2181
+ preserving its identifier and usage history.
2182
+
2183
+ :param input: The operation's input.
2184
+
2185
+ :param plugins: A list of callables that modify the configuration dynamically.
2186
+ Changes made by these plugins only apply for the duration of the operation
2187
+ execution and will not affect any other operation invocations.
2188
+
2189
+ """
2190
+ operation_plugins: list[Plugin] = [
2191
+
2192
+ ]
2193
+ if plugins:
2194
+ operation_plugins.extend(plugins)
2195
+
2196
+ return await self._execute_operation(
2197
+ input=input,
2198
+ plugins=operation_plugins,
2199
+ serialize=_serialize_update_type_templates,
2200
+ deserialize=_deserialize_update_type_templates,
2201
+ config=self._config,
2202
+ operation=UPDATE_TYPE_TEMPLATES,
2203
+ )
2204
+
2205
+ async def update_webhook(self, input: UpdateWebhookInput, plugins: list[Plugin] | None = None) -> UpdateWebhookOutput:
2206
+ """
2207
+ Updates an existing webhook config, allowing modification of URL, events,
2208
+ headers, and other webhook properties.
2209
+
2210
+ :param input: The operation's input.
2211
+
2212
+ :param plugins: A list of callables that modify the configuration dynamically.
2213
+ Changes made by these plugins only apply for the duration of the operation
2214
+ execution and will not affect any other operation invocations.
2215
+
2216
+ """
2217
+ operation_plugins: list[Plugin] = [
2218
+
2219
+ ]
2220
+ if plugins:
2221
+ operation_plugins.extend(plugins)
2222
+
2223
+ return await self._execute_operation(
2224
+ input=input,
2225
+ plugins=operation_plugins,
2226
+ serialize=_serialize_update_webhook,
2227
+ deserialize=_deserialize_update_webhook,
2228
+ config=self._config,
2229
+ operation=UPDATE_WEBHOOK,
2230
+ )
2231
+
2232
+ async def update_workspace(self, input: UpdateWorkspaceInput, plugins: list[Plugin] | None = None) -> UpdateWorkspaceOutput:
2233
+ """
2234
+ Updates an existing workspace configuration, allowing modification of admin
2235
+ settings, mandatory dimensions, and workspace properties. Validates config
2236
+ version existence if provided.
2237
+
2238
+ :param input: The operation's input.
2239
+
2240
+ :param plugins: A list of callables that modify the configuration dynamically.
2241
+ Changes made by these plugins only apply for the duration of the operation
2242
+ execution and will not affect any other operation invocations.
2243
+
2244
+ """
2245
+ operation_plugins: list[Plugin] = [
2246
+
2247
+ ]
2248
+ if plugins:
2249
+ operation_plugins.extend(plugins)
2250
+
2251
+ return await self._execute_operation(
2252
+ input=input,
2253
+ plugins=operation_plugins,
2254
+ serialize=_serialize_update_workspace,
2255
+ deserialize=_deserialize_update_workspace,
2256
+ config=self._config,
2257
+ operation=UPDATE_WORKSPACE,
2258
+ )
2259
+
2260
+ async def validate_context(self, input: ValidateContextInput, plugins: list[Plugin] | None = None) -> ValidateContextOutput:
2261
+ """
2262
+ Validates if a given context condition is well-formed
2263
+
2264
+ :param input: The operation's input.
2265
+
2266
+ :param plugins: A list of callables that modify the configuration dynamically.
2267
+ Changes made by these plugins only apply for the duration of the operation
2268
+ execution and will not affect any other operation invocations.
2269
+
2270
+ """
2271
+ operation_plugins: list[Plugin] = [
2272
+
2273
+ ]
2274
+ if plugins:
2275
+ operation_plugins.extend(plugins)
2276
+
2277
+ return await self._execute_operation(
2278
+ input=input,
2279
+ plugins=operation_plugins,
2280
+ serialize=_serialize_validate_context,
2281
+ deserialize=_deserialize_validate_context,
2282
+ config=self._config,
2283
+ operation=VALIDATE_CONTEXT,
2284
+ )
2285
+
2286
+ async def weight_recompute(self, input: WeightRecomputeInput, plugins: list[Plugin] | None = None) -> WeightRecomputeOutput:
2287
+ """
2288
+ Recalculates and updates the priority weights for all contexts in the workspace
2289
+ based on their dimensions.
2290
+
2291
+ :param input: The operation's input.
2292
+
2293
+ :param plugins: A list of callables that modify the configuration dynamically.
2294
+ Changes made by these plugins only apply for the duration of the operation
2295
+ execution and will not affect any other operation invocations.
2296
+
2297
+ """
2298
+ operation_plugins: list[Plugin] = [
2299
+
2300
+ ]
2301
+ if plugins:
2302
+ operation_plugins.extend(plugins)
2303
+
2304
+ return await self._execute_operation(
2305
+ input=input,
2306
+ plugins=operation_plugins,
2307
+ serialize=_serialize_weight_recompute,
2308
+ deserialize=_deserialize_weight_recompute,
2309
+ config=self._config,
2310
+ operation=WEIGHT_RECOMPUTE,
2311
+ )
2312
+
2313
+ def _classify_error(
2314
+ self,
2315
+ *,
2316
+ error: Exception,
2317
+ context: ResponseContext[Any, HTTPRequest, HTTPResponse | None]
2318
+ ) -> RetryErrorInfo:
2319
+ logger.debug("Classifying error: %s", error)
2320
+
2321
+ if not isinstance(error, HasFault) and not context.transport_response:
2322
+ return RetryErrorInfo(error_type=RetryErrorType.TRANSIENT)
2323
+
2324
+ if context.transport_response:
2325
+ if context.transport_response.status in [429, 503]:
2326
+ retry_after = None
2327
+ retry_header = context.transport_response.fields["retry-after"]
2328
+ if retry_header and retry_header.values:
2329
+ retry_after = float(retry_header.values[0])
2330
+ return RetryErrorInfo(error_type=RetryErrorType.THROTTLING, retry_after_hint=retry_after)
2331
+
2332
+ if context.transport_response.status >= 500:
2333
+ return RetryErrorInfo(error_type=RetryErrorType.SERVER_ERROR)
2334
+
2335
+ error_type = RetryErrorType.CLIENT_ERROR
2336
+ if isinstance(error, HasFault) and error.fault == "server":
2337
+ error_type = RetryErrorType.SERVER_ERROR
2338
+
2339
+ return RetryErrorInfo(error_type=error_type)
2340
+
2341
+ async def _execute_operation[Input: SerializeableShape, Output: DeserializeableShape](
2342
+ self,
2343
+ input: Input,
2344
+ plugins: list[Plugin],
2345
+ serialize: Callable[[Input, Config], Awaitable[HTTPRequest]],
2346
+ deserialize: Callable[[HTTPResponse, Config], Awaitable[Output]],
2347
+ config: Config,
2348
+ operation: APIOperation[Input, Output],
2349
+ request_future: Future[RequestContext[Any, HTTPRequest]] | None = None,
2350
+ response_future: Future[HTTPResponse] | None = None,
2351
+ ) -> Output:
2352
+ try:
2353
+ return await self._handle_execution(
2354
+ input, plugins, serialize, deserialize, config, operation,
2355
+ request_future, response_future,
2356
+ )
2357
+ except Exception as e:
2358
+ if request_future is not None and not request_future.done():
2359
+ request_future.set_exception(ServiceError(e))
2360
+ if response_future is not None and not response_future.done():
2361
+ response_future.set_exception(ServiceError(e))
2362
+
2363
+ # Make sure every exception that we throw is an instance of ServiceError so
2364
+ # customers can reliably catch everything we throw.
2365
+ if not isinstance(e, ServiceError):
2366
+ raise ServiceError(e) from e
2367
+ raise
2368
+
2369
+ async def _handle_execution[Input: SerializeableShape, Output: DeserializeableShape](
2370
+ self,
2371
+ input: Input,
2372
+ plugins: list[Plugin],
2373
+ serialize: Callable[[Input, Config], Awaitable[HTTPRequest]],
2374
+ deserialize: Callable[[HTTPResponse, Config], Awaitable[Output]],
2375
+ config: Config,
2376
+ operation: APIOperation[Input, Output],
2377
+ request_future: Future[RequestContext[Any, HTTPRequest]] | None,
2378
+ response_future: Future[HTTPResponse] | None,
2379
+ ) -> Output:
2380
+ operation_name = operation.schema.id.name
2381
+ logger.debug('Making request for operation "%s" with parameters: %s', operation_name, input)
2382
+ config = deepcopy(config)
2383
+ for plugin in plugins:
2384
+ plugin(config)
2385
+
2386
+ input_context = InputContext(request=input, properties=TypedProperties({"config": config}))
2387
+ transport_request: HTTPRequest | None = None
2388
+ output_context: OutputContext[Input, Output, HTTPRequest | None, HTTPResponse | None] | None = None
2389
+
2390
+ client_interceptors = cast(
2391
+ list[Interceptor[Input, Output, HTTPRequest, HTTPResponse]], list(config.interceptors)
2392
+ )
2393
+ interceptor_chain = InterceptorChain(client_interceptors)
2394
+
2395
+ try:
2396
+ # Step 1: Invoke read_before_execution
2397
+ interceptor_chain.read_before_execution(input_context)
2398
+
2399
+ # Step 2: Invoke the modify_before_serialization hooks
2400
+ input_context = replace(
2401
+ input_context,
2402
+ request=interceptor_chain.modify_before_serialization(input_context)
2403
+ )
2404
+
2405
+ # Step 3: Invoke the read_before_serialization hooks
2406
+ interceptor_chain.read_before_serialization(input_context)
2407
+
2408
+ # Step 4: Serialize the request
2409
+ logger.debug("Serializing request for: %s", input_context.request)
2410
+ transport_request = await serialize(input_context.request, config)
2411
+ request_context = RequestContext(
2412
+ request=input_context.request,
2413
+ transport_request=transport_request,
2414
+ properties=input_context.properties,
2415
+ )
2416
+ logger.debug("Serialization complete. Transport request: %s", request_context.transport_request)
2417
+
2418
+ # Step 5: Invoke read_after_serialization
2419
+ interceptor_chain.read_after_serialization(request_context)
2420
+
2421
+ # Step 6: Invoke modify_before_retry_loop
2422
+ request_context = replace(
2423
+ request_context,
2424
+ transport_request=interceptor_chain.modify_before_retry_loop(request_context)
2425
+ )
2426
+
2427
+ # Step 7: Acquire the retry token.
2428
+ retry_strategy = config.retry_strategy
2429
+ retry_token = retry_strategy.acquire_initial_retry_token()
2430
+
2431
+ while True:
2432
+ # Make an attempt
2433
+ output_context = await self._handle_attempt(
2434
+ deserialize,
2435
+ interceptor_chain,
2436
+ replace(
2437
+ request_context,
2438
+ transport_request = copy(request_context.transport_request)
2439
+ ),
2440
+ config,
2441
+ operation,
2442
+ request_future,
2443
+ )
2444
+
2445
+ if isinstance(output_context.response, Exception):
2446
+ # Step 7u: Reacquire retry token if the attempt failed
2447
+ try:
2448
+ retry_token = retry_strategy.refresh_retry_token_for_retry(
2449
+ token_to_renew=retry_token,
2450
+ error_info=self._classify_error(
2451
+ error=output_context.response,
2452
+ context=output_context,
2453
+ )
2454
+ )
2455
+ except SmithyRetryException:
2456
+ raise output_context.response
2457
+ logger.debug(
2458
+ "Retry needed. Attempting request #%s in %.4f seconds.",
2459
+ retry_token.retry_count + 1,
2460
+ retry_token.retry_delay
2461
+ )
2462
+ await sleep(retry_token.retry_delay)
2463
+ current_body = output_context.transport_request.body
2464
+ if (seek := getattr(current_body, "seek", None)) is not None:
2465
+ if iscoroutine((result := seek(0))):
2466
+ await result
2467
+ else:
2468
+ # Step 8: Invoke record_success
2469
+ retry_strategy.record_success(token=retry_token)
2470
+ if response_future is not None:
2471
+ response_future.set_result(
2472
+ output_context.transport_response # type: ignore
2473
+ )
2474
+ break
2475
+ except Exception as e:
2476
+ if output_context is not None:
2477
+ logger.exception("Exception occurred while handling: %s", output_context.response)
2478
+ output_context = replace(output_context, response=e)
2479
+ else:
2480
+ output_context = OutputContext(
2481
+ request=input_context.request,
2482
+ response=e,
2483
+ transport_request=transport_request,
2484
+ transport_response=None,
2485
+ properties=input_context.properties
2486
+ )
2487
+
2488
+ return await self._finalize_execution(interceptor_chain, output_context)
2489
+
2490
+ async def _handle_attempt[Input: SerializeableShape, Output: DeserializeableShape](
2491
+ self,
2492
+ deserialize: Callable[[HTTPResponse, Config], Awaitable[Output]],
2493
+ interceptor: Interceptor[Input, Output, HTTPRequest, HTTPResponse],
2494
+ context: RequestContext[Input, HTTPRequest],
2495
+ config: Config,
2496
+ operation: APIOperation[Input, Output],
2497
+ request_future: Future[RequestContext[Input, HTTPRequest]] | None,
2498
+ ) -> OutputContext[Input, Output, HTTPRequest, HTTPResponse | None]:
2499
+ transport_response: HTTPResponse | None = None
2500
+ try:
2501
+ # Step 7a: Invoke read_before_attempt
2502
+ interceptor.read_before_attempt(context)
2503
+
2504
+ # Step 7b: Invoke service_auth_scheme_resolver.resolve_auth_scheme
2505
+ auth_parameters: HTTPAuthParams = HTTPAuthParams(
2506
+ operation=operation.schema.id.name,
2507
+
2508
+ )
2509
+
2510
+ auth_options = config.http_auth_scheme_resolver.resolve_auth_scheme(
2511
+ auth_parameters=auth_parameters
2512
+ )
2513
+ auth_option: HTTPAuthOption | None = None
2514
+ for option in auth_options:
2515
+ if option.scheme_id in config.http_auth_schemes:
2516
+ auth_option = option
2517
+ break
2518
+
2519
+ signer: HTTPSigner[Any, Any] | None = None
2520
+ identity: Identity | None = None
2521
+
2522
+ if auth_option:
2523
+ auth_scheme = config.http_auth_schemes[auth_option.scheme_id]
2524
+
2525
+ # Step 7c: Invoke auth_scheme.identity_resolver
2526
+ identity_resolver = auth_scheme.identity_resolver(config=config)
2527
+
2528
+ # Step 7d: Invoke auth_scheme.signer
2529
+ signer = auth_scheme.signer
2530
+
2531
+ # Step 7e: Invoke identity_resolver.get_identity
2532
+ identity = await identity_resolver.get_identity(
2533
+ identity_properties=auth_option.identity_properties
2534
+ )
2535
+
2536
+ # Step 7f: Invoke endpoint_resolver.resolve_endpoint
2537
+ endpoint_resolver_parameters = EndpointResolverParams(
2538
+ operation=operation,
2539
+ input=context.request,
2540
+ context=context.properties
2541
+ )
2542
+ logger.debug("Calling endpoint resolver with parameters: %s", endpoint_resolver_parameters)
2543
+ endpoint = await config.endpoint_resolver.resolve_endpoint(
2544
+ endpoint_resolver_parameters
2545
+ )
2546
+ logger.debug("Endpoint resolver result: %s", endpoint)
2547
+ if not endpoint.uri.path:
2548
+ path = ""
2549
+ elif endpoint.uri.path.endswith("/"):
2550
+ path = endpoint.uri.path[:-1]
2551
+ else:
2552
+ path = endpoint.uri.path
2553
+ if context.transport_request.destination.path:
2554
+ path += context.transport_request.destination.path
2555
+ context.transport_request.destination = URI(
2556
+ scheme=endpoint.uri.scheme,
2557
+ host=context.transport_request.destination.host + endpoint.uri.host,
2558
+ path=path,
2559
+ port=endpoint.uri.port,
2560
+ query=context.transport_request.destination.query,
2561
+ )
2562
+
2563
+ if (headers := endpoint.properties.get("headers")) is not None:
2564
+ context.transport_request.fields.extend(headers)
2565
+
2566
+ # Step 7g: Invoke modify_before_signing
2567
+ context = replace(
2568
+ context,
2569
+ transport_request=interceptor.modify_before_signing(context)
2570
+ )
2571
+
2572
+ # Step 7h: Invoke read_before_signing
2573
+ interceptor.read_before_signing(context)
2574
+
2575
+ # Step 7i: sign the request
2576
+ if auth_option and signer:
2577
+ logger.debug("HTTP request to sign: %s", context.transport_request)
2578
+ logger.debug(
2579
+ "Signer properties: %s",
2580
+ auth_option.signer_properties
2581
+ )
2582
+ context = replace(
2583
+ context,
2584
+ transport_request= await signer.sign(
2585
+ http_request=context.transport_request,
2586
+ identity=identity,
2587
+ signing_properties=auth_option.signer_properties,
2588
+ )
2589
+ )
2590
+ logger.debug("Signed HTTP request: %s", context.transport_request)
2591
+
2592
+ # TODO - Move this to separate resolution/population function
2593
+ fields = context.transport_request.fields
2594
+ auth_value = fields["Authorization"].as_string() # type: ignore
2595
+ signature = re.split("Signature=", auth_value)[-1] # type: ignore
2596
+ context.properties["signature"] = signature.encode('utf-8')
2597
+
2598
+ identity_key: PropertyKey[Identity | None] = PropertyKey(
2599
+ key="identity",
2600
+ value_type=Identity | None # type: ignore
2601
+ )
2602
+ sp_key: PropertyKey[dict[str, Any]] = PropertyKey(
2603
+ key="signer_properties",
2604
+ value_type=dict[str, Any] # type: ignore
2605
+ )
2606
+ context.properties[identity_key] = identity
2607
+ context.properties[sp_key] = auth_option.signer_properties
2608
+
2609
+ # Step 7j: Invoke read_after_signing
2610
+ interceptor.read_after_signing(context)
2611
+
2612
+ # Step 7k: Invoke modify_before_transmit
2613
+ context = replace(
2614
+ context,
2615
+ transport_request=interceptor.modify_before_transmit(context)
2616
+ )
2617
+
2618
+ # Step 7l: Invoke read_before_transmit
2619
+ interceptor.read_before_transmit(context)
2620
+
2621
+ # Step 7m: Invoke http_client.send
2622
+ request_config = config.http_request_config or HTTPRequestConfiguration()
2623
+ logger.debug("HTTP request config: %s", request_config)
2624
+ logger.debug("Sending HTTP request: %s", context.transport_request)
2625
+
2626
+ if request_future is not None:
2627
+ response_task = asyncio.create_task(config.http_client.send(
2628
+ request=context.transport_request,
2629
+ request_config=request_config,
2630
+ ))
2631
+ request_future.set_result(context)
2632
+ transport_response = await response_task
2633
+ else:
2634
+ transport_response = await config.http_client.send(
2635
+ request=context.transport_request,
2636
+ request_config=request_config,
2637
+ )
2638
+
2639
+ response_context = ResponseContext(
2640
+ request=context.request,
2641
+ transport_request=context.transport_request,
2642
+ transport_response=transport_response,
2643
+ properties=context.properties
2644
+ )
2645
+ logger.debug("Received HTTP response: %s", response_context.transport_response)
2646
+
2647
+ # Step 7n: Invoke read_after_transmit
2648
+ interceptor.read_after_transmit(response_context)
2649
+
2650
+ # Step 7o: Invoke modify_before_deserialization
2651
+ response_context = replace(
2652
+ response_context,
2653
+ transport_response=interceptor.modify_before_deserialization(response_context)
2654
+ )
2655
+
2656
+ # Step 7p: Invoke read_before_deserialization
2657
+ interceptor.read_before_deserialization(response_context)
2658
+
2659
+ # Step 7q: deserialize
2660
+ logger.debug("Deserializing transport response: %s", response_context.transport_response)
2661
+ output = await deserialize(
2662
+ response_context.transport_response, config
2663
+ )
2664
+ output_context = OutputContext(
2665
+ request=response_context.request,
2666
+ response=output,
2667
+ transport_request=response_context.transport_request,
2668
+ transport_response=response_context.transport_response,
2669
+ properties=response_context.properties
2670
+ )
2671
+ logger.debug("Deserialization complete. Response: %s", output_context.response)
2672
+
2673
+ # Step 7r: Invoke read_after_deserialization
2674
+ interceptor.read_after_deserialization(output_context)
2675
+ except Exception as e:
2676
+ output_context: OutputContext[Input, Output, HTTPRequest, HTTPResponse] = OutputContext(
2677
+ request=context.request,
2678
+ response=e, # type: ignore
2679
+ transport_request=context.transport_request,
2680
+ transport_response=transport_response,
2681
+ properties=context.properties
2682
+ )
2683
+
2684
+ return await self._finalize_attempt(interceptor, output_context)
2685
+
2686
+ async def _finalize_attempt[Input: SerializeableShape, Output: DeserializeableShape](
2687
+ self,
2688
+ interceptor: Interceptor[Input, Output, HTTPRequest, HTTPResponse],
2689
+ context: OutputContext[Input, Output, HTTPRequest, HTTPResponse | None],
2690
+ ) -> OutputContext[Input, Output, HTTPRequest, HTTPResponse | None]:
2691
+ # Step 7s: Invoke modify_before_attempt_completion
2692
+ try:
2693
+ context = replace(
2694
+ context,
2695
+ response=interceptor.modify_before_attempt_completion(context)
2696
+ )
2697
+ except Exception as e:
2698
+ logger.exception("Exception occurred while handling: %s", context.response)
2699
+ context = replace(context, response=e)
2700
+
2701
+ # Step 7t: Invoke read_after_attempt
2702
+ try:
2703
+ interceptor.read_after_attempt(context)
2704
+ except Exception as e:
2705
+ context = replace(context, response=e)
2706
+
2707
+ return context
2708
+
2709
+ async def _finalize_execution[Input: SerializeableShape, Output: DeserializeableShape](
2710
+ self,
2711
+ interceptor: Interceptor[Input, Output, HTTPRequest, HTTPResponse],
2712
+ context: OutputContext[Input, Output, HTTPRequest | None, HTTPResponse | None],
2713
+ ) -> Output:
2714
+ try:
2715
+ # Step 9: Invoke modify_before_completion
2716
+ context = replace(
2717
+ context,
2718
+ response=interceptor.modify_before_completion(context)
2719
+ )
2720
+
2721
+ # Step 10: Invoke trace_probe.dispatch_events
2722
+ try:
2723
+ pass
2724
+ except Exception as e:
2725
+ # log and ignore exceptions
2726
+ logger.exception("Exception occurred while dispatching trace events: %s", e)
2727
+ pass
2728
+ except Exception as e:
2729
+ logger.exception("Exception occurred while handling: %s", context.response)
2730
+ context = replace(context, response=e)
2731
+
2732
+ # Step 11: Invoke read_after_execution
2733
+ try:
2734
+ interceptor.read_after_execution(context)
2735
+ except Exception as e:
2736
+ context = replace(context, response=e)
2737
+
2738
+ # Step 12: Return / throw
2739
+ if isinstance(context.response, Exception):
2740
+ raise context.response
2741
+
2742
+ # We may want to add some aspects of this context to the output types so we can
2743
+ # return it to the end-users.
2744
+ return context.response