airbyte-cdk 6.32.0__py3-none-any.whl → 6.33.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airbyte_cdk/sources/declarative/auth/token.py +3 -8
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +13 -2
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +14 -4
- airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +7 -6
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +10 -4
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +34 -30
- airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py +4 -2
- airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py +3 -9
- airbyte_cdk/sources/declarative/requesters/http_requester.py +5 -1
- airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +6 -5
- airbyte_cdk/sources/declarative/requesters/request_option.py +83 -4
- airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py +7 -6
- airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +4 -1
- airbyte_cdk/utils/mapping_helpers.py +86 -27
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/METADATA +1 -1
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/RECORD +20 -20
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/WHEEL +0 -0
- {airbyte_cdk-6.32.0.dist-info → airbyte_cdk-6.33.0.dist-info}/entry_points.txt +0 -0
@@ -5,7 +5,7 @@
|
|
5
5
|
import base64
|
6
6
|
import logging
|
7
7
|
from dataclasses import InitVar, dataclass
|
8
|
-
from typing import Any, Mapping, Union
|
8
|
+
from typing import Any, Mapping, MutableMapping, Union
|
9
9
|
|
10
10
|
import requests
|
11
11
|
from cachetools import TTLCache, cached
|
@@ -45,11 +45,6 @@ class ApiKeyAuthenticator(DeclarativeAuthenticator):
|
|
45
45
|
config: Config
|
46
46
|
parameters: InitVar[Mapping[str, Any]]
|
47
47
|
|
48
|
-
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
49
|
-
self._field_name = InterpolatedString.create(
|
50
|
-
self.request_option.field_name, parameters=parameters
|
51
|
-
)
|
52
|
-
|
53
48
|
@property
|
54
49
|
def auth_header(self) -> str:
|
55
50
|
options = self._get_request_options(RequestOptionType.header)
|
@@ -60,9 +55,9 @@ class ApiKeyAuthenticator(DeclarativeAuthenticator):
|
|
60
55
|
return self.token_provider.get_token()
|
61
56
|
|
62
57
|
def _get_request_options(self, option_type: RequestOptionType) -> Mapping[str, Any]:
|
63
|
-
options = {}
|
58
|
+
options: MutableMapping[str, Any] = {}
|
64
59
|
if self.request_option.inject_into == option_type:
|
65
|
-
|
60
|
+
self.request_option.inject_into_request(options, self.token, self.config)
|
66
61
|
return options
|
67
62
|
|
68
63
|
def get_request_params(self) -> Mapping[str, Any]:
|
@@ -475,10 +475,21 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
|
475
475
|
# Also a temporary hack. In the legacy Stream implementation, as part of the read,
|
476
476
|
# set_initial_state() is called to instantiate incoming state on the cursor. Although we no
|
477
477
|
# longer rely on the legacy low-code cursor for concurrent checkpointing, low-code components
|
478
|
-
# like StopConditionPaginationStrategyDecorator
|
479
|
-
#
|
478
|
+
# like StopConditionPaginationStrategyDecorator still rely on a DatetimeBasedCursor that is
|
479
|
+
# properly initialized with state.
|
480
480
|
if retriever.cursor:
|
481
481
|
retriever.cursor.set_initial_state(stream_state=stream_state)
|
482
|
+
|
483
|
+
# Similar to above, the ClientSideIncrementalRecordFilterDecorator cursor is a separate instance
|
484
|
+
# from the one initialized on the SimpleRetriever, so it also must also have state initialized
|
485
|
+
# for semi-incremental streams using is_client_side_incremental to filter properly
|
486
|
+
if isinstance(retriever.record_selector, RecordSelector) and isinstance(
|
487
|
+
retriever.record_selector.record_filter, ClientSideIncrementalRecordFilterDecorator
|
488
|
+
):
|
489
|
+
retriever.record_selector.record_filter._cursor.set_initial_state(
|
490
|
+
stream_state=stream_state
|
491
|
+
) # type: ignore # After non-concurrent cursors are deprecated we can remove these cursor workarounds
|
492
|
+
|
482
493
|
# We zero it out here, but since this is a cursor reference, the state is still properly
|
483
494
|
# instantiated for the other components that reference it
|
484
495
|
retriever.cursor = None
|
@@ -2847,25 +2847,35 @@ definitions:
|
|
2847
2847
|
enum: [RequestPath]
|
2848
2848
|
RequestOption:
|
2849
2849
|
title: Request Option
|
2850
|
-
description: Specifies the key field and where in the request a component's value should be injected.
|
2850
|
+
description: Specifies the key field or path and where in the request a component's value should be injected.
|
2851
2851
|
type: object
|
2852
2852
|
required:
|
2853
2853
|
- type
|
2854
|
-
- field_name
|
2855
2854
|
- inject_into
|
2856
2855
|
properties:
|
2857
2856
|
type:
|
2858
2857
|
type: string
|
2859
2858
|
enum: [RequestOption]
|
2860
2859
|
field_name:
|
2861
|
-
title:
|
2862
|
-
description: Configures which key should be used in the location that the descriptor is being injected into
|
2860
|
+
title: Field Name
|
2861
|
+
description: Configures which key should be used in the location that the descriptor is being injected into. We hope to eventually deprecate this field in favor of `field_path` for all request_options, but must currently maintain it for backwards compatibility in the Builder.
|
2863
2862
|
type: string
|
2864
2863
|
examples:
|
2865
2864
|
- segment_id
|
2866
2865
|
interpolation_context:
|
2867
2866
|
- config
|
2868
2867
|
- parameters
|
2868
|
+
field_path:
|
2869
|
+
title: Field Path
|
2870
|
+
description: Configures a path to be used for nested structures in JSON body requests (e.g. GraphQL queries)
|
2871
|
+
type: array
|
2872
|
+
items:
|
2873
|
+
type: string
|
2874
|
+
examples:
|
2875
|
+
- ["data", "viewer", "id"]
|
2876
|
+
interpolation_context:
|
2877
|
+
- config
|
2878
|
+
- parameters
|
2869
2879
|
inject_into:
|
2870
2880
|
title: Inject Into
|
2871
2881
|
description: Configures where the descriptor should be set on the HTTP requests. Note that request parameters that are already encoded in the URL path will not be duplicated.
|
@@ -365,14 +365,15 @@ class DatetimeBasedCursor(DeclarativeCursor):
|
|
365
365
|
options: MutableMapping[str, Any] = {}
|
366
366
|
if not stream_slice:
|
367
367
|
return options
|
368
|
+
|
368
369
|
if self.start_time_option and self.start_time_option.inject_into == option_type:
|
369
|
-
|
370
|
-
|
371
|
-
|
370
|
+
start_time_value = stream_slice.get(self._partition_field_start.eval(self.config))
|
371
|
+
self.start_time_option.inject_into_request(options, start_time_value, self.config)
|
372
|
+
|
372
373
|
if self.end_time_option and self.end_time_option.inject_into == option_type:
|
373
|
-
|
374
|
-
|
375
|
-
|
374
|
+
end_time_value = stream_slice.get(self._partition_field_end.eval(self.config))
|
375
|
+
self.end_time_option.inject_into_request(options, end_time_value, self.config)
|
376
|
+
|
376
377
|
return options
|
377
378
|
|
378
379
|
def should_be_synced(self, record: Record) -> bool:
|
@@ -1200,11 +1200,17 @@ class InjectInto(Enum):
|
|
1200
1200
|
|
1201
1201
|
class RequestOption(BaseModel):
|
1202
1202
|
type: Literal["RequestOption"]
|
1203
|
-
field_name: str = Field(
|
1204
|
-
|
1205
|
-
description="Configures which key should be used in the location that the descriptor is being injected into",
|
1203
|
+
field_name: Optional[str] = Field(
|
1204
|
+
None,
|
1205
|
+
description="Configures which key should be used in the location that the descriptor is being injected into. We hope to eventually deprecate this field in favor of `field_path` for all request_options, but must currently maintain it for backwards compatibility in the Builder.",
|
1206
1206
|
examples=["segment_id"],
|
1207
|
-
title="
|
1207
|
+
title="Field Name",
|
1208
|
+
)
|
1209
|
+
field_path: Optional[List[str]] = Field(
|
1210
|
+
None,
|
1211
|
+
description="Configures a path to be used for nested structures in JSON body requests (e.g. GraphQL queries)",
|
1212
|
+
examples=[["data", "viewer", "id"]],
|
1213
|
+
title="Field Path",
|
1208
1214
|
)
|
1209
1215
|
inject_into: InjectInto = Field(
|
1210
1216
|
...,
|
@@ -733,8 +733,8 @@ class ModelToComponentFactory:
|
|
733
733
|
}
|
734
734
|
return names_to_types[value_type]
|
735
735
|
|
736
|
-
@staticmethod
|
737
736
|
def create_api_key_authenticator(
|
737
|
+
self,
|
738
738
|
model: ApiKeyAuthenticatorModel,
|
739
739
|
config: Config,
|
740
740
|
token_provider: Optional[TokenProvider] = None,
|
@@ -756,10 +756,8 @@ class ModelToComponentFactory:
|
|
756
756
|
)
|
757
757
|
|
758
758
|
request_option = (
|
759
|
-
|
760
|
-
inject_into=
|
761
|
-
field_name=model.inject_into.field_name,
|
762
|
-
parameters=model.parameters or {},
|
759
|
+
self._create_component_from_model(
|
760
|
+
model.inject_into, config, parameters=model.parameters or {}
|
763
761
|
)
|
764
762
|
if model.inject_into
|
765
763
|
else RequestOption(
|
@@ -768,6 +766,7 @@ class ModelToComponentFactory:
|
|
768
766
|
parameters=model.parameters or {},
|
769
767
|
)
|
770
768
|
)
|
769
|
+
|
771
770
|
return ApiKeyAuthenticator(
|
772
771
|
token_provider=(
|
773
772
|
token_provider
|
@@ -849,7 +848,7 @@ class ModelToComponentFactory:
|
|
849
848
|
token_provider=token_provider,
|
850
849
|
)
|
851
850
|
else:
|
852
|
-
return
|
851
|
+
return self.create_api_key_authenticator(
|
853
852
|
ApiKeyAuthenticatorModel(
|
854
853
|
type="ApiKeyAuthenticator",
|
855
854
|
api_token="",
|
@@ -1489,19 +1488,15 @@ class ModelToComponentFactory:
|
|
1489
1488
|
)
|
1490
1489
|
|
1491
1490
|
end_time_option = (
|
1492
|
-
|
1493
|
-
|
1494
|
-
field_name=model.end_time_option.field_name,
|
1495
|
-
parameters=model.parameters or {},
|
1491
|
+
self._create_component_from_model(
|
1492
|
+
model.end_time_option, config, parameters=model.parameters or {}
|
1496
1493
|
)
|
1497
1494
|
if model.end_time_option
|
1498
1495
|
else None
|
1499
1496
|
)
|
1500
1497
|
start_time_option = (
|
1501
|
-
|
1502
|
-
|
1503
|
-
field_name=model.start_time_option.field_name,
|
1504
|
-
parameters=model.parameters or {},
|
1498
|
+
self._create_component_from_model(
|
1499
|
+
model.start_time_option, config, parameters=model.parameters or {}
|
1505
1500
|
)
|
1506
1501
|
if model.start_time_option
|
1507
1502
|
else None
|
@@ -1572,19 +1567,15 @@ class ModelToComponentFactory:
|
|
1572
1567
|
cursor_model = model.incremental_sync
|
1573
1568
|
|
1574
1569
|
end_time_option = (
|
1575
|
-
|
1576
|
-
|
1577
|
-
field_name=cursor_model.end_time_option.field_name,
|
1578
|
-
parameters=cursor_model.parameters or {},
|
1570
|
+
self._create_component_from_model(
|
1571
|
+
cursor_model.end_time_option, config, parameters=cursor_model.parameters or {}
|
1579
1572
|
)
|
1580
1573
|
if cursor_model.end_time_option
|
1581
1574
|
else None
|
1582
1575
|
)
|
1583
1576
|
start_time_option = (
|
1584
|
-
|
1585
|
-
|
1586
|
-
field_name=cursor_model.start_time_option.field_name,
|
1587
|
-
parameters=cursor_model.parameters or {},
|
1577
|
+
self._create_component_from_model(
|
1578
|
+
cursor_model.start_time_option, config, parameters=cursor_model.parameters or {}
|
1588
1579
|
)
|
1589
1580
|
if cursor_model.start_time_option
|
1590
1581
|
else None
|
@@ -2150,16 +2141,11 @@ class ModelToComponentFactory:
|
|
2150
2141
|
additional_jwt_payload=model.additional_jwt_payload,
|
2151
2142
|
)
|
2152
2143
|
|
2153
|
-
@staticmethod
|
2154
2144
|
def create_list_partition_router(
|
2155
|
-
model: ListPartitionRouterModel, config: Config, **kwargs: Any
|
2145
|
+
self, model: ListPartitionRouterModel, config: Config, **kwargs: Any
|
2156
2146
|
) -> ListPartitionRouter:
|
2157
2147
|
request_option = (
|
2158
|
-
|
2159
|
-
inject_into=RequestOptionType(model.request_option.inject_into.value),
|
2160
|
-
field_name=model.request_option.field_name,
|
2161
|
-
parameters=model.parameters or {},
|
2162
|
-
)
|
2148
|
+
self._create_component_from_model(model.request_option, config)
|
2163
2149
|
if model.request_option
|
2164
2150
|
else None
|
2165
2151
|
)
|
@@ -2355,7 +2341,25 @@ class ModelToComponentFactory:
|
|
2355
2341
|
model: RequestOptionModel, config: Config, **kwargs: Any
|
2356
2342
|
) -> RequestOption:
|
2357
2343
|
inject_into = RequestOptionType(model.inject_into.value)
|
2358
|
-
|
2344
|
+
field_path: Optional[List[Union[InterpolatedString, str]]] = (
|
2345
|
+
[
|
2346
|
+
InterpolatedString.create(segment, parameters=kwargs.get("parameters", {}))
|
2347
|
+
for segment in model.field_path
|
2348
|
+
]
|
2349
|
+
if model.field_path
|
2350
|
+
else None
|
2351
|
+
)
|
2352
|
+
field_name = (
|
2353
|
+
InterpolatedString.create(model.field_name, parameters=kwargs.get("parameters", {}))
|
2354
|
+
if model.field_name
|
2355
|
+
else None
|
2356
|
+
)
|
2357
|
+
return RequestOption(
|
2358
|
+
field_name=field_name,
|
2359
|
+
field_path=field_path,
|
2360
|
+
inject_into=inject_into,
|
2361
|
+
parameters=kwargs.get("parameters", {}),
|
2362
|
+
)
|
2359
2363
|
|
2360
2364
|
def create_record_selector(
|
2361
2365
|
self,
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
|
5
5
|
from dataclasses import InitVar, dataclass
|
6
|
-
from typing import Any, Iterable, List, Mapping, Optional, Union
|
6
|
+
from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Union
|
7
7
|
|
8
8
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
9
9
|
from airbyte_cdk.sources.declarative.partition_routers.partition_router import PartitionRouter
|
@@ -100,7 +100,9 @@ class ListPartitionRouter(PartitionRouter):
|
|
100
100
|
):
|
101
101
|
slice_value = stream_slice.get(self._cursor_field.eval(self.config))
|
102
102
|
if slice_value:
|
103
|
-
|
103
|
+
options: MutableMapping[str, Any] = {}
|
104
|
+
self.request_option.inject_into_request(options, slice_value, self.config)
|
105
|
+
return options
|
104
106
|
else:
|
105
107
|
return {}
|
106
108
|
else:
|
@@ -4,7 +4,7 @@
|
|
4
4
|
import copy
|
5
5
|
import logging
|
6
6
|
from dataclasses import InitVar, dataclass
|
7
|
-
from typing import TYPE_CHECKING, Any, Iterable, List, Mapping, Optional, Union
|
7
|
+
from typing import TYPE_CHECKING, Any, Iterable, List, Mapping, MutableMapping, Optional, Union
|
8
8
|
|
9
9
|
import dpath
|
10
10
|
|
@@ -118,7 +118,7 @@ class SubstreamPartitionRouter(PartitionRouter):
|
|
118
118
|
def _get_request_option(
|
119
119
|
self, option_type: RequestOptionType, stream_slice: Optional[StreamSlice]
|
120
120
|
) -> Mapping[str, Any]:
|
121
|
-
params = {}
|
121
|
+
params: MutableMapping[str, Any] = {}
|
122
122
|
if stream_slice:
|
123
123
|
for parent_config in self.parent_stream_configs:
|
124
124
|
if (
|
@@ -128,13 +128,7 @@ class SubstreamPartitionRouter(PartitionRouter):
|
|
128
128
|
key = parent_config.partition_field.eval(self.config) # type: ignore # partition_field is always casted to an interpolated string
|
129
129
|
value = stream_slice.get(key)
|
130
130
|
if value:
|
131
|
-
params.
|
132
|
-
{
|
133
|
-
parent_config.request_option.field_name.eval( # type: ignore [union-attr]
|
134
|
-
config=self.config
|
135
|
-
): value
|
136
|
-
}
|
137
|
-
)
|
131
|
+
parent_config.request_option.inject_into_request(params, value, self.config)
|
138
132
|
return params
|
139
133
|
|
140
134
|
def stream_slices(self) -> Iterable[StreamSlice]:
|
@@ -199,6 +199,9 @@ class HttpRequester(Requester):
|
|
199
199
|
Raise a ValueError if there's a key collision
|
200
200
|
Returned merged mapping otherwise
|
201
201
|
"""
|
202
|
+
|
203
|
+
is_body_json = requester_method.__name__ == "get_request_body_json"
|
204
|
+
|
202
205
|
return combine_mappings(
|
203
206
|
[
|
204
207
|
requester_method(
|
@@ -208,7 +211,8 @@ class HttpRequester(Requester):
|
|
208
211
|
),
|
209
212
|
auth_options_method(),
|
210
213
|
extra_options,
|
211
|
-
]
|
214
|
+
],
|
215
|
+
allow_same_value_merge=is_body_json,
|
212
216
|
)
|
213
217
|
|
214
218
|
def _request_headers(
|
@@ -187,7 +187,7 @@ class DefaultPaginator(Paginator):
|
|
187
187
|
def _get_request_options(
|
188
188
|
self, option_type: RequestOptionType, next_page_token: Optional[Mapping[str, Any]]
|
189
189
|
) -> MutableMapping[str, Any]:
|
190
|
-
options = {}
|
190
|
+
options: MutableMapping[str, Any] = {}
|
191
191
|
|
192
192
|
token = next_page_token.get("next_page_token") if next_page_token else None
|
193
193
|
if (
|
@@ -196,15 +196,16 @@ class DefaultPaginator(Paginator):
|
|
196
196
|
and isinstance(self.page_token_option, RequestOption)
|
197
197
|
and self.page_token_option.inject_into == option_type
|
198
198
|
):
|
199
|
-
|
199
|
+
self.page_token_option.inject_into_request(options, token, self.config)
|
200
|
+
|
200
201
|
if (
|
201
202
|
self.page_size_option
|
202
203
|
and self.pagination_strategy.get_page_size()
|
203
204
|
and self.page_size_option.inject_into == option_type
|
204
205
|
):
|
205
|
-
|
206
|
-
|
207
|
-
|
206
|
+
page_size = self.pagination_strategy.get_page_size()
|
207
|
+
self.page_size_option.inject_into_request(options, page_size, self.config)
|
208
|
+
|
208
209
|
return options
|
209
210
|
|
210
211
|
|
@@ -4,9 +4,10 @@
|
|
4
4
|
|
5
5
|
from dataclasses import InitVar, dataclass
|
6
6
|
from enum import Enum
|
7
|
-
from typing import Any, Mapping, Union
|
7
|
+
from typing import Any, List, Literal, Mapping, MutableMapping, Optional, Union
|
8
8
|
|
9
9
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
10
|
+
from airbyte_cdk.sources.types import Config
|
10
11
|
|
11
12
|
|
12
13
|
class RequestOptionType(Enum):
|
@@ -26,13 +27,91 @@ class RequestOption:
|
|
26
27
|
Describes an option to set on a request
|
27
28
|
|
28
29
|
Attributes:
|
29
|
-
field_name (str): Describes the name of the parameter to inject
|
30
|
+
field_name (str): Describes the name of the parameter to inject. Mutually exclusive with field_path.
|
31
|
+
field_path (list(str)): Describes the path to a nested field as a list of field names.
|
32
|
+
Only valid for body_json injection type, and mutually exclusive with field_name.
|
30
33
|
inject_into (RequestOptionType): Describes where in the HTTP request to inject the parameter
|
31
34
|
"""
|
32
35
|
|
33
|
-
field_name: Union[InterpolatedString, str]
|
34
36
|
inject_into: RequestOptionType
|
35
37
|
parameters: InitVar[Mapping[str, Any]]
|
38
|
+
field_name: Optional[Union[InterpolatedString, str]] = None
|
39
|
+
field_path: Optional[List[Union[InterpolatedString, str]]] = None
|
36
40
|
|
37
41
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
38
|
-
|
42
|
+
# Validate inputs. We should expect either field_name or field_path, but not both
|
43
|
+
if self.field_name is None and self.field_path is None:
|
44
|
+
raise ValueError("RequestOption requires either a field_name or field_path")
|
45
|
+
|
46
|
+
if self.field_name is not None and self.field_path is not None:
|
47
|
+
raise ValueError(
|
48
|
+
"Only one of field_name or field_path can be provided to RequestOption"
|
49
|
+
)
|
50
|
+
|
51
|
+
# Nested field injection is only supported for body JSON injection
|
52
|
+
if self.field_path is not None and self.inject_into != RequestOptionType.body_json:
|
53
|
+
raise ValueError(
|
54
|
+
"Nested field injection is only supported for body JSON injection. Please use a top-level field_name for other injection types."
|
55
|
+
)
|
56
|
+
|
57
|
+
# Convert field_name and field_path into InterpolatedString objects if they are strings
|
58
|
+
if self.field_name is not None:
|
59
|
+
self.field_name = InterpolatedString.create(self.field_name, parameters=parameters)
|
60
|
+
elif self.field_path is not None:
|
61
|
+
self.field_path = [
|
62
|
+
InterpolatedString.create(segment, parameters=parameters)
|
63
|
+
for segment in self.field_path
|
64
|
+
]
|
65
|
+
|
66
|
+
@property
|
67
|
+
def _is_field_path(self) -> bool:
|
68
|
+
"""Returns whether this option is a field path (ie, a nested field)"""
|
69
|
+
return self.field_path is not None
|
70
|
+
|
71
|
+
def inject_into_request(
|
72
|
+
self,
|
73
|
+
target: MutableMapping[str, Any],
|
74
|
+
value: Any,
|
75
|
+
config: Config,
|
76
|
+
) -> None:
|
77
|
+
"""
|
78
|
+
Inject a request option value into a target request structure using either field_name or field_path.
|
79
|
+
For non-body-json injection, only top-level field names are supported.
|
80
|
+
For body-json injection, both field names and nested field paths are supported.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
target: The request structure to inject the value into
|
84
|
+
value: The value to inject
|
85
|
+
config: The config object to use for interpolation
|
86
|
+
"""
|
87
|
+
if self._is_field_path:
|
88
|
+
if self.inject_into != RequestOptionType.body_json:
|
89
|
+
raise ValueError(
|
90
|
+
"Nested field injection is only supported for body JSON injection. Please use a top-level field_name for other injection types."
|
91
|
+
)
|
92
|
+
|
93
|
+
assert self.field_path is not None # for type checker
|
94
|
+
current = target
|
95
|
+
# Convert path segments into strings, evaluating any interpolated segments
|
96
|
+
# Example: ["data", "{{ config[user_type] }}", "id"] -> ["data", "admin", "id"]
|
97
|
+
*path_parts, final_key = [
|
98
|
+
str(
|
99
|
+
segment.eval(config=config)
|
100
|
+
if isinstance(segment, InterpolatedString)
|
101
|
+
else segment
|
102
|
+
)
|
103
|
+
for segment in self.field_path
|
104
|
+
]
|
105
|
+
|
106
|
+
# Build a nested dictionary structure and set the final value at the deepest level
|
107
|
+
for part in path_parts:
|
108
|
+
current = current.setdefault(part, {})
|
109
|
+
current[final_key] = value
|
110
|
+
else:
|
111
|
+
# For non-nested fields, evaluate the field name if it's an interpolated string
|
112
|
+
key = (
|
113
|
+
self.field_name.eval(config=config)
|
114
|
+
if isinstance(self.field_name, InterpolatedString)
|
115
|
+
else self.field_name
|
116
|
+
)
|
117
|
+
target[str(key)] = value
|
@@ -80,12 +80,13 @@ class DatetimeBasedRequestOptionsProvider(RequestOptionsProvider):
|
|
80
80
|
options: MutableMapping[str, Any] = {}
|
81
81
|
if not stream_slice:
|
82
82
|
return options
|
83
|
+
|
83
84
|
if self.start_time_option and self.start_time_option.inject_into == option_type:
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
start_time_value = stream_slice.get(self._partition_field_start.eval(self.config))
|
86
|
+
self.start_time_option.inject_into_request(options, start_time_value, self.config)
|
87
|
+
|
87
88
|
if self.end_time_option and self.end_time_option.inject_into == option_type:
|
88
|
-
|
89
|
-
|
90
|
-
|
89
|
+
end_time_value = stream_slice.get(self._partition_field_end.eval(self.config))
|
90
|
+
self.end_time_option.inject_into_request(options, end_time_value, self.config)
|
91
|
+
|
91
92
|
return options
|
@@ -128,6 +128,9 @@ class SimpleRetriever(Retriever):
|
|
128
128
|
Returned merged mapping otherwise
|
129
129
|
"""
|
130
130
|
# FIXME we should eventually remove the usage of stream_state as part of the interpolation
|
131
|
+
|
132
|
+
is_body_json = paginator_method.__name__ == "get_request_body_json"
|
133
|
+
|
131
134
|
mappings = [
|
132
135
|
paginator_method(
|
133
136
|
stream_state=stream_state,
|
@@ -143,7 +146,7 @@ class SimpleRetriever(Retriever):
|
|
143
146
|
next_page_token=next_page_token,
|
144
147
|
)
|
145
148
|
)
|
146
|
-
return combine_mappings(mappings)
|
149
|
+
return combine_mappings(mappings, allow_same_value_merge=is_body_json)
|
147
150
|
|
148
151
|
def _request_headers(
|
149
152
|
self,
|
@@ -3,43 +3,102 @@
|
|
3
3
|
#
|
4
4
|
|
5
5
|
|
6
|
-
|
6
|
+
import copy
|
7
|
+
from typing import Any, Dict, List, Mapping, Optional, Union
|
8
|
+
|
9
|
+
|
10
|
+
def _merge_mappings(
|
11
|
+
target: Dict[str, Any],
|
12
|
+
source: Mapping[str, Any],
|
13
|
+
path: Optional[List[str]] = None,
|
14
|
+
allow_same_value_merge: bool = False,
|
15
|
+
) -> None:
|
16
|
+
"""
|
17
|
+
Recursively merge two dictionaries, raising an error if there are any conflicts.
|
18
|
+
For body_json requests (allow_same_value_merge=True), a conflict occurs only when the same path has different values.
|
19
|
+
For other request types (allow_same_value_merge=False), any duplicate key is a conflict, regardless of value.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
target: The dictionary to merge into
|
23
|
+
source: The dictionary to merge from
|
24
|
+
path: The current path in the nested structure (for error messages)
|
25
|
+
allow_same_value_merge: Whether to allow merging the same value into the same key. Set to false by default, should only be true for body_json injections
|
26
|
+
"""
|
27
|
+
path = path or []
|
28
|
+
for key, source_value in source.items():
|
29
|
+
current_path = path + [str(key)]
|
30
|
+
|
31
|
+
if key in target:
|
32
|
+
target_value = target[key]
|
33
|
+
if isinstance(target_value, dict) and isinstance(source_value, dict):
|
34
|
+
# Only body_json supports nested_structures
|
35
|
+
if not allow_same_value_merge:
|
36
|
+
raise ValueError(f"Duplicate keys found: {'.'.join(current_path)}")
|
37
|
+
# If both are dictionaries, recursively merge them
|
38
|
+
_merge_mappings(target_value, source_value, current_path, allow_same_value_merge)
|
39
|
+
|
40
|
+
elif not allow_same_value_merge or target_value != source_value:
|
41
|
+
# If same key has different values, that's a conflict
|
42
|
+
raise ValueError(f"Duplicate keys found: {'.'.join(current_path)}")
|
43
|
+
else:
|
44
|
+
# No conflict, just copy the value (using deepcopy for nested structures)
|
45
|
+
target[key] = copy.deepcopy(source_value)
|
7
46
|
|
8
47
|
|
9
48
|
def combine_mappings(
|
10
49
|
mappings: List[Optional[Union[Mapping[str, Any], str]]],
|
50
|
+
allow_same_value_merge: bool = False,
|
11
51
|
) -> Union[Mapping[str, Any], str]:
|
12
52
|
"""
|
13
|
-
Combine multiple mappings into a single mapping.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
53
|
+
Combine multiple mappings into a single mapping.
|
54
|
+
|
55
|
+
For body_json requests (allow_same_value_merge=True):
|
56
|
+
- Supports nested structures (e.g., {"data": {"user": {"id": 1}}})
|
57
|
+
- Allows duplicate keys if their values match
|
58
|
+
- Raises error if same path has different values
|
59
|
+
|
60
|
+
For other request types (allow_same_value_merge=False):
|
61
|
+
- Only supports flat structures
|
62
|
+
- Any duplicate key raises an error, regardless of value
|
63
|
+
|
64
|
+
Args:
|
65
|
+
mappings: List of mappings to combine
|
66
|
+
allow_same_value_merge: Whether to allow duplicate keys with matching values.
|
67
|
+
Should only be True for body_json requests.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
A single mapping combining all inputs, or a string if there is exactly one
|
71
|
+
string mapping and no other non-empty mappings.
|
72
|
+
|
73
|
+
Raises:
|
74
|
+
ValueError: If there are:
|
75
|
+
- Multiple string mappings
|
76
|
+
- Both a string mapping and non-empty dictionary mappings
|
77
|
+
- Conflicting keys/paths based on allow_same_value_merge setting
|
18
78
|
"""
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
all_keys.append(keys)
|
25
|
-
|
26
|
-
string_options = sum(isinstance(mapping, str) for mapping in mappings)
|
27
|
-
# If more than one mapping is a string, raise a ValueError
|
79
|
+
if not mappings:
|
80
|
+
return {}
|
81
|
+
|
82
|
+
# Count how many string options we have, ignoring None values
|
83
|
+
string_options = sum(isinstance(mapping, str) for mapping in mappings if mapping is not None)
|
28
84
|
if string_options > 1:
|
29
85
|
raise ValueError("Cannot combine multiple string options")
|
30
86
|
|
31
|
-
|
32
|
-
|
87
|
+
# Filter out None values and empty mappings
|
88
|
+
non_empty_mappings = [
|
89
|
+
m for m in mappings if m is not None and not (isinstance(m, Mapping) and not m)
|
90
|
+
]
|
33
91
|
|
34
|
-
# If
|
35
|
-
|
36
|
-
if
|
37
|
-
|
92
|
+
# If there is only one string option and no other non-empty mappings, return it
|
93
|
+
if string_options == 1:
|
94
|
+
if len(non_empty_mappings) > 1:
|
95
|
+
raise ValueError("Cannot combine multiple options if one is a string")
|
96
|
+
return next(m for m in non_empty_mappings if isinstance(m, str))
|
38
97
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
98
|
+
# Start with an empty result and merge each mapping into it
|
99
|
+
result: Dict[str, Any] = {}
|
100
|
+
for mapping in non_empty_mappings:
|
101
|
+
if mapping and isinstance(mapping, Mapping):
|
102
|
+
_merge_mappings(result, mapping, allow_same_value_merge=allow_same_value_merge)
|
43
103
|
|
44
|
-
|
45
|
-
return {key: value for mapping in mappings if mapping for key, value in mapping.items()} # type: ignore # mapping can't be string here
|
104
|
+
return result
|
@@ -55,7 +55,7 @@ airbyte_cdk/sources/declarative/auth/declarative_authenticator.py,sha256=nf-OmRU
|
|
55
55
|
airbyte_cdk/sources/declarative/auth/jwt.py,sha256=SICqNsN2Cn_EgKadIgWuZpQxuMHyzrMZD_2-Uwy10rY,8539
|
56
56
|
airbyte_cdk/sources/declarative/auth/oauth.py,sha256=fibXa-dqtM54jIUscWbz7DEA5uY6F2o1LfARjEeGRy0,13926
|
57
57
|
airbyte_cdk/sources/declarative/auth/selective_authenticator.py,sha256=qGwC6YsCldr1bIeKG6Qo-A9a5cTdHw-vcOn3OtQrS4c,1540
|
58
|
-
airbyte_cdk/sources/declarative/auth/token.py,sha256=
|
58
|
+
airbyte_cdk/sources/declarative/auth/token.py,sha256=2EnE78EhBOY9hbeZnQJ9AuFaM-G7dccU-oKo_LThRQk,11070
|
59
59
|
airbyte_cdk/sources/declarative/auth/token_provider.py,sha256=9CuSsmOoHkvlc4k-oZ3Jx5luAgfTMm1I_5HOZxw7wMU,3075
|
60
60
|
airbyte_cdk/sources/declarative/checks/__init__.py,sha256=nsVV5Bo0E_tBNd8A4Xdsdb-75PpcLo5RQu2RQ_Gv-ME,806
|
61
61
|
airbyte_cdk/sources/declarative/checks/check_dynamic_stream.py,sha256=HUktywjI8pqOeED08UGqponUSwxs2TOAECTowlWlrRE,2138
|
@@ -63,11 +63,11 @@ airbyte_cdk/sources/declarative/checks/check_stream.py,sha256=dAA-UhmMj0WLXCkRQr
|
|
63
63
|
airbyte_cdk/sources/declarative/checks/connection_checker.py,sha256=MBRJo6WJlZQHpIfOGaNOkkHUmgUl_4wDM6VPo41z5Ss,1383
|
64
64
|
airbyte_cdk/sources/declarative/concurrency_level/__init__.py,sha256=5XUqrmlstYlMM0j6crktlKQwALek0uiz2D3WdM46MyA,191
|
65
65
|
airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py,sha256=YIwCTCpOr_QSNW4ltQK0yUGWInI8PKNY216HOOegYLk,2101
|
66
|
-
airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=
|
66
|
+
airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=7uqf_zQd2T08AYdMDJ80Zt0W1QHqZd-dvltXC-3g8W4,28136
|
67
67
|
airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=l9LG7Qm6e5r_qgqfVKnx3mXYtg1I9MmMjomVIPfU4XA,177
|
68
68
|
airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=SX9JjdesN1edN2WVUVMzU_ptqp2QB1OnsnjZ4mwcX7w,2579
|
69
69
|
airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
|
70
|
-
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=
|
70
|
+
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=51R-WLE1Xhrk57DoiHFxWZSP8V9HtCEi1UE8_KtEOuM,140375
|
71
71
|
airbyte_cdk/sources/declarative/declarative_source.py,sha256=nF7wBqFd3AQmEKAm4CnIo29CJoQL562cJGSCeL8U8bA,1531
|
72
72
|
airbyte_cdk/sources/declarative/declarative_stream.py,sha256=venZjfpvtqr3oFSuvMBWtn4h9ayLhD4L65ACuXCDZ64,10445
|
73
73
|
airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=KSpQetKGqPCv-38QgcVJ5kzM5nzbFldTSsYDCS3Xf0Y,1035
|
@@ -89,7 +89,7 @@ airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py,sha256=
|
|
89
89
|
airbyte_cdk/sources/declarative/extractors/type_transformer.py,sha256=d6Y2Rfg8pMVEEnHllfVksWZdNVOU55yk34O03dP9muY,1626
|
90
90
|
airbyte_cdk/sources/declarative/incremental/__init__.py,sha256=U1oZKtBaEC6IACmvziY9Wzg7Z8EgF4ZuR7NwvjlB_Sk,1255
|
91
91
|
airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py,sha256=5dbO47TFmC5Oz8TZ8DKXwXeZElz70xy2v2HJlZr5qVs,17751
|
92
|
-
airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py,sha256=
|
92
|
+
airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py,sha256=5Bl_2EeA4as0e3J23Yxp8Q8BXzh0nJ2NcGSgj3V0h2o,21954
|
93
93
|
airbyte_cdk/sources/declarative/incremental/declarative_cursor.py,sha256=5Bhw9VRPyIuCaD0wmmq_L3DZsa-rJgtKSEUzSd8YYD0,536
|
94
94
|
airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py,sha256=9HO-QbL9akvjq2NP7l498RwLA4iQZlBMQW1tZbt34I8,15943
|
95
95
|
airbyte_cdk/sources/declarative/incremental/per_partition_cursor.py,sha256=9IAJTCiRUXvhFFz-IhZtYh_KfAjLHqthsYf2jErQRls,17728
|
@@ -109,20 +109,20 @@ airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW
|
|
109
109
|
airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
|
110
110
|
airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
|
111
111
|
airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
|
112
|
-
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=
|
112
|
+
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=7qzq5ZV3V90uYRMa_-CGTbJ7aVv5jyPqGGjpJb9zdHk,98706
|
113
113
|
airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
|
114
114
|
airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=958MMX6_ZOJUlDDdNr9Krosgi2bCKGx2Z765M2Woz18,5505
|
115
115
|
airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
|
116
116
|
airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=CXwTfD3wSQq3okcqwigpprbHhSURUokh4GK2OmOyKC8,9132
|
117
117
|
airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
|
118
|
-
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=
|
118
|
+
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=_BXGXZ6RP3m9KYk3NxhBQgYzrqAwud1gWTie204dUhY,128424
|
119
119
|
airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=HJ-Syp3p7RpyR_OK0X_a2kSyISfu3W-PKrRI16iY0a8,957
|
120
120
|
airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
|
121
121
|
airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
|
122
|
-
airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py,sha256=
|
122
|
+
airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py,sha256=tmGGpMoOBmaMfhVZq53AEWxoHm2lmNVi6hA2_IVEnAA,4882
|
123
123
|
airbyte_cdk/sources/declarative/partition_routers/partition_router.py,sha256=YyEIzdmLd1FjbVP3QbQ2VFCLW_P-OGbVh6VpZShp54k,2218
|
124
124
|
airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py,sha256=SKzKjSyfccq4dxGIh-J6ejrgkCHzaiTIazmbmeQiRD4,1942
|
125
|
-
airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py,sha256=
|
125
|
+
airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py,sha256=sqNF8hPdDn7EUCB2-Y-8xtZFPO1ncVNrCsdPljdczJ8,16575
|
126
126
|
airbyte_cdk/sources/declarative/requesters/README.md,sha256=eL1I4iLkxaw7hJi9S9d18_XcRl-R8lUSjqBVJJzvXmg,2656
|
127
127
|
airbyte_cdk/sources/declarative/requesters/__init__.py,sha256=d7a3OoHbqaJDyyPli3nqqJ2yAW_SLX6XDaBAKOwvpxw,364
|
128
128
|
airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py,sha256=SkEDcJxlT1683rNx93K9whoS0OyUukkuOfToGtgpF58,776
|
@@ -139,9 +139,9 @@ airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_
|
|
139
139
|
airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py,sha256=Tan66odx8VHzfdyyXMQkXz2pJYksllGqvxmpoajgcK4,669
|
140
140
|
airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py,sha256=E-fQbt4ShfxZVoqfnmOx69C6FUPWZz8BIqI3DN9Kcjs,7935
|
141
141
|
airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=3GtOefPH08evlSUxaILkiKLTHbIspFY4qd5B3ZqNE60,10063
|
142
|
-
airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=
|
142
|
+
airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=C6YT7t4UZMfarFeQ9fc362R5TbQ2jNSew8ESP-9yuZQ,14851
|
143
143
|
airbyte_cdk/sources/declarative/requesters/paginators/__init__.py,sha256=uArbKs9JKNCt7t9tZoeWwjDpyI1HoPp29FNW0JzvaEM,644
|
144
|
-
airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=
|
144
|
+
airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=dSm_pKGOZjzvg-X_Vif-MjrnlUG23fCa69bocq8dVIs,11693
|
145
145
|
airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py,sha256=j6j9QRPaTbKQ2N661RFVKthhkWiodEp6ut0tKeEd0Ng,2019
|
146
146
|
airbyte_cdk/sources/declarative/requesters/paginators/paginator.py,sha256=OlN-y0PEOMzlUNUh3pzonoTpIJpGwkP4ibFengvpLVU,2230
|
147
147
|
airbyte_cdk/sources/declarative/requesters/paginators/strategies/__init__.py,sha256=2gly8fuZpDNwtu1Qg6oE2jBLGqQRdzSLJdnpk_iDV6I,767
|
@@ -150,9 +150,9 @@ airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_incremen
|
|
150
150
|
airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py,sha256=Z2i6a-oKMmOTxHxsTVSnyaShkJ3u8xZw1xIJdx2yxss,2731
|
151
151
|
airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py,sha256=ZBshGQNr5Bb_V8dqnWRISqdXFcjm1CKIXnlfbRhNl8g,1308
|
152
152
|
airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py,sha256=LoKXdUbSgHEtSwtA8DFrnX6SpQbRVVwreY8NguTKTcI,2229
|
153
|
-
airbyte_cdk/sources/declarative/requesters/request_option.py,sha256=
|
153
|
+
airbyte_cdk/sources/declarative/requesters/request_option.py,sha256=Bl0gxGWudmwT3FXBozTN00WYle2jd6ry_S1YylCnwqM,4825
|
154
154
|
airbyte_cdk/sources/declarative/requesters/request_options/__init__.py,sha256=WCwpKqM4wKqy-DHJaCHbKAlFqRVOqMi9K5qonxIfi_Y,809
|
155
|
-
airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py,sha256=
|
155
|
+
airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py,sha256=31nG6_0igidJFQon37-WeQkTpG3g2A5ZmlluI3ilZdE,3632
|
156
156
|
airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py,sha256=SRROdPJZ5kuqHLOlkh115pWP9nDGfDxRYPgH9oD3hPo,1798
|
157
157
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py,sha256=UW4cAtzkQ261AyLI1cmCL2WLdI3ZDYGUTmrqKB9W3u8,2422
|
158
158
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py,sha256=Vr2-qa8iHC0vJ4cCtPl7lAUlhrnl4lUuPLMSFrzxMIg,3024
|
@@ -167,7 +167,7 @@ airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py,sha256=Aio
|
|
167
167
|
airbyte_cdk/sources/declarative/retrievers/__init__.py,sha256=ix9m1dkR69DcXCXUKC5RK_ZZM7ojTLBQ4IkWQTfmfCk,456
|
168
168
|
airbyte_cdk/sources/declarative/retrievers/async_retriever.py,sha256=2oQn_vo7uJKp4pdMnsF5CG5Iwc9rkPeEOLoAm_9bcus,3222
|
169
169
|
airbyte_cdk/sources/declarative/retrievers/retriever.py,sha256=XPLs593Xv8c5cKMc37XzUAYmzlXd1a7eSsspM-CMuWA,1696
|
170
|
-
airbyte_cdk/sources/declarative/retrievers/simple_retriever.py,sha256=
|
170
|
+
airbyte_cdk/sources/declarative/retrievers/simple_retriever.py,sha256=uvsBqSUimi85YfSjPuOUoAlewwtvaYwgsLg2EDcswLE,24665
|
171
171
|
airbyte_cdk/sources/declarative/schema/__init__.py,sha256=xU45UvM5O4c1PSM13UHpCdh5hpW3HXy9vRRGEiAC1rg,795
|
172
172
|
airbyte_cdk/sources/declarative/schema/default_schema_loader.py,sha256=KTACrIE23a83wsm3Rd9Eb4K6-20lrGqYxTHNp9yxsso,1820
|
173
173
|
airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py,sha256=J8Q_iJYhcSQLWyt0bTZCbDAGpxt9G8FCc6Q9jtGsNzw,10703
|
@@ -342,7 +342,7 @@ airbyte_cdk/utils/datetime_format_inferrer.py,sha256=Ne2cpk7Tx3eZDEW2Q3O7jnNOY9g
|
|
342
342
|
airbyte_cdk/utils/datetime_helpers.py,sha256=8mqzZ67Or2PBp7tLtrhh6XFv4wFzYsjCL_DOQJRaftI,17751
|
343
343
|
airbyte_cdk/utils/event_timing.py,sha256=aiuFmPU80buLlNdKq4fDTEqqhEIelHPF6AalFGwY8as,2557
|
344
344
|
airbyte_cdk/utils/is_cloud_environment.py,sha256=DayV32Irh-SdnJ0MnjvstwCJ66_l5oEsd8l85rZtHoc,574
|
345
|
-
airbyte_cdk/utils/mapping_helpers.py,sha256=
|
345
|
+
airbyte_cdk/utils/mapping_helpers.py,sha256=4EOyUzNAGkq-M0QF5rPeBfT4v_eV7qBrEaAtsTH1k8Y,4309
|
346
346
|
airbyte_cdk/utils/message_utils.py,sha256=OTzbkwN7AdMDA3iKYq1LKwfPFxpyEDfdgEF9BED3dkU,1366
|
347
347
|
airbyte_cdk/utils/oneof_option_config.py,sha256=N8EmWdYdwt0FM7fuShh6H8nj_r4KEL9tb2DJJtwsPow,1180
|
348
348
|
airbyte_cdk/utils/print_buffer.py,sha256=PhMOi0C4Z91kWKrSvCQXcp8qRh1uCimpIdvrg6voZIA,2810
|
@@ -351,9 +351,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
|
|
351
351
|
airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
|
352
352
|
airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
|
353
353
|
airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
|
354
|
-
airbyte_cdk-6.
|
355
|
-
airbyte_cdk-6.
|
356
|
-
airbyte_cdk-6.
|
357
|
-
airbyte_cdk-6.
|
358
|
-
airbyte_cdk-6.
|
359
|
-
airbyte_cdk-6.
|
354
|
+
airbyte_cdk-6.33.0.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
|
355
|
+
airbyte_cdk-6.33.0.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
|
356
|
+
airbyte_cdk-6.33.0.dist-info/METADATA,sha256=zem-s1VWtFeGuvTO6ohvvi687MVXqmQ_QrcRWM6KnAM,6010
|
357
|
+
airbyte_cdk-6.33.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
358
|
+
airbyte_cdk-6.33.0.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
|
359
|
+
airbyte_cdk-6.33.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|