airbyte-cdk 6.5.3rc2__py3-none-any.whl → 6.6.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/__init__.py +17 -2
- airbyte_cdk/config_observation.py +10 -3
- airbyte_cdk/connector.py +19 -9
- airbyte_cdk/connector_builder/connector_builder_handler.py +28 -8
- airbyte_cdk/connector_builder/main.py +26 -6
- airbyte_cdk/connector_builder/message_grouper.py +95 -25
- airbyte_cdk/destinations/destination.py +47 -14
- airbyte_cdk/destinations/vector_db_based/config.py +36 -14
- airbyte_cdk/destinations/vector_db_based/document_processor.py +49 -11
- airbyte_cdk/destinations/vector_db_based/embedder.py +52 -11
- airbyte_cdk/destinations/vector_db_based/test_utils.py +14 -4
- airbyte_cdk/destinations/vector_db_based/utils.py +8 -2
- airbyte_cdk/destinations/vector_db_based/writer.py +15 -4
- airbyte_cdk/entrypoint.py +82 -26
- airbyte_cdk/exception_handler.py +13 -3
- airbyte_cdk/logger.py +10 -2
- airbyte_cdk/models/airbyte_protocol.py +11 -5
- airbyte_cdk/models/airbyte_protocol_serializers.py +9 -3
- airbyte_cdk/models/well_known_types.py +1 -1
- airbyte_cdk/sources/abstract_source.py +63 -17
- airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +47 -14
- airbyte_cdk/sources/concurrent_source/concurrent_source.py +25 -7
- airbyte_cdk/sources/concurrent_source/concurrent_source_adapter.py +27 -6
- airbyte_cdk/sources/concurrent_source/thread_pool_manager.py +9 -3
- airbyte_cdk/sources/connector_state_manager.py +32 -10
- airbyte_cdk/sources/declarative/async_job/job.py +3 -1
- airbyte_cdk/sources/declarative/async_job/job_orchestrator.py +68 -14
- airbyte_cdk/sources/declarative/async_job/job_tracker.py +24 -6
- airbyte_cdk/sources/declarative/async_job/repository.py +3 -1
- airbyte_cdk/sources/declarative/auth/declarative_authenticator.py +3 -1
- airbyte_cdk/sources/declarative/auth/jwt.py +27 -7
- airbyte_cdk/sources/declarative/auth/oauth.py +35 -11
- airbyte_cdk/sources/declarative/auth/selective_authenticator.py +3 -1
- airbyte_cdk/sources/declarative/auth/token.py +25 -8
- airbyte_cdk/sources/declarative/checks/check_stream.py +12 -4
- airbyte_cdk/sources/declarative/checks/connection_checker.py +3 -1
- airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py +11 -3
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +106 -50
- airbyte_cdk/sources/declarative/datetime/min_max_datetime.py +20 -6
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +43 -0
- airbyte_cdk/sources/declarative/declarative_source.py +3 -1
- airbyte_cdk/sources/declarative/declarative_stream.py +27 -6
- airbyte_cdk/sources/declarative/decoders/__init__.py +2 -2
- airbyte_cdk/sources/declarative/decoders/decoder.py +3 -1
- airbyte_cdk/sources/declarative/decoders/json_decoder.py +48 -13
- airbyte_cdk/sources/declarative/decoders/pagination_decoder_decorator.py +3 -1
- airbyte_cdk/sources/declarative/decoders/xml_decoder.py +6 -2
- airbyte_cdk/sources/declarative/extractors/dpath_extractor.py +6 -2
- airbyte_cdk/sources/declarative/extractors/record_filter.py +24 -7
- airbyte_cdk/sources/declarative/extractors/record_selector.py +10 -3
- airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py +15 -5
- airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +96 -31
- airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py +22 -8
- airbyte_cdk/sources/declarative/incremental/per_partition_cursor.py +46 -15
- airbyte_cdk/sources/declarative/incremental/per_partition_with_global.py +19 -5
- airbyte_cdk/sources/declarative/incremental/resumable_full_refresh_cursor.py +3 -1
- airbyte_cdk/sources/declarative/interpolation/interpolated_boolean.py +20 -2
- airbyte_cdk/sources/declarative/interpolation/interpolated_mapping.py +5 -1
- airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +10 -3
- airbyte_cdk/sources/declarative/interpolation/interpolated_string.py +6 -2
- airbyte_cdk/sources/declarative/interpolation/interpolation.py +7 -1
- airbyte_cdk/sources/declarative/interpolation/jinja.py +6 -2
- airbyte_cdk/sources/declarative/interpolation/macros.py +19 -4
- airbyte_cdk/sources/declarative/manifest_declarative_source.py +106 -24
- airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py +14 -5
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +697 -678
- airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +13 -4
- airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py +9 -2
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +802 -232
- airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py +29 -7
- airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py +25 -7
- airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py +54 -15
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py +6 -2
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/header_helper.py +3 -1
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py +17 -5
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py +15 -5
- airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py +3 -1
- airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +18 -8
- airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py +16 -7
- airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +51 -14
- airbyte_cdk/sources/declarative/requesters/http_job_repository.py +29 -8
- airbyte_cdk/sources/declarative/requesters/http_requester.py +58 -16
- airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +49 -14
- airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py +3 -1
- airbyte_cdk/sources/declarative/requesters/paginators/paginator.py +3 -1
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py +17 -5
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py +24 -7
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py +9 -3
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py +3 -1
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py +6 -2
- airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py +19 -6
- airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py +3 -1
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py +21 -7
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py +18 -6
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +27 -8
- airbyte_cdk/sources/declarative/requesters/requester.py +3 -1
- airbyte_cdk/sources/declarative/retrievers/async_retriever.py +12 -5
- airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +105 -24
- airbyte_cdk/sources/declarative/schema/default_schema_loader.py +3 -1
- airbyte_cdk/sources/declarative/spec/spec.py +8 -2
- airbyte_cdk/sources/declarative/stream_slicers/stream_slicer.py +3 -1
- airbyte_cdk/sources/declarative/transformations/add_fields.py +12 -3
- airbyte_cdk/sources/declarative/transformations/remove_fields.py +6 -2
- airbyte_cdk/sources/declarative/types.py +8 -1
- airbyte_cdk/sources/declarative/yaml_declarative_source.py +3 -1
- airbyte_cdk/sources/embedded/base_integration.py +14 -4
- airbyte_cdk/sources/embedded/catalog.py +16 -4
- airbyte_cdk/sources/embedded/runner.py +19 -3
- airbyte_cdk/sources/embedded/tools.py +3 -1
- airbyte_cdk/sources/file_based/availability_strategy/abstract_file_based_availability_strategy.py +12 -4
- airbyte_cdk/sources/file_based/availability_strategy/default_file_based_availability_strategy.py +27 -7
- airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py +12 -6
- airbyte_cdk/sources/file_based/config/csv_format.py +21 -9
- airbyte_cdk/sources/file_based/config/file_based_stream_config.py +6 -2
- airbyte_cdk/sources/file_based/config/unstructured_format.py +10 -3
- airbyte_cdk/sources/file_based/discovery_policy/abstract_discovery_policy.py +2 -4
- airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py +7 -2
- airbyte_cdk/sources/file_based/exceptions.py +13 -15
- airbyte_cdk/sources/file_based/file_based_source.py +82 -24
- airbyte_cdk/sources/file_based/file_based_stream_reader.py +16 -5
- airbyte_cdk/sources/file_based/file_types/avro_parser.py +58 -17
- airbyte_cdk/sources/file_based/file_types/csv_parser.py +89 -26
- airbyte_cdk/sources/file_based/file_types/excel_parser.py +25 -7
- airbyte_cdk/sources/file_based/file_types/file_transfer.py +8 -2
- airbyte_cdk/sources/file_based/file_types/file_type_parser.py +4 -1
- airbyte_cdk/sources/file_based/file_types/jsonl_parser.py +20 -6
- airbyte_cdk/sources/file_based/file_types/parquet_parser.py +57 -16
- airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +64 -15
- airbyte_cdk/sources/file_based/schema_helpers.py +33 -10
- airbyte_cdk/sources/file_based/schema_validation_policies/abstract_schema_validation_policy.py +3 -1
- airbyte_cdk/sources/file_based/schema_validation_policies/default_schema_validation_policies.py +16 -5
- airbyte_cdk/sources/file_based/stream/abstract_file_based_stream.py +33 -10
- airbyte_cdk/sources/file_based/stream/concurrent/adapters.py +47 -11
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/abstract_concurrent_file_based_cursor.py +13 -22
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_concurrent_cursor.py +53 -17
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_cursor.py +17 -5
- airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py +3 -1
- airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py +26 -9
- airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +67 -21
- airbyte_cdk/sources/http_logger.py +5 -1
- airbyte_cdk/sources/message/repository.py +18 -4
- airbyte_cdk/sources/source.py +17 -7
- airbyte_cdk/sources/streams/availability_strategy.py +9 -3
- airbyte_cdk/sources/streams/call_rate.py +63 -19
- airbyte_cdk/sources/streams/checkpoint/checkpoint_reader.py +31 -7
- airbyte_cdk/sources/streams/checkpoint/substream_resumable_full_refresh_cursor.py +6 -2
- airbyte_cdk/sources/streams/concurrent/adapters.py +77 -22
- airbyte_cdk/sources/streams/concurrent/cursor.py +56 -20
- airbyte_cdk/sources/streams/concurrent/default_stream.py +9 -2
- airbyte_cdk/sources/streams/concurrent/helpers.py +6 -2
- airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py +9 -2
- airbyte_cdk/sources/streams/concurrent/partition_reader.py +4 -1
- airbyte_cdk/sources/streams/concurrent/partitions/record.py +10 -2
- airbyte_cdk/sources/streams/concurrent/partitions/types.py +6 -2
- airbyte_cdk/sources/streams/concurrent/state_converters/abstract_stream_state_converter.py +25 -10
- airbyte_cdk/sources/streams/concurrent/state_converters/datetime_stream_state_converter.py +32 -16
- airbyte_cdk/sources/streams/core.py +77 -22
- airbyte_cdk/sources/streams/http/availability_strategy.py +3 -1
- airbyte_cdk/sources/streams/http/error_handlers/default_error_mapping.py +4 -1
- airbyte_cdk/sources/streams/http/error_handlers/error_handler.py +3 -1
- airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py +16 -5
- airbyte_cdk/sources/streams/http/error_handlers/response_models.py +9 -3
- airbyte_cdk/sources/streams/http/exceptions.py +2 -2
- airbyte_cdk/sources/streams/http/http.py +133 -33
- airbyte_cdk/sources/streams/http/http_client.py +91 -29
- airbyte_cdk/sources/streams/http/rate_limiting.py +23 -7
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +19 -6
- airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +38 -11
- airbyte_cdk/sources/streams/http/requests_native_auth/token.py +13 -3
- airbyte_cdk/sources/types.py +5 -1
- airbyte_cdk/sources/utils/record_helper.py +12 -3
- airbyte_cdk/sources/utils/schema_helpers.py +9 -3
- airbyte_cdk/sources/utils/slice_logger.py +4 -1
- airbyte_cdk/sources/utils/transform.py +24 -9
- airbyte_cdk/sql/exceptions.py +19 -6
- airbyte_cdk/sql/secrets.py +3 -1
- airbyte_cdk/sql/shared/catalog_providers.py +13 -4
- airbyte_cdk/sql/shared/sql_processor.py +44 -14
- airbyte_cdk/test/catalog_builder.py +19 -8
- airbyte_cdk/test/entrypoint_wrapper.py +27 -8
- airbyte_cdk/test/mock_http/mocker.py +41 -11
- airbyte_cdk/test/mock_http/request.py +9 -3
- airbyte_cdk/test/mock_http/response.py +3 -1
- airbyte_cdk/test/mock_http/response_builder.py +29 -7
- airbyte_cdk/test/state_builder.py +10 -2
- airbyte_cdk/test/utils/data.py +6 -2
- airbyte_cdk/test/utils/http_mocking.py +3 -1
- airbyte_cdk/utils/airbyte_secrets_utils.py +3 -1
- airbyte_cdk/utils/analytics_message.py +10 -2
- airbyte_cdk/utils/datetime_format_inferrer.py +4 -1
- airbyte_cdk/utils/mapping_helpers.py +3 -1
- airbyte_cdk/utils/message_utils.py +11 -4
- airbyte_cdk/utils/print_buffer.py +6 -1
- airbyte_cdk/utils/schema_inferrer.py +30 -9
- airbyte_cdk/utils/spec_schema_transformations.py +3 -1
- airbyte_cdk/utils/traced_exception.py +35 -9
- {airbyte_cdk-6.5.3rc2.dist-info → airbyte_cdk-6.6.0.dist-info}/METADATA +8 -7
- {airbyte_cdk-6.5.3rc2.dist-info → airbyte_cdk-6.6.0.dist-info}/RECORD +200 -200
- {airbyte_cdk-6.5.3rc2.dist-info → airbyte_cdk-6.6.0.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.5.3rc2.dist-info → airbyte_cdk-6.6.0.dist-info}/WHEEL +0 -0
@@ -5,7 +5,10 @@
|
|
5
5
|
from dataclasses import InitVar, dataclass, field
|
6
6
|
from typing import Any, Mapping, Optional, Union
|
7
7
|
|
8
|
-
from airbyte_cdk.sources.declarative.interpolation.interpolated_nested_mapping import
|
8
|
+
from airbyte_cdk.sources.declarative.interpolation.interpolated_nested_mapping import (
|
9
|
+
InterpolatedNestedMapping,
|
10
|
+
NestedMapping,
|
11
|
+
)
|
9
12
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
10
13
|
from airbyte_cdk.sources.types import Config, StreamSlice, StreamState
|
11
14
|
|
@@ -19,16 +22,23 @@ class InterpolatedNestedRequestInputProvider:
|
|
19
22
|
parameters: InitVar[Mapping[str, Any]]
|
20
23
|
request_inputs: Optional[Union[str, NestedMapping]] = field(default=None)
|
21
24
|
config: Config = field(default_factory=dict)
|
22
|
-
_interpolator: Optional[Union[InterpolatedString, InterpolatedNestedMapping]] = field(
|
23
|
-
|
25
|
+
_interpolator: Optional[Union[InterpolatedString, InterpolatedNestedMapping]] = field(
|
26
|
+
init=False, repr=False, default=None
|
27
|
+
)
|
28
|
+
_request_inputs: Optional[Union[str, NestedMapping]] = field(
|
29
|
+
init=False, repr=False, default=None
|
30
|
+
)
|
24
31
|
|
25
32
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
26
|
-
|
27
33
|
self._request_inputs = self.request_inputs or {}
|
28
34
|
if isinstance(self._request_inputs, str):
|
29
|
-
self._interpolator = InterpolatedString(
|
35
|
+
self._interpolator = InterpolatedString(
|
36
|
+
self._request_inputs, default="", parameters=parameters
|
37
|
+
)
|
30
38
|
else:
|
31
|
-
self._interpolator = InterpolatedNestedMapping(
|
39
|
+
self._interpolator = InterpolatedNestedMapping(
|
40
|
+
self._request_inputs, parameters=parameters
|
41
|
+
)
|
32
42
|
|
33
43
|
def eval_request_inputs(
|
34
44
|
self,
|
@@ -44,5 +54,9 @@ class InterpolatedNestedRequestInputProvider:
|
|
44
54
|
:param next_page_token: The pagination token
|
45
55
|
:return: The request inputs to set on an outgoing HTTP request
|
46
56
|
"""
|
47
|
-
kwargs = {
|
57
|
+
kwargs = {
|
58
|
+
"stream_state": stream_state,
|
59
|
+
"stream_slice": stream_slice,
|
60
|
+
"next_page_token": next_page_token,
|
61
|
+
}
|
48
62
|
return self._interpolator.eval(self.config, **kwargs) # type: ignore # self._interpolator is always initialized with a value and will not be None
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py
CHANGED
@@ -19,14 +19,19 @@ class InterpolatedRequestInputProvider:
|
|
19
19
|
parameters: InitVar[Mapping[str, Any]]
|
20
20
|
request_inputs: Optional[Union[str, Mapping[str, str]]] = field(default=None)
|
21
21
|
config: Config = field(default_factory=dict)
|
22
|
-
_interpolator: Optional[Union[InterpolatedString, InterpolatedMapping]] = field(
|
23
|
-
|
22
|
+
_interpolator: Optional[Union[InterpolatedString, InterpolatedMapping]] = field(
|
23
|
+
init=False, repr=False, default=None
|
24
|
+
)
|
25
|
+
_request_inputs: Optional[Union[str, Mapping[str, str]]] = field(
|
26
|
+
init=False, repr=False, default=None
|
27
|
+
)
|
24
28
|
|
25
29
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
26
|
-
|
27
30
|
self._request_inputs = self.request_inputs or {}
|
28
31
|
if isinstance(self._request_inputs, str):
|
29
|
-
self._interpolator = InterpolatedString(
|
32
|
+
self._interpolator = InterpolatedString(
|
33
|
+
self._request_inputs, default="", parameters=parameters
|
34
|
+
)
|
30
35
|
else:
|
31
36
|
self._interpolator = InterpolatedMapping(self._request_inputs, parameters=parameters)
|
32
37
|
|
@@ -48,9 +53,16 @@ class InterpolatedRequestInputProvider:
|
|
48
53
|
:param valid_value_types: A tuple of types that the interpolator should allow
|
49
54
|
:return: The request inputs to set on an outgoing HTTP request
|
50
55
|
"""
|
51
|
-
kwargs = {
|
56
|
+
kwargs = {
|
57
|
+
"stream_state": stream_state,
|
58
|
+
"stream_slice": stream_slice,
|
59
|
+
"next_page_token": next_page_token,
|
60
|
+
}
|
52
61
|
interpolated_value = self._interpolator.eval( # type: ignore # self._interpolator is always initialized with a value and will not be None
|
53
|
-
self.config,
|
62
|
+
self.config,
|
63
|
+
valid_key_types=valid_key_types,
|
64
|
+
valid_value_types=valid_value_types,
|
65
|
+
**kwargs,
|
54
66
|
)
|
55
67
|
|
56
68
|
if isinstance(interpolated_value, dict):
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py
CHANGED
@@ -9,8 +9,12 @@ from airbyte_cdk.sources.declarative.interpolation.interpolated_nested_mapping i
|
|
9
9
|
from airbyte_cdk.sources.declarative.requesters.request_options.interpolated_nested_request_input_provider import (
|
10
10
|
InterpolatedNestedRequestInputProvider,
|
11
11
|
)
|
12
|
-
from airbyte_cdk.sources.declarative.requesters.request_options.interpolated_request_input_provider import
|
13
|
-
|
12
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.interpolated_request_input_provider import (
|
13
|
+
InterpolatedRequestInputProvider,
|
14
|
+
)
|
15
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
16
|
+
RequestOptionsProvider,
|
17
|
+
)
|
14
18
|
from airbyte_cdk.sources.source import ExperimentalClassWarning
|
15
19
|
from airbyte_cdk.sources.types import Config, StreamSlice, StreamState
|
16
20
|
from deprecated import deprecated
|
@@ -50,7 +54,9 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
50
54
|
self.request_body_json = {}
|
51
55
|
|
52
56
|
if self.request_body_json and self.request_body_data:
|
53
|
-
raise ValueError(
|
57
|
+
raise ValueError(
|
58
|
+
"RequestOptionsProvider should only contain either 'request_body_data' or 'request_body_json' not both"
|
59
|
+
)
|
54
60
|
|
55
61
|
self._parameter_interpolator = InterpolatedRequestInputProvider(
|
56
62
|
config=self.config, request_inputs=self.request_parameters, parameters=parameters
|
@@ -73,7 +79,11 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
73
79
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
74
80
|
) -> MutableMapping[str, Any]:
|
75
81
|
interpolated_value = self._parameter_interpolator.eval_request_inputs(
|
76
|
-
stream_state,
|
82
|
+
stream_state,
|
83
|
+
stream_slice,
|
84
|
+
next_page_token,
|
85
|
+
valid_key_types=(str,),
|
86
|
+
valid_value_types=ValidRequestTypes,
|
77
87
|
)
|
78
88
|
if isinstance(interpolated_value, dict):
|
79
89
|
return interpolated_value
|
@@ -86,7 +96,9 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
86
96
|
stream_slice: Optional[StreamSlice] = None,
|
87
97
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
88
98
|
) -> Mapping[str, Any]:
|
89
|
-
return self._headers_interpolator.eval_request_inputs(
|
99
|
+
return self._headers_interpolator.eval_request_inputs(
|
100
|
+
stream_state, stream_slice, next_page_token
|
101
|
+
)
|
90
102
|
|
91
103
|
def get_request_body_data(
|
92
104
|
self,
|
@@ -110,9 +122,14 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
110
122
|
stream_slice: Optional[StreamSlice] = None,
|
111
123
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
112
124
|
) -> Mapping[str, Any]:
|
113
|
-
return self._body_json_interpolator.eval_request_inputs(
|
125
|
+
return self._body_json_interpolator.eval_request_inputs(
|
126
|
+
stream_state, stream_slice, next_page_token
|
127
|
+
)
|
114
128
|
|
115
|
-
@deprecated(
|
129
|
+
@deprecated(
|
130
|
+
"This class is temporary and used to incrementally deliver low-code to concurrent",
|
131
|
+
category=ExperimentalClassWarning,
|
132
|
+
)
|
116
133
|
def request_options_contain_stream_state(self) -> bool:
|
117
134
|
"""
|
118
135
|
Temporary helper method used as we move low-code streams to the concurrent framework. This method determines if
|
@@ -128,7 +145,9 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
128
145
|
)
|
129
146
|
|
130
147
|
@staticmethod
|
131
|
-
def _check_if_interpolation_uses_stream_state(
|
148
|
+
def _check_if_interpolation_uses_stream_state(
|
149
|
+
request_input: Optional[Union[RequestInput, NestedMapping]],
|
150
|
+
) -> bool:
|
132
151
|
if not request_input:
|
133
152
|
return False
|
134
153
|
elif isinstance(request_input, str):
|
@@ -8,7 +8,9 @@ from typing import Any, Callable, Mapping, MutableMapping, Optional, Union
|
|
8
8
|
|
9
9
|
import requests
|
10
10
|
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
|
11
|
-
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import
|
11
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
12
|
+
RequestOptionsProvider,
|
13
|
+
)
|
12
14
|
from airbyte_cdk.sources.types import StreamSlice, StreamState
|
13
15
|
|
14
16
|
|
@@ -5,7 +5,10 @@ from dataclasses import InitVar, dataclass, field
|
|
5
5
|
from typing import Any, Callable, Iterable, Mapping, Optional
|
6
6
|
|
7
7
|
from airbyte_cdk.models import FailureType
|
8
|
-
from airbyte_cdk.sources.declarative.async_job.job_orchestrator import
|
8
|
+
from airbyte_cdk.sources.declarative.async_job.job_orchestrator import (
|
9
|
+
AsyncJobOrchestrator,
|
10
|
+
AsyncPartition,
|
11
|
+
)
|
9
12
|
from airbyte_cdk.sources.declarative.extractors.record_selector import RecordSelector
|
10
13
|
from airbyte_cdk.sources.declarative.partition_routers import SinglePartitionRouter
|
11
14
|
from airbyte_cdk.sources.declarative.retrievers import Retriever
|
@@ -24,7 +27,9 @@ class AsyncRetriever(Retriever):
|
|
24
27
|
parameters: InitVar[Mapping[str, Any]]
|
25
28
|
job_orchestrator_factory: Callable[[Iterable[StreamSlice]], AsyncJobOrchestrator]
|
26
29
|
record_selector: RecordSelector
|
27
|
-
stream_slicer: StreamSlicer = field(
|
30
|
+
stream_slicer: StreamSlicer = field(
|
31
|
+
default_factory=lambda: SinglePartitionRouter(parameters={})
|
32
|
+
)
|
28
33
|
|
29
34
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
30
35
|
self._job_orchestrator_factory = self.job_orchestrator_factory
|
@@ -66,7 +71,9 @@ class AsyncRetriever(Retriever):
|
|
66
71
|
|
67
72
|
return self.state
|
68
73
|
|
69
|
-
def _validate_and_get_stream_slice_partition(
|
74
|
+
def _validate_and_get_stream_slice_partition(
|
75
|
+
self, stream_slice: Optional[StreamSlice] = None
|
76
|
+
) -> AsyncPartition:
|
70
77
|
"""
|
71
78
|
Validates the stream_slice argument and returns the partition from it.
|
72
79
|
|
@@ -93,7 +100,8 @@ class AsyncRetriever(Retriever):
|
|
93
100
|
|
94
101
|
for completed_partition in self._job_orchestrator.create_and_get_completed_partitions():
|
95
102
|
yield StreamSlice(
|
96
|
-
partition=dict(completed_partition.stream_slice.partition)
|
103
|
+
partition=dict(completed_partition.stream_slice.partition)
|
104
|
+
| {"partition": completed_partition},
|
97
105
|
cursor_slice=completed_partition.stream_slice.cursor_slice,
|
98
106
|
)
|
99
107
|
|
@@ -102,7 +110,6 @@ class AsyncRetriever(Retriever):
|
|
102
110
|
records_schema: Mapping[str, Any],
|
103
111
|
stream_slice: Optional[StreamSlice] = None,
|
104
112
|
) -> Iterable[StreamData]:
|
105
|
-
|
106
113
|
stream_state: StreamState = self._get_stream_state()
|
107
114
|
partition: AsyncPartition = self._validate_and_get_stream_slice_partition(stream_slice)
|
108
115
|
records: Iterable[Mapping[str, Any]] = self._job_orchestrator.fetch_records(partition)
|
@@ -6,7 +6,18 @@ import json
|
|
6
6
|
from dataclasses import InitVar, dataclass, field
|
7
7
|
from functools import partial
|
8
8
|
from itertools import islice
|
9
|
-
from typing import
|
9
|
+
from typing import (
|
10
|
+
Any,
|
11
|
+
Callable,
|
12
|
+
Iterable,
|
13
|
+
List,
|
14
|
+
Mapping,
|
15
|
+
MutableMapping,
|
16
|
+
Optional,
|
17
|
+
Set,
|
18
|
+
Tuple,
|
19
|
+
Union,
|
20
|
+
)
|
10
21
|
|
11
22
|
import requests
|
12
23
|
from airbyte_cdk.models import AirbyteMessage
|
@@ -14,10 +25,15 @@ from airbyte_cdk.sources.declarative.extractors.http_selector import HttpSelecto
|
|
14
25
|
from airbyte_cdk.sources.declarative.incremental import ResumableFullRefreshCursor
|
15
26
|
from airbyte_cdk.sources.declarative.incremental.declarative_cursor import DeclarativeCursor
|
16
27
|
from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
|
17
|
-
from airbyte_cdk.sources.declarative.partition_routers.single_partition_router import
|
28
|
+
from airbyte_cdk.sources.declarative.partition_routers.single_partition_router import (
|
29
|
+
SinglePartitionRouter,
|
30
|
+
)
|
18
31
|
from airbyte_cdk.sources.declarative.requesters.paginators.no_pagination import NoPagination
|
19
32
|
from airbyte_cdk.sources.declarative.requesters.paginators.paginator import Paginator
|
20
|
-
from airbyte_cdk.sources.declarative.requesters.request_options import
|
33
|
+
from airbyte_cdk.sources.declarative.requesters.request_options import (
|
34
|
+
DefaultRequestOptionsProvider,
|
35
|
+
RequestOptionsProvider,
|
36
|
+
)
|
21
37
|
from airbyte_cdk.sources.declarative.requesters.requester import Requester
|
22
38
|
from airbyte_cdk.sources.declarative.retrievers.retriever import Retriever
|
23
39
|
from airbyte_cdk.sources.declarative.stream_slicers.stream_slicer import StreamSlicer
|
@@ -62,8 +78,12 @@ class SimpleRetriever(Retriever):
|
|
62
78
|
primary_key: Optional[Union[str, List[str], List[List[str]]]]
|
63
79
|
_primary_key: str = field(init=False, repr=False, default="")
|
64
80
|
paginator: Optional[Paginator] = None
|
65
|
-
stream_slicer: StreamSlicer = field(
|
66
|
-
|
81
|
+
stream_slicer: StreamSlicer = field(
|
82
|
+
default_factory=lambda: SinglePartitionRouter(parameters={})
|
83
|
+
)
|
84
|
+
request_option_provider: RequestOptionsProvider = field(
|
85
|
+
default_factory=lambda: DefaultRequestOptionsProvider(parameters={})
|
86
|
+
)
|
67
87
|
cursor: Optional[DeclarativeCursor] = None
|
68
88
|
ignore_stream_slicer_parameters_on_paginated_requests: bool = False
|
69
89
|
|
@@ -73,7 +93,11 @@ class SimpleRetriever(Retriever):
|
|
73
93
|
self._last_page_size: int = 0
|
74
94
|
self._last_record: Optional[Record] = None
|
75
95
|
self._parameters = parameters
|
76
|
-
self._name =
|
96
|
+
self._name = (
|
97
|
+
InterpolatedString(self._name, parameters=parameters)
|
98
|
+
if isinstance(self._name, str)
|
99
|
+
else self._name
|
100
|
+
)
|
77
101
|
|
78
102
|
# This mapping is used during a resumable full refresh syncs to indicate whether a partition has started syncing
|
79
103
|
# records. Partitions serve as the key and map to True if they already began processing records
|
@@ -84,7 +108,11 @@ class SimpleRetriever(Retriever):
|
|
84
108
|
"""
|
85
109
|
:return: Stream name
|
86
110
|
"""
|
87
|
-
return
|
111
|
+
return (
|
112
|
+
str(self._name.eval(self.config))
|
113
|
+
if isinstance(self._name, InterpolatedString)
|
114
|
+
else self._name
|
115
|
+
)
|
88
116
|
|
89
117
|
@name.setter
|
90
118
|
def name(self, value: str) -> None:
|
@@ -118,10 +146,20 @@ class SimpleRetriever(Retriever):
|
|
118
146
|
"""
|
119
147
|
# FIXME we should eventually remove the usage of stream_state as part of the interpolation
|
120
148
|
mappings = [
|
121
|
-
paginator_method(
|
149
|
+
paginator_method(
|
150
|
+
stream_state=stream_state,
|
151
|
+
stream_slice=stream_slice,
|
152
|
+
next_page_token=next_page_token,
|
153
|
+
),
|
122
154
|
]
|
123
155
|
if not next_page_token or not self.ignore_stream_slicer_parameters_on_paginated_requests:
|
124
|
-
mappings.append(
|
156
|
+
mappings.append(
|
157
|
+
stream_slicer_method(
|
158
|
+
stream_state=stream_state,
|
159
|
+
stream_slice=stream_slice,
|
160
|
+
next_page_token=next_page_token,
|
161
|
+
)
|
162
|
+
)
|
125
163
|
return combine_mappings(mappings)
|
126
164
|
|
127
165
|
def _request_headers(
|
@@ -271,20 +309,35 @@ class SimpleRetriever(Retriever):
|
|
271
309
|
return self._paginator.next_page_token(response, self._last_page_size, self._last_record)
|
272
310
|
|
273
311
|
def _fetch_next_page(
|
274
|
-
self,
|
312
|
+
self,
|
313
|
+
stream_state: Mapping[str, Any],
|
314
|
+
stream_slice: StreamSlice,
|
315
|
+
next_page_token: Optional[Mapping[str, Any]] = None,
|
275
316
|
) -> Optional[requests.Response]:
|
276
317
|
return self.requester.send_request(
|
277
318
|
path=self._paginator_path(),
|
278
319
|
stream_state=stream_state,
|
279
320
|
stream_slice=stream_slice,
|
280
321
|
next_page_token=next_page_token,
|
281
|
-
request_headers=self._request_headers(
|
282
|
-
|
322
|
+
request_headers=self._request_headers(
|
323
|
+
stream_state=stream_state,
|
324
|
+
stream_slice=stream_slice,
|
325
|
+
next_page_token=next_page_token,
|
326
|
+
),
|
327
|
+
request_params=self._request_params(
|
328
|
+
stream_state=stream_state,
|
329
|
+
stream_slice=stream_slice,
|
330
|
+
next_page_token=next_page_token,
|
331
|
+
),
|
283
332
|
request_body_data=self._request_body_data(
|
284
|
-
stream_state=stream_state,
|
333
|
+
stream_state=stream_state,
|
334
|
+
stream_slice=stream_slice,
|
335
|
+
next_page_token=next_page_token,
|
285
336
|
),
|
286
337
|
request_body_json=self._request_body_json(
|
287
|
-
stream_state=stream_state,
|
338
|
+
stream_state=stream_state,
|
339
|
+
stream_slice=stream_slice,
|
340
|
+
next_page_token=next_page_token,
|
288
341
|
),
|
289
342
|
)
|
290
343
|
|
@@ -323,10 +376,14 @@ class SimpleRetriever(Retriever):
|
|
323
376
|
if not response:
|
324
377
|
next_page_token: Mapping[str, Any] = {FULL_REFRESH_SYNC_COMPLETE_KEY: True}
|
325
378
|
else:
|
326
|
-
next_page_token = self._next_page_token(response) or {
|
379
|
+
next_page_token = self._next_page_token(response) or {
|
380
|
+
FULL_REFRESH_SYNC_COMPLETE_KEY: True
|
381
|
+
}
|
327
382
|
|
328
383
|
if self.cursor:
|
329
|
-
self.cursor.close_slice(
|
384
|
+
self.cursor.close_slice(
|
385
|
+
StreamSlice(cursor_slice=next_page_token, partition=stream_slice.partition)
|
386
|
+
)
|
330
387
|
|
331
388
|
# Always return an empty generator just in case no records were ever yielded
|
332
389
|
yield from []
|
@@ -383,7 +440,9 @@ class SimpleRetriever(Retriever):
|
|
383
440
|
# Latest record read, not necessarily within slice boundaries.
|
384
441
|
# TODO Remove once all custom components implement `observe` method.
|
385
442
|
# https://github.com/airbytehq/airbyte-internal-issues/issues/6955
|
386
|
-
most_recent_record_from_slice = self._get_most_recent_record(
|
443
|
+
most_recent_record_from_slice = self._get_most_recent_record(
|
444
|
+
most_recent_record_from_slice, current_record, _slice
|
445
|
+
)
|
387
446
|
yield stream_data
|
388
447
|
|
389
448
|
if self.cursor:
|
@@ -391,13 +450,20 @@ class SimpleRetriever(Retriever):
|
|
391
450
|
return
|
392
451
|
|
393
452
|
def _get_most_recent_record(
|
394
|
-
self,
|
453
|
+
self,
|
454
|
+
current_most_recent: Optional[Record],
|
455
|
+
current_record: Optional[Record],
|
456
|
+
stream_slice: StreamSlice,
|
395
457
|
) -> Optional[Record]:
|
396
458
|
if self.cursor and current_record:
|
397
459
|
if not current_most_recent:
|
398
460
|
return current_record
|
399
461
|
else:
|
400
|
-
return
|
462
|
+
return (
|
463
|
+
current_most_recent
|
464
|
+
if self.cursor.is_greater_than_or_equal(current_most_recent, current_record)
|
465
|
+
else current_record
|
466
|
+
)
|
401
467
|
else:
|
402
468
|
return None
|
403
469
|
|
@@ -482,20 +548,35 @@ class SimpleRetrieverTestReadDecorator(SimpleRetriever):
|
|
482
548
|
return islice(super().stream_slices(), self.maximum_number_of_slices)
|
483
549
|
|
484
550
|
def _fetch_next_page(
|
485
|
-
self,
|
551
|
+
self,
|
552
|
+
stream_state: Mapping[str, Any],
|
553
|
+
stream_slice: StreamSlice,
|
554
|
+
next_page_token: Optional[Mapping[str, Any]] = None,
|
486
555
|
) -> Optional[requests.Response]:
|
487
556
|
return self.requester.send_request(
|
488
557
|
path=self._paginator_path(),
|
489
558
|
stream_state=stream_state,
|
490
559
|
stream_slice=stream_slice,
|
491
560
|
next_page_token=next_page_token,
|
492
|
-
request_headers=self._request_headers(
|
493
|
-
|
561
|
+
request_headers=self._request_headers(
|
562
|
+
stream_state=stream_state,
|
563
|
+
stream_slice=stream_slice,
|
564
|
+
next_page_token=next_page_token,
|
565
|
+
),
|
566
|
+
request_params=self._request_params(
|
567
|
+
stream_state=stream_state,
|
568
|
+
stream_slice=stream_slice,
|
569
|
+
next_page_token=next_page_token,
|
570
|
+
),
|
494
571
|
request_body_data=self._request_body_data(
|
495
|
-
stream_state=stream_state,
|
572
|
+
stream_state=stream_state,
|
573
|
+
stream_slice=stream_slice,
|
574
|
+
next_page_token=next_page_token,
|
496
575
|
),
|
497
576
|
request_body_json=self._request_body_json(
|
498
|
-
stream_state=stream_state,
|
577
|
+
stream_state=stream_state,
|
578
|
+
stream_slice=stream_slice,
|
579
|
+
next_page_token=next_page_token,
|
499
580
|
),
|
500
581
|
log_formatter=lambda response: format_http_message(
|
501
582
|
response,
|
@@ -41,5 +41,7 @@ class DefaultSchemaLoader(SchemaLoader):
|
|
41
41
|
# A slight hack since we don't directly have the stream name. However, when building the default filepath we assume the
|
42
42
|
# runtime options stores stream name 'name' so we'll do the same here
|
43
43
|
stream_name = self._parameters.get("name", "")
|
44
|
-
logging.info(
|
44
|
+
logging.info(
|
45
|
+
f"Could not find schema for stream {stream_name}, defaulting to the empty schema"
|
46
|
+
)
|
45
47
|
return {}
|
@@ -5,7 +5,11 @@
|
|
5
5
|
from dataclasses import InitVar, dataclass
|
6
6
|
from typing import Any, Mapping, Optional
|
7
7
|
|
8
|
-
from airbyte_cdk.models import
|
8
|
+
from airbyte_cdk.models import (
|
9
|
+
AdvancedAuth,
|
10
|
+
ConnectorSpecification,
|
11
|
+
ConnectorSpecificationSerializer,
|
12
|
+
) # type: ignore [attr-defined]
|
9
13
|
from airbyte_cdk.sources.declarative.models.declarative_component_schema import AuthFlow
|
10
14
|
|
11
15
|
|
@@ -29,7 +33,9 @@ class Spec:
|
|
29
33
|
Returns the connector specification according the spec block defined in the low code connector manifest.
|
30
34
|
"""
|
31
35
|
|
32
|
-
obj: dict[str, Mapping[str, Any] | str | AdvancedAuth] = {
|
36
|
+
obj: dict[str, Mapping[str, Any] | str | AdvancedAuth] = {
|
37
|
+
"connectionSpecification": self.connection_specification
|
38
|
+
}
|
33
39
|
|
34
40
|
if self.documentation_url:
|
35
41
|
obj["documentationUrl"] = self.documentation_url
|
@@ -6,7 +6,9 @@ from abc import abstractmethod
|
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from typing import Iterable
|
8
8
|
|
9
|
-
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import
|
9
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
10
|
+
RequestOptionsProvider,
|
11
|
+
)
|
10
12
|
from airbyte_cdk.sources.types import StreamSlice
|
11
13
|
|
12
14
|
|
@@ -85,12 +85,16 @@ class AddFields(RecordTransformation):
|
|
85
85
|
|
86
86
|
fields: List[AddedFieldDefinition]
|
87
87
|
parameters: InitVar[Mapping[str, Any]]
|
88
|
-
_parsed_fields: List[ParsedAddFieldDefinition] = field(
|
88
|
+
_parsed_fields: List[ParsedAddFieldDefinition] = field(
|
89
|
+
init=False, repr=False, default_factory=list
|
90
|
+
)
|
89
91
|
|
90
92
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
91
93
|
for add_field in self.fields:
|
92
94
|
if len(add_field.path) < 1:
|
93
|
-
raise ValueError(
|
95
|
+
raise ValueError(
|
96
|
+
f"Expected a non-zero-length path for the AddFields transformation {add_field}"
|
97
|
+
)
|
94
98
|
|
95
99
|
if not isinstance(add_field.value, InterpolatedString):
|
96
100
|
if not isinstance(add_field.value, str):
|
@@ -106,7 +110,12 @@ class AddFields(RecordTransformation):
|
|
106
110
|
)
|
107
111
|
else:
|
108
112
|
self._parsed_fields.append(
|
109
|
-
ParsedAddFieldDefinition(
|
113
|
+
ParsedAddFieldDefinition(
|
114
|
+
add_field.path,
|
115
|
+
add_field.value,
|
116
|
+
value_type=add_field.value_type,
|
117
|
+
parameters={},
|
118
|
+
)
|
110
119
|
)
|
111
120
|
|
112
121
|
def transform(
|
@@ -44,7 +44,9 @@ class RemoveFields(RecordTransformation):
|
|
44
44
|
condition: str = ""
|
45
45
|
|
46
46
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
47
|
-
self._filter_interpolator = InterpolatedBoolean(
|
47
|
+
self._filter_interpolator = InterpolatedBoolean(
|
48
|
+
condition=self.condition, parameters=parameters
|
49
|
+
)
|
48
50
|
|
49
51
|
def transform(
|
50
52
|
self,
|
@@ -63,7 +65,9 @@ class RemoveFields(RecordTransformation):
|
|
63
65
|
dpath.delete(
|
64
66
|
record,
|
65
67
|
pointer,
|
66
|
-
afilter=(lambda x: self._filter_interpolator.eval(config or {}, property=x))
|
68
|
+
afilter=(lambda x: self._filter_interpolator.eval(config or {}, property=x))
|
69
|
+
if self.condition
|
70
|
+
else None,
|
67
71
|
)
|
68
72
|
except dpath.exceptions.PathNotFound:
|
69
73
|
# if the (potentially nested) property does not exist, silently skip
|
@@ -4,7 +4,14 @@
|
|
4
4
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
|
-
from airbyte_cdk.sources.types import
|
7
|
+
from airbyte_cdk.sources.types import (
|
8
|
+
Config,
|
9
|
+
ConnectionDefinition,
|
10
|
+
FieldPointer,
|
11
|
+
Record,
|
12
|
+
StreamSlice,
|
13
|
+
StreamState,
|
14
|
+
)
|
8
15
|
|
9
16
|
# Note: This package originally contained class definitions for low-code CDK types, but we promoted them into the Python CDK.
|
10
17
|
# We've migrated connectors in the repository to reference the new location, but these assignments are used to retain backwards
|
@@ -7,7 +7,9 @@ from typing import Any, List, Mapping, Optional
|
|
7
7
|
|
8
8
|
import yaml
|
9
9
|
from airbyte_cdk.models import AirbyteStateMessage, ConfiguredAirbyteCatalog
|
10
|
-
from airbyte_cdk.sources.declarative.concurrent_declarative_source import
|
10
|
+
from airbyte_cdk.sources.declarative.concurrent_declarative_source import (
|
11
|
+
ConcurrentDeclarativeSource,
|
12
|
+
)
|
11
13
|
from airbyte_cdk.sources.types import ConnectionDefinition
|
12
14
|
|
13
15
|
|
@@ -7,7 +7,11 @@ from typing import Generic, Iterable, Optional, TypeVar
|
|
7
7
|
|
8
8
|
from airbyte_cdk.connector import TConfig
|
9
9
|
from airbyte_cdk.models import AirbyteRecordMessage, AirbyteStateMessage, SyncMode, Type
|
10
|
-
from airbyte_cdk.sources.embedded.catalog import
|
10
|
+
from airbyte_cdk.sources.embedded.catalog import (
|
11
|
+
create_configured_catalog,
|
12
|
+
get_stream,
|
13
|
+
get_stream_names,
|
14
|
+
)
|
11
15
|
from airbyte_cdk.sources.embedded.runner import SourceRunner
|
12
16
|
from airbyte_cdk.sources.embedded.tools import get_defined_id
|
13
17
|
from airbyte_cdk.sources.utils.schema_helpers import check_config_against_spec_or_exit
|
@@ -31,11 +35,15 @@ class BaseEmbeddedIntegration(ABC, Generic[TConfig, TOutput]):
|
|
31
35
|
"""
|
32
36
|
pass
|
33
37
|
|
34
|
-
def _load_data(
|
38
|
+
def _load_data(
|
39
|
+
self, stream_name: str, state: Optional[AirbyteStateMessage] = None
|
40
|
+
) -> Iterable[TOutput]:
|
35
41
|
catalog = self.source.discover(self.config)
|
36
42
|
stream = get_stream(catalog, stream_name)
|
37
43
|
if not stream:
|
38
|
-
raise ValueError(
|
44
|
+
raise ValueError(
|
45
|
+
f"Stream {stream_name} not found, the following streams are available: {', '.join(get_stream_names(catalog))}"
|
46
|
+
)
|
39
47
|
if SyncMode.incremental not in stream.supported_sync_modes:
|
40
48
|
configured_catalog = create_configured_catalog(stream, sync_mode=SyncMode.full_refresh)
|
41
49
|
else:
|
@@ -43,7 +51,9 @@ class BaseEmbeddedIntegration(ABC, Generic[TConfig, TOutput]):
|
|
43
51
|
|
44
52
|
for message in self.source.read(self.config, configured_catalog, state):
|
45
53
|
if message.type == Type.RECORD:
|
46
|
-
output = self._handle_record(
|
54
|
+
output = self._handle_record(
|
55
|
+
message.record, get_defined_id(stream, message.record.data)
|
56
|
+
) # type: ignore[union-attr] # record has `data`
|
47
57
|
if output:
|
48
58
|
yield output
|
49
59
|
elif message.type is Type.STATE and message.state:
|