airbyte-cdk 6.13.1.dev4109__py3-none-any.whl → 6.14.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/entrypoint.py +1 -13
- airbyte_cdk/sources/declarative/auth/oauth.py +0 -26
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +51 -24
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +20 -128
- airbyte_cdk/sources/declarative/extractors/__init__.py +0 -2
- airbyte_cdk/sources/declarative/extractors/record_selector.py +7 -5
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +11 -97
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +14 -71
- airbyte_cdk/sources/declarative/requesters/http_job_repository.py +4 -33
- airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +35 -52
- airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py +7 -10
- airbyte_cdk/sources/declarative/requesters/paginators/paginator.py +4 -9
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py +6 -11
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py +13 -13
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py +13 -14
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py +7 -6
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py +10 -10
- airbyte_cdk/sources/declarative/retrievers/async_retriever.py +4 -1
- airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +64 -71
- airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +4 -4
- airbyte_cdk/sources/declarative/transformations/flatten_fields.py +1 -3
- airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py +0 -11
- airbyte_cdk/sources/file_based/exceptions.py +0 -34
- airbyte_cdk/sources/file_based/file_based_source.py +5 -28
- airbyte_cdk/sources/file_based/file_based_stream_reader.py +4 -18
- airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +2 -25
- airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +2 -30
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +4 -20
- airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +4 -34
- airbyte_cdk/sources/types.py +0 -3
- {airbyte_cdk-6.13.1.dev4109.dist-info → airbyte_cdk-6.14.0.dist-info}/METADATA +2 -2
- {airbyte_cdk-6.13.1.dev4109.dist-info → airbyte_cdk-6.14.0.dist-info}/RECORD +35 -38
- {airbyte_cdk-6.13.1.dev4109.dist-info → airbyte_cdk-6.14.0.dist-info}/WHEEL +1 -1
- airbyte_cdk/sources/declarative/extractors/type_transformer.py +0 -55
- airbyte_cdk/sources/declarative/requesters/README.md +0 -57
- airbyte_cdk/sources/declarative/transformations/keys_replace_transformation.py +0 -61
- {airbyte_cdk-6.13.1.dev4109.dist-info → airbyte_cdk-6.14.0.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.13.1.dev4109.dist-info → airbyte_cdk-6.14.0.dist-info}/entry_points.txt +0 -0
airbyte_cdk/entrypoint.py
CHANGED
@@ -5,7 +5,6 @@
|
|
5
5
|
import argparse
|
6
6
|
import importlib
|
7
7
|
import ipaddress
|
8
|
-
import json
|
9
8
|
import logging
|
10
9
|
import os.path
|
11
10
|
import socket
|
@@ -47,7 +46,6 @@ logger = init_logger("airbyte")
|
|
47
46
|
|
48
47
|
VALID_URL_SCHEMES = ["https"]
|
49
48
|
CLOUD_DEPLOYMENT_MODE = "cloud"
|
50
|
-
_HAS_LOGGED_FOR_SERIALIZATION_ERROR = False
|
51
49
|
|
52
50
|
|
53
51
|
class AirbyteEntrypoint(object):
|
@@ -293,17 +291,7 @@ class AirbyteEntrypoint(object):
|
|
293
291
|
|
294
292
|
@staticmethod
|
295
293
|
def airbyte_message_to_string(airbyte_message: AirbyteMessage) -> str:
|
296
|
-
|
297
|
-
serialized_message = AirbyteMessageSerializer.dump(airbyte_message)
|
298
|
-
try:
|
299
|
-
return orjson.dumps(serialized_message).decode()
|
300
|
-
except Exception as exception:
|
301
|
-
if not _HAS_LOGGED_FOR_SERIALIZATION_ERROR:
|
302
|
-
logger.warning(
|
303
|
-
f"There was an error during the serialization of an AirbyteMessage: `{exception}`. This might impact the sync performances."
|
304
|
-
)
|
305
|
-
_HAS_LOGGED_FOR_SERIALIZATION_ERROR = True
|
306
|
-
return json.dumps(serialized_message)
|
294
|
+
return orjson.dumps(AirbyteMessageSerializer.dump(airbyte_message)).decode()
|
307
295
|
|
308
296
|
@classmethod
|
309
297
|
def extract_state(cls, args: List[str]) -> Optional[Any]:
|
@@ -56,12 +56,8 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
56
56
|
token_expiry_is_time_of_expiration: bool = False
|
57
57
|
access_token_name: Union[InterpolatedString, str] = "access_token"
|
58
58
|
access_token_value: Optional[Union[InterpolatedString, str]] = None
|
59
|
-
client_id_name: Union[InterpolatedString, str] = "client_id"
|
60
|
-
client_secret_name: Union[InterpolatedString, str] = "client_secret"
|
61
59
|
expires_in_name: Union[InterpolatedString, str] = "expires_in"
|
62
|
-
refresh_token_name: Union[InterpolatedString, str] = "refresh_token"
|
63
60
|
refresh_request_body: Optional[Mapping[str, Any]] = None
|
64
|
-
grant_type_name: Union[InterpolatedString, str] = "grant_type"
|
65
61
|
grant_type: Union[InterpolatedString, str] = "refresh_token"
|
66
62
|
message_repository: MessageRepository = NoopMessageRepository()
|
67
63
|
|
@@ -73,15 +69,8 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
73
69
|
)
|
74
70
|
else:
|
75
71
|
self._token_refresh_endpoint = None
|
76
|
-
self._client_id_name = InterpolatedString.create(self.client_id_name, parameters=parameters)
|
77
72
|
self._client_id = InterpolatedString.create(self.client_id, parameters=parameters)
|
78
|
-
self._client_secret_name = InterpolatedString.create(
|
79
|
-
self.client_secret_name, parameters=parameters
|
80
|
-
)
|
81
73
|
self._client_secret = InterpolatedString.create(self.client_secret, parameters=parameters)
|
82
|
-
self._refresh_token_name = InterpolatedString.create(
|
83
|
-
self.refresh_token_name, parameters=parameters
|
84
|
-
)
|
85
74
|
if self.refresh_token is not None:
|
86
75
|
self._refresh_token: Optional[InterpolatedString] = InterpolatedString.create(
|
87
76
|
self.refresh_token, parameters=parameters
|
@@ -94,9 +83,6 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
94
83
|
self.expires_in_name = InterpolatedString.create(
|
95
84
|
self.expires_in_name, parameters=parameters
|
96
85
|
)
|
97
|
-
self.grant_type_name = InterpolatedString.create(
|
98
|
-
self.grant_type_name, parameters=parameters
|
99
|
-
)
|
100
86
|
self.grant_type = InterpolatedString.create(self.grant_type, parameters=parameters)
|
101
87
|
self._refresh_request_body = InterpolatedMapping(
|
102
88
|
self.refresh_request_body or {}, parameters=parameters
|
@@ -136,27 +122,18 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
136
122
|
return refresh_token_endpoint
|
137
123
|
return None
|
138
124
|
|
139
|
-
def get_client_id_name(self) -> str:
|
140
|
-
return self._client_id_name.eval(self.config) # type: ignore # eval returns a string in this context
|
141
|
-
|
142
125
|
def get_client_id(self) -> str:
|
143
126
|
client_id: str = self._client_id.eval(self.config)
|
144
127
|
if not client_id:
|
145
128
|
raise ValueError("OAuthAuthenticator was unable to evaluate client_id parameter")
|
146
129
|
return client_id
|
147
130
|
|
148
|
-
def get_client_secret_name(self) -> str:
|
149
|
-
return self._client_secret_name.eval(self.config) # type: ignore # eval returns a string in this context
|
150
|
-
|
151
131
|
def get_client_secret(self) -> str:
|
152
132
|
client_secret: str = self._client_secret.eval(self.config)
|
153
133
|
if not client_secret:
|
154
134
|
raise ValueError("OAuthAuthenticator was unable to evaluate client_secret parameter")
|
155
135
|
return client_secret
|
156
136
|
|
157
|
-
def get_refresh_token_name(self) -> str:
|
158
|
-
return self._refresh_token_name.eval(self.config) # type: ignore # eval returns a string in this context
|
159
|
-
|
160
137
|
def get_refresh_token(self) -> Optional[str]:
|
161
138
|
return None if self._refresh_token is None else str(self._refresh_token.eval(self.config))
|
162
139
|
|
@@ -169,9 +146,6 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
169
146
|
def get_expires_in_name(self) -> str:
|
170
147
|
return self.expires_in_name.eval(self.config) # type: ignore # eval returns a string in this context
|
171
148
|
|
172
|
-
def get_grant_type_name(self) -> str:
|
173
|
-
return self.grant_type_name.eval(self.config) # type: ignore # eval returns a string in this context
|
174
|
-
|
175
149
|
def get_grant_type(self) -> str:
|
176
150
|
return self.grant_type.eval(self.config) # type: ignore # eval returns a string in this context
|
177
151
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Any, Generic, Iterator, List, Mapping, Optional, Tuple
|
6
|
+
from typing import Any, Callable, Generic, Iterator, List, Mapping, Optional, Tuple, Union
|
7
7
|
|
8
8
|
from airbyte_cdk.models import (
|
9
9
|
AirbyteCatalog,
|
@@ -28,11 +28,15 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import
|
|
28
28
|
from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
|
29
29
|
DatetimeBasedCursor as DatetimeBasedCursorModel,
|
30
30
|
)
|
31
|
+
from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
|
32
|
+
DeclarativeStream as DeclarativeStreamModel,
|
33
|
+
)
|
31
34
|
from airbyte_cdk.sources.declarative.parsers.model_to_component_factory import (
|
35
|
+
ComponentDefinition,
|
32
36
|
ModelToComponentFactory,
|
33
37
|
)
|
34
38
|
from airbyte_cdk.sources.declarative.requesters import HttpRequester
|
35
|
-
from airbyte_cdk.sources.declarative.retrievers import SimpleRetriever
|
39
|
+
from airbyte_cdk.sources.declarative.retrievers import Retriever, SimpleRetriever
|
36
40
|
from airbyte_cdk.sources.declarative.stream_slicers.declarative_partition_generator import (
|
37
41
|
DeclarativePartitionFactory,
|
38
42
|
StreamSlicerPartitionGenerator,
|
@@ -48,6 +52,7 @@ from airbyte_cdk.sources.streams.concurrent.availability_strategy import (
|
|
48
52
|
from airbyte_cdk.sources.streams.concurrent.cursor import FinalStateCursor
|
49
53
|
from airbyte_cdk.sources.streams.concurrent.default_stream import DefaultStream
|
50
54
|
from airbyte_cdk.sources.streams.concurrent.helpers import get_primary_key_from_stream
|
55
|
+
from airbyte_cdk.sources.types import Config, StreamState
|
51
56
|
|
52
57
|
|
53
58
|
class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
@@ -189,11 +194,10 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
|
189
194
|
# Some low-code sources use a combination of DeclarativeStream and regular Python streams. We can't inspect
|
190
195
|
# these legacy Python streams the way we do low-code streams to determine if they are concurrent compatible,
|
191
196
|
# so we need to treat them as synchronous
|
192
|
-
if
|
193
|
-
|
197
|
+
if (
|
198
|
+
isinstance(declarative_stream, DeclarativeStream)
|
199
|
+
and name_to_stream_mapping[declarative_stream.name]["retriever"]["type"]
|
194
200
|
== "SimpleRetriever"
|
195
|
-
or name_to_stream_mapping[declarative_stream.name]["retriever"]["type"]
|
196
|
-
== "AsyncRetriever"
|
197
201
|
):
|
198
202
|
incremental_sync_component_definition = name_to_stream_mapping[
|
199
203
|
declarative_stream.name
|
@@ -230,27 +234,15 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
|
230
234
|
stream_state=stream_state,
|
231
235
|
)
|
232
236
|
|
233
|
-
retriever = declarative_stream.retriever
|
234
|
-
|
235
|
-
# This is an optimization so that we don't invoke any cursor or state management flows within the
|
236
|
-
# low-code framework because state management is handled through the ConcurrentCursor.
|
237
|
-
if declarative_stream and isinstance(retriever, SimpleRetriever):
|
238
|
-
# Also a temporary hack. In the legacy Stream implementation, as part of the read,
|
239
|
-
# set_initial_state() is called to instantiate incoming state on the cursor. Although we no
|
240
|
-
# longer rely on the legacy low-code cursor for concurrent checkpointing, low-code components
|
241
|
-
# like StopConditionPaginationStrategyDecorator and ClientSideIncrementalRecordFilterDecorator
|
242
|
-
# still rely on a DatetimeBasedCursor that is properly initialized with state.
|
243
|
-
if retriever.cursor:
|
244
|
-
retriever.cursor.set_initial_state(stream_state=stream_state)
|
245
|
-
# We zero it out here, but since this is a cursor reference, the state is still properly
|
246
|
-
# instantiated for the other components that reference it
|
247
|
-
retriever.cursor = None
|
248
|
-
|
249
237
|
partition_generator = StreamSlicerPartitionGenerator(
|
250
238
|
DeclarativePartitionFactory(
|
251
239
|
declarative_stream.name,
|
252
240
|
declarative_stream.get_json_schema(),
|
253
|
-
|
241
|
+
self._retriever_factory(
|
242
|
+
name_to_stream_mapping[declarative_stream.name],
|
243
|
+
config,
|
244
|
+
stream_state,
|
245
|
+
),
|
254
246
|
self.message_repository,
|
255
247
|
),
|
256
248
|
cursor,
|
@@ -280,7 +272,11 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
|
280
272
|
DeclarativePartitionFactory(
|
281
273
|
declarative_stream.name,
|
282
274
|
declarative_stream.get_json_schema(),
|
283
|
-
|
275
|
+
self._retriever_factory(
|
276
|
+
name_to_stream_mapping[declarative_stream.name],
|
277
|
+
config,
|
278
|
+
{},
|
279
|
+
),
|
284
280
|
self.message_repository,
|
285
281
|
),
|
286
282
|
declarative_stream.retriever.stream_slicer,
|
@@ -419,3 +415,34 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
|
|
419
415
|
if stream.stream.name not in concurrent_stream_names
|
420
416
|
]
|
421
417
|
)
|
418
|
+
|
419
|
+
def _retriever_factory(
|
420
|
+
self, stream_config: ComponentDefinition, source_config: Config, stream_state: StreamState
|
421
|
+
) -> Callable[[], Retriever]:
|
422
|
+
def _factory_method() -> Retriever:
|
423
|
+
declarative_stream: DeclarativeStream = self._constructor.create_component(
|
424
|
+
DeclarativeStreamModel,
|
425
|
+
stream_config,
|
426
|
+
source_config,
|
427
|
+
emit_connector_builder_messages=self._emit_connector_builder_messages,
|
428
|
+
)
|
429
|
+
|
430
|
+
# This is an optimization so that we don't invoke any cursor or state management flows within the
|
431
|
+
# low-code framework because state management is handled through the ConcurrentCursor.
|
432
|
+
if (
|
433
|
+
declarative_stream
|
434
|
+
and declarative_stream.retriever
|
435
|
+
and isinstance(declarative_stream.retriever, SimpleRetriever)
|
436
|
+
):
|
437
|
+
# Also a temporary hack. In the legacy Stream implementation, as part of the read, set_initial_state() is
|
438
|
+
# called to instantiate incoming state on the cursor. Although we no longer rely on the legacy low-code cursor
|
439
|
+
# for concurrent checkpointing, low-code components like StopConditionPaginationStrategyDecorator and
|
440
|
+
# ClientSideIncrementalRecordFilterDecorator still rely on a DatetimeBasedCursor that is properly initialized
|
441
|
+
# with state.
|
442
|
+
if declarative_stream.retriever.cursor:
|
443
|
+
declarative_stream.retriever.cursor.set_initial_state(stream_state=stream_state)
|
444
|
+
declarative_stream.retriever.cursor = None
|
445
|
+
|
446
|
+
return declarative_stream.retriever
|
447
|
+
|
448
|
+
return _factory_method
|
@@ -667,28 +667,6 @@ definitions:
|
|
667
667
|
$parameters:
|
668
668
|
type: object
|
669
669
|
additionalProperties: true
|
670
|
-
CustomSchemaNormalization:
|
671
|
-
title: Custom Schema Normalization
|
672
|
-
description: Schema normalization component whose behavior is derived from a custom code implementation of the connector.
|
673
|
-
type: object
|
674
|
-
additionalProperties: true
|
675
|
-
required:
|
676
|
-
- type
|
677
|
-
- class_name
|
678
|
-
properties:
|
679
|
-
type:
|
680
|
-
type: string
|
681
|
-
enum: [ CustomSchemaNormalization ]
|
682
|
-
class_name:
|
683
|
-
title: Class Name
|
684
|
-
description: Fully-qualified name of the class that will be implementing the custom normalization. The format is `source_<name>.<package>.<class_name>`.
|
685
|
-
type: string
|
686
|
-
additionalProperties: true
|
687
|
-
examples:
|
688
|
-
- "source_amazon_seller_partner.components.LedgerDetailedViewReportsTypeTransformer"
|
689
|
-
$parameters:
|
690
|
-
type: object
|
691
|
-
additionalProperties: true
|
692
670
|
CustomStateMigration:
|
693
671
|
title: Custom State Migration
|
694
672
|
description: Apply a custom transformation on the input state.
|
@@ -1047,13 +1025,6 @@ definitions:
|
|
1047
1025
|
type:
|
1048
1026
|
type: string
|
1049
1027
|
enum: [OAuthAuthenticator]
|
1050
|
-
client_id_name:
|
1051
|
-
title: Client ID Property Name
|
1052
|
-
description: The name of the property to use to refresh the `access_token`.
|
1053
|
-
type: string
|
1054
|
-
default: "client_id"
|
1055
|
-
examples:
|
1056
|
-
- custom_app_id
|
1057
1028
|
client_id:
|
1058
1029
|
title: Client ID
|
1059
1030
|
description: The OAuth client ID. Fill it in the user inputs.
|
@@ -1061,13 +1032,6 @@ definitions:
|
|
1061
1032
|
examples:
|
1062
1033
|
- "{{ config['client_id }}"
|
1063
1034
|
- "{{ config['credentials']['client_id }}"
|
1064
|
-
client_secret_name:
|
1065
|
-
title: Client Secret Property Name
|
1066
|
-
description: The name of the property to use to refresh the `access_token`.
|
1067
|
-
type: string
|
1068
|
-
default: "client_secret"
|
1069
|
-
examples:
|
1070
|
-
- custom_app_secret
|
1071
1035
|
client_secret:
|
1072
1036
|
title: Client Secret
|
1073
1037
|
description: The OAuth client secret. Fill it in the user inputs.
|
@@ -1075,13 +1039,6 @@ definitions:
|
|
1075
1039
|
examples:
|
1076
1040
|
- "{{ config['client_secret }}"
|
1077
1041
|
- "{{ config['credentials']['client_secret }}"
|
1078
|
-
refresh_token_name:
|
1079
|
-
title: Refresh Token Property Name
|
1080
|
-
description: The name of the property to use to refresh the `access_token`.
|
1081
|
-
type: string
|
1082
|
-
default: "refresh_token"
|
1083
|
-
examples:
|
1084
|
-
- custom_app_refresh_value
|
1085
1042
|
refresh_token:
|
1086
1043
|
title: Refresh Token
|
1087
1044
|
description: Credential artifact used to get a new access token.
|
@@ -1115,13 +1072,6 @@ definitions:
|
|
1115
1072
|
default: "expires_in"
|
1116
1073
|
examples:
|
1117
1074
|
- expires_in
|
1118
|
-
grant_type_name:
|
1119
|
-
title: Grant Type Property Name
|
1120
|
-
description: The name of the property to use to refresh the `access_token`.
|
1121
|
-
type: string
|
1122
|
-
default: "grant_type"
|
1123
|
-
examples:
|
1124
|
-
- custom_grant_type
|
1125
1075
|
grant_type:
|
1126
1076
|
title: Grant Type
|
1127
1077
|
description: Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.
|
@@ -1291,7 +1241,6 @@ definitions:
|
|
1291
1241
|
- "$ref": "#/definitions/KeysToLower"
|
1292
1242
|
- "$ref": "#/definitions/KeysToSnakeCase"
|
1293
1243
|
- "$ref": "#/definitions/FlattenFields"
|
1294
|
-
- "$ref": "#/definitions/KeysReplace"
|
1295
1244
|
state_migrations:
|
1296
1245
|
title: State Migrations
|
1297
1246
|
description: Array of state migrations to be applied on the input state
|
@@ -1836,7 +1785,6 @@ definitions:
|
|
1836
1785
|
- "$ref": "#/definitions/KeysToLower"
|
1837
1786
|
- "$ref": "#/definitions/KeysToSnakeCase"
|
1838
1787
|
- "$ref": "#/definitions/FlattenFields"
|
1839
|
-
- "$ref": "#/definitions/KeysReplace"
|
1840
1788
|
schema_type_identifier:
|
1841
1789
|
"$ref": "#/definitions/SchemaTypeIdentifier"
|
1842
1790
|
$parameters:
|
@@ -1932,54 +1880,6 @@ definitions:
|
|
1932
1880
|
type:
|
1933
1881
|
type: string
|
1934
1882
|
enum: [FlattenFields]
|
1935
|
-
flatten_lists:
|
1936
|
-
title: Flatten Lists
|
1937
|
-
description: Whether to flatten lists or leave it as is. Default is True.
|
1938
|
-
type: boolean
|
1939
|
-
default: true
|
1940
|
-
$parameters:
|
1941
|
-
type: object
|
1942
|
-
additionalProperties: true
|
1943
|
-
KeysReplace:
|
1944
|
-
title: Keys Replace
|
1945
|
-
description: A transformation that replaces symbols in keys.
|
1946
|
-
type: object
|
1947
|
-
required:
|
1948
|
-
- type
|
1949
|
-
- old
|
1950
|
-
- new
|
1951
|
-
properties:
|
1952
|
-
type:
|
1953
|
-
type: string
|
1954
|
-
enum: [KeysReplace]
|
1955
|
-
old:
|
1956
|
-
type: string
|
1957
|
-
title: Old value
|
1958
|
-
description: Old value to replace.
|
1959
|
-
examples:
|
1960
|
-
- " "
|
1961
|
-
- "{{ record.id }}"
|
1962
|
-
- "{{ config['id'] }}"
|
1963
|
-
- "{{ stream_slice['id'] }}"
|
1964
|
-
interpolation_context:
|
1965
|
-
- config
|
1966
|
-
- record
|
1967
|
-
- stream_state
|
1968
|
-
- stream_slice
|
1969
|
-
new:
|
1970
|
-
type: string
|
1971
|
-
title: New value
|
1972
|
-
description: New value to set.
|
1973
|
-
examples:
|
1974
|
-
- "_"
|
1975
|
-
- "{{ record.id }}"
|
1976
|
-
- "{{ config['id'] }}"
|
1977
|
-
- "{{ stream_slice['id'] }}"
|
1978
|
-
interpolation_context:
|
1979
|
-
- config
|
1980
|
-
- record
|
1981
|
-
- stream_state
|
1982
|
-
- stream_slice
|
1983
1883
|
$parameters:
|
1984
1884
|
type: object
|
1985
1885
|
additionalProperties: true
|
@@ -2232,15 +2132,15 @@ definitions:
|
|
2232
2132
|
Pertains to the fields defined by the connector relating to the OAuth flow.
|
2233
2133
|
|
2234
2134
|
Interpolation capabilities:
|
2235
|
-
- The variables placeholders are declared as `{
|
2236
|
-
- The nested resolution variables like `{{
|
2135
|
+
- The variables placeholders are declared as `{my_var}`.
|
2136
|
+
- The nested resolution variables like `{{my_nested_var}}` is allowed as well.
|
2237
2137
|
|
2238
2138
|
- The allowed interpolation context is:
|
2239
|
-
+ base64Encoder - encode to `base64`, {{
|
2240
|
-
+ base64Decorer - decode from `base64` encoded string, {{
|
2241
|
-
+ urlEncoder - encode the input string to URL-like format, {
|
2242
|
-
+ urlDecorer - decode the input url-encoded string into text format, {
|
2243
|
-
+ codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{
|
2139
|
+
+ base64Encoder - encode to `base64`, {base64Encoder:{my_var_a}:{my_var_b}}
|
2140
|
+
+ base64Decorer - decode from `base64` encoded string, {base64Decoder:{my_string_variable_or_string_value}}
|
2141
|
+
+ urlEncoder - encode the input string to URL-like format, {urlEncoder:https://test.host.com/endpoint}
|
2142
|
+
+ urlDecorer - decode the input url-encoded string into text format, {urlDecoder:https%3A%2F%2Fairbyte.io}
|
2143
|
+
+ codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {codeChallengeS256:{state_value}}
|
2244
2144
|
|
2245
2145
|
Examples:
|
2246
2146
|
- The TikTok Marketing DeclarativeOAuth spec:
|
@@ -2249,12 +2149,12 @@ definitions:
|
|
2249
2149
|
"type": "object",
|
2250
2150
|
"additionalProperties": false,
|
2251
2151
|
"properties": {
|
2252
|
-
"consent_url": "https://ads.tiktok.com/marketing_api/auth?{
|
2152
|
+
"consent_url": "https://ads.tiktok.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}",
|
2253
2153
|
"access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",
|
2254
2154
|
"access_token_params": {
|
2255
|
-
"{
|
2256
|
-
"{
|
2257
|
-
"{
|
2155
|
+
"{auth_code_key}": "{{auth_code_key}}",
|
2156
|
+
"{client_id_key}": "{{client_id_key}}",
|
2157
|
+
"{client_secret_key}": "{{client_secret_key}}"
|
2258
2158
|
},
|
2259
2159
|
"access_token_headers": {
|
2260
2160
|
"Content-Type": "application/json",
|
@@ -2272,6 +2172,7 @@ definitions:
|
|
2272
2172
|
required:
|
2273
2173
|
- consent_url
|
2274
2174
|
- access_token_url
|
2175
|
+
- extract_output
|
2275
2176
|
properties:
|
2276
2177
|
consent_url:
|
2277
2178
|
title: Consent URL
|
@@ -2280,8 +2181,8 @@ definitions:
|
|
2280
2181
|
The DeclarativeOAuth Specific string URL string template to initiate the authentication.
|
2281
2182
|
The placeholders are replaced during the processing to provide neccessary values.
|
2282
2183
|
examples:
|
2283
|
-
- https://domain.host.com/marketing_api/auth?{
|
2284
|
-
- https://endpoint.host.com/oauth2/authorize?{
|
2184
|
+
- https://domain.host.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}
|
2185
|
+
- https://endpoint.host.com/oauth2/authorize?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{scope_key}={urlEncoder:{{scope_key}}}&{state_key}={{state_key}}&subdomain={subdomain}
|
2285
2186
|
scope:
|
2286
2187
|
title: Scopes
|
2287
2188
|
type: string
|
@@ -2296,7 +2197,7 @@ definitions:
|
|
2296
2197
|
The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.
|
2297
2198
|
The placeholders are replaced during the processing to provide neccessary values.
|
2298
2199
|
examples:
|
2299
|
-
- https://auth.host.com/oauth2/token?{
|
2200
|
+
- https://auth.host.com/oauth2/token?{client_id_key}={{client_id_key}}&{client_secret_key}={{client_secret_key}}&{auth_code_key}={{auth_code_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}
|
2300
2201
|
access_token_headers:
|
2301
2202
|
title: Access Token Headers
|
2302
2203
|
type: object
|
@@ -2305,7 +2206,7 @@ definitions:
|
|
2305
2206
|
The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.
|
2306
2207
|
examples:
|
2307
2208
|
- {
|
2308
|
-
"Authorization": "Basic {{
|
2209
|
+
"Authorization": "Basic {base64Encoder:{client_id}:{client_secret}}",
|
2309
2210
|
}
|
2310
2211
|
access_token_params:
|
2311
2212
|
title: Access Token Query Params (Json Encoded)
|
@@ -2316,9 +2217,9 @@ definitions:
|
|
2316
2217
|
When this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.
|
2317
2218
|
examples:
|
2318
2219
|
- {
|
2319
|
-
"{
|
2320
|
-
"{
|
2321
|
-
"{
|
2220
|
+
"{auth_code_key}": "{{auth_code_key}}",
|
2221
|
+
"{client_id_key}": "{{client_id_key}}",
|
2222
|
+
"{client_secret_key}": "{{client_secret_key}}",
|
2322
2223
|
}
|
2323
2224
|
extract_output:
|
2324
2225
|
title: Extract Output
|
@@ -2654,11 +2555,7 @@ definitions:
|
|
2654
2555
|
- "$ref": "#/definitions/CustomRecordFilter"
|
2655
2556
|
- "$ref": "#/definitions/RecordFilter"
|
2656
2557
|
schema_normalization:
|
2657
|
-
|
2658
|
-
description: Responsible for normalization according to the schema.
|
2659
|
-
anyOf:
|
2660
|
-
- "$ref": "#/definitions/SchemaNormalization"
|
2661
|
-
- "$ref": "#/definitions/CustomSchemaNormalization"
|
2558
|
+
"$ref": "#/definitions/SchemaNormalization"
|
2662
2559
|
default: None
|
2663
2560
|
$parameters:
|
2664
2561
|
type: object
|
@@ -3004,11 +2901,6 @@ definitions:
|
|
3004
2901
|
anyOf:
|
3005
2902
|
- "$ref": "#/definitions/CustomRequester"
|
3006
2903
|
- "$ref": "#/definitions/HttpRequester"
|
3007
|
-
url_requester:
|
3008
|
-
description: Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.
|
3009
|
-
anyOf:
|
3010
|
-
- "$ref": "#/definitions/CustomRequester"
|
3011
|
-
- "$ref": "#/definitions/HttpRequester"
|
3012
2904
|
download_requester:
|
3013
2905
|
description: Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.
|
3014
2906
|
anyOf:
|
@@ -9,10 +9,8 @@ from airbyte_cdk.sources.declarative.extractors.record_selector import RecordSel
|
|
9
9
|
from airbyte_cdk.sources.declarative.extractors.response_to_file_extractor import (
|
10
10
|
ResponseToFileExtractor,
|
11
11
|
)
|
12
|
-
from airbyte_cdk.sources.declarative.extractors.type_transformer import TypeTransformer
|
13
12
|
|
14
13
|
__all__ = [
|
15
|
-
"TypeTransformer",
|
16
14
|
"HttpSelector",
|
17
15
|
"DpathExtractor",
|
18
16
|
"RecordFilter",
|
@@ -10,14 +10,16 @@ import requests
|
|
10
10
|
from airbyte_cdk.sources.declarative.extractors.http_selector import HttpSelector
|
11
11
|
from airbyte_cdk.sources.declarative.extractors.record_extractor import RecordExtractor
|
12
12
|
from airbyte_cdk.sources.declarative.extractors.record_filter import RecordFilter
|
13
|
-
from airbyte_cdk.sources.declarative.extractors.type_transformer import (
|
14
|
-
TypeTransformer as DeclarativeTypeTransformer,
|
15
|
-
)
|
16
13
|
from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
|
17
14
|
from airbyte_cdk.sources.declarative.models import SchemaNormalization
|
18
15
|
from airbyte_cdk.sources.declarative.transformations import RecordTransformation
|
19
16
|
from airbyte_cdk.sources.types import Config, Record, StreamSlice, StreamState
|
20
|
-
from airbyte_cdk.sources.utils.transform import TypeTransformer
|
17
|
+
from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer
|
18
|
+
|
19
|
+
SCHEMA_TRANSFORMER_TYPE_MAPPING = {
|
20
|
+
SchemaNormalization.None_: TransformConfig.NoTransform,
|
21
|
+
SchemaNormalization.Default: TransformConfig.DefaultSchemaNormalization,
|
22
|
+
}
|
21
23
|
|
22
24
|
|
23
25
|
@dataclass
|
@@ -36,7 +38,7 @@ class RecordSelector(HttpSelector):
|
|
36
38
|
extractor: RecordExtractor
|
37
39
|
config: Config
|
38
40
|
parameters: InitVar[Mapping[str, Any]]
|
39
|
-
schema_normalization:
|
41
|
+
schema_normalization: TypeTransformer
|
40
42
|
name: str
|
41
43
|
_name: Union[InterpolatedString, str] = field(init=False, repr=False, default="")
|
42
44
|
record_filter: Optional[RecordFilter] = None
|