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
@@ -12,8 +12,13 @@ from airbyte_cdk.models import FailureType, Type
|
|
12
12
|
from airbyte_cdk.sources.declarative.async_job.job import AsyncJob
|
13
13
|
from airbyte_cdk.sources.declarative.async_job.repository import AsyncJobRepository
|
14
14
|
from airbyte_cdk.sources.declarative.async_job.status import AsyncJobStatus
|
15
|
-
from airbyte_cdk.sources.declarative.extractors.dpath_extractor import
|
16
|
-
|
15
|
+
from airbyte_cdk.sources.declarative.extractors.dpath_extractor import (
|
16
|
+
DpathExtractor,
|
17
|
+
RecordExtractor,
|
18
|
+
)
|
19
|
+
from airbyte_cdk.sources.declarative.extractors.response_to_file_extractor import (
|
20
|
+
ResponseToFileExtractor,
|
21
|
+
)
|
17
22
|
from airbyte_cdk.sources.declarative.requesters.requester import Requester
|
18
23
|
from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever
|
19
24
|
from airbyte_cdk.sources.types import Record, StreamSlice
|
@@ -35,7 +40,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
35
40
|
urls_extractor: DpathExtractor
|
36
41
|
|
37
42
|
job_timeout: Optional[timedelta] = None
|
38
|
-
record_extractor: RecordExtractor = field(
|
43
|
+
record_extractor: RecordExtractor = field(
|
44
|
+
init=False, repr=False, default_factory=lambda: ResponseToFileExtractor()
|
45
|
+
)
|
39
46
|
|
40
47
|
def __post_init__(self) -> None:
|
41
48
|
self._create_job_response_by_id: Dict[str, Response] = {}
|
@@ -55,7 +62,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
55
62
|
AirbyteTracedException: If the polling request returns an empty response.
|
56
63
|
"""
|
57
64
|
|
58
|
-
polling_response: Optional[requests.Response] = self.polling_requester.send_request(
|
65
|
+
polling_response: Optional[requests.Response] = self.polling_requester.send_request(
|
66
|
+
stream_slice=stream_slice
|
67
|
+
)
|
59
68
|
if polling_response is None:
|
60
69
|
raise AirbyteTracedException(
|
61
70
|
internal_message="Polling Requester received an empty Response.",
|
@@ -100,7 +109,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
100
109
|
AirbyteTracedException: If no response is received from the creation requester.
|
101
110
|
"""
|
102
111
|
|
103
|
-
response: Optional[requests.Response] = self.creation_requester.send_request(
|
112
|
+
response: Optional[requests.Response] = self.creation_requester.send_request(
|
113
|
+
stream_slice=stream_slice
|
114
|
+
)
|
104
115
|
if not response:
|
105
116
|
raise AirbyteTracedException(
|
106
117
|
internal_message="Always expect a response or an exception from creation_requester",
|
@@ -146,9 +157,17 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
146
157
|
job_status: AsyncJobStatus = self._get_validated_job_status(polling_response)
|
147
158
|
|
148
159
|
if job_status != job.status():
|
149
|
-
lazy_log(
|
160
|
+
lazy_log(
|
161
|
+
LOGGER,
|
162
|
+
logging.DEBUG,
|
163
|
+
lambda: f"Status of job {job.api_job_id()} changed from {job.status()} to {job_status}",
|
164
|
+
)
|
150
165
|
else:
|
151
|
-
lazy_log(
|
166
|
+
lazy_log(
|
167
|
+
LOGGER,
|
168
|
+
logging.DEBUG,
|
169
|
+
lambda: f"Status of job {job.api_job_id()} is still {job.status()}",
|
170
|
+
)
|
152
171
|
|
153
172
|
job.update_status(job_status)
|
154
173
|
if job_status == AsyncJobStatus.COMPLETED:
|
@@ -166,7 +185,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
166
185
|
|
167
186
|
"""
|
168
187
|
|
169
|
-
for url in self.urls_extractor.extract_records(
|
188
|
+
for url in self.urls_extractor.extract_records(
|
189
|
+
self._polling_job_response_by_id[job.api_job_id()]
|
190
|
+
):
|
170
191
|
stream_slice: StreamSlice = StreamSlice(partition={"url": url}, cursor_slice={})
|
171
192
|
for message in self.download_retriever.read_records({}, stream_slice):
|
172
193
|
if isinstance(message, Record):
|
@@ -9,7 +9,10 @@ from typing import Any, Callable, Mapping, MutableMapping, Optional, Union
|
|
9
9
|
from urllib.parse import urljoin
|
10
10
|
|
11
11
|
import requests
|
12
|
-
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import
|
12
|
+
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import (
|
13
|
+
DeclarativeAuthenticator,
|
14
|
+
NoAuth,
|
15
|
+
)
|
13
16
|
from airbyte_cdk.sources.declarative.decoders import Decoder
|
14
17
|
from airbyte_cdk.sources.declarative.decoders.json_decoder import JsonDecoder
|
15
18
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
@@ -62,13 +65,19 @@ class HttpRequester(Requester):
|
|
62
65
|
self._url_base = InterpolatedString.create(self.url_base, parameters=parameters)
|
63
66
|
self._path = InterpolatedString.create(self.path, parameters=parameters)
|
64
67
|
if self.request_options_provider is None:
|
65
|
-
self._request_options_provider = InterpolatedRequestOptionsProvider(
|
68
|
+
self._request_options_provider = InterpolatedRequestOptionsProvider(
|
69
|
+
config=self.config, parameters=parameters
|
70
|
+
)
|
66
71
|
elif isinstance(self.request_options_provider, dict):
|
67
|
-
self._request_options_provider = InterpolatedRequestOptionsProvider(
|
72
|
+
self._request_options_provider = InterpolatedRequestOptionsProvider(
|
73
|
+
config=self.config, **self.request_options_provider
|
74
|
+
)
|
68
75
|
else:
|
69
76
|
self._request_options_provider = self.request_options_provider
|
70
77
|
self._authenticator = self.authenticator or NoAuth(parameters=parameters)
|
71
|
-
self._http_method =
|
78
|
+
self._http_method = (
|
79
|
+
HttpMethod[self.http_method] if isinstance(self.http_method, str) else self.http_method
|
80
|
+
)
|
72
81
|
self.error_handler = self.error_handler
|
73
82
|
self._parameters = parameters
|
74
83
|
|
@@ -103,9 +112,17 @@ class HttpRequester(Requester):
|
|
103
112
|
return os.path.join(self._url_base.eval(self.config), "")
|
104
113
|
|
105
114
|
def get_path(
|
106
|
-
self,
|
115
|
+
self,
|
116
|
+
*,
|
117
|
+
stream_state: Optional[StreamState],
|
118
|
+
stream_slice: Optional[StreamSlice],
|
119
|
+
next_page_token: Optional[Mapping[str, Any]],
|
107
120
|
) -> str:
|
108
|
-
kwargs = {
|
121
|
+
kwargs = {
|
122
|
+
"stream_state": stream_state,
|
123
|
+
"stream_slice": stream_slice,
|
124
|
+
"next_page_token": next_page_token,
|
125
|
+
}
|
109
126
|
path = str(self._path.eval(self.config, **kwargs))
|
110
127
|
return path.lstrip("/")
|
111
128
|
|
@@ -144,7 +161,9 @@ class HttpRequester(Requester):
|
|
144
161
|
) -> Union[Mapping[str, Any], str]:
|
145
162
|
return (
|
146
163
|
self._request_options_provider.get_request_body_data(
|
147
|
-
stream_state=stream_state,
|
164
|
+
stream_state=stream_state,
|
165
|
+
stream_slice=stream_slice,
|
166
|
+
next_page_token=next_page_token,
|
148
167
|
)
|
149
168
|
or {}
|
150
169
|
)
|
@@ -181,7 +200,11 @@ class HttpRequester(Requester):
|
|
181
200
|
"""
|
182
201
|
return combine_mappings(
|
183
202
|
[
|
184
|
-
requester_method(
|
203
|
+
requester_method(
|
204
|
+
stream_state=stream_state,
|
205
|
+
stream_slice=stream_slice,
|
206
|
+
next_page_token=next_page_token,
|
207
|
+
),
|
185
208
|
auth_options_method(),
|
186
209
|
extra_options,
|
187
210
|
]
|
@@ -223,14 +246,21 @@ class HttpRequester(Requester):
|
|
223
246
|
E.g: you might want to define query parameters for paging if next_page_token is not None.
|
224
247
|
"""
|
225
248
|
options = self._get_request_options(
|
226
|
-
stream_state,
|
249
|
+
stream_state,
|
250
|
+
stream_slice,
|
251
|
+
next_page_token,
|
252
|
+
self.get_request_params,
|
253
|
+
self.get_authenticator().get_request_params,
|
254
|
+
extra_params,
|
227
255
|
)
|
228
256
|
if isinstance(options, str):
|
229
257
|
raise ValueError("Request params cannot be a string")
|
230
258
|
|
231
259
|
for k, v in options.items():
|
232
260
|
if isinstance(v, (dict,)):
|
233
|
-
raise ValueError(
|
261
|
+
raise ValueError(
|
262
|
+
f"Invalid value for `{k}` parameter. The values of request params cannot be an object."
|
263
|
+
)
|
234
264
|
|
235
265
|
return options
|
236
266
|
|
@@ -301,18 +331,30 @@ class HttpRequester(Requester):
|
|
301
331
|
request_body_json: Optional[Mapping[str, Any]] = None,
|
302
332
|
log_formatter: Optional[Callable[[requests.Response], Any]] = None,
|
303
333
|
) -> Optional[requests.Response]:
|
304
|
-
|
305
334
|
request, response = self._http_client.send_request(
|
306
335
|
http_method=self.get_method().value,
|
307
336
|
url=self._join_url(
|
308
337
|
self.get_url_base(),
|
309
|
-
path
|
338
|
+
path
|
339
|
+
or self.get_path(
|
340
|
+
stream_state=stream_state,
|
341
|
+
stream_slice=stream_slice,
|
342
|
+
next_page_token=next_page_token,
|
343
|
+
),
|
310
344
|
),
|
311
345
|
request_kwargs={"stream": self.stream_response},
|
312
|
-
headers=self._request_headers(
|
313
|
-
|
314
|
-
|
315
|
-
|
346
|
+
headers=self._request_headers(
|
347
|
+
stream_state, stream_slice, next_page_token, request_headers
|
348
|
+
),
|
349
|
+
params=self._request_params(
|
350
|
+
stream_state, stream_slice, next_page_token, request_params
|
351
|
+
),
|
352
|
+
json=self._request_body_json(
|
353
|
+
stream_state, stream_slice, next_page_token, request_body_json
|
354
|
+
),
|
355
|
+
data=self._request_body_data(
|
356
|
+
stream_state, stream_slice, next_page_token, request_body_data
|
357
|
+
),
|
316
358
|
dedupe_query_params=True,
|
317
359
|
log_formatter=log_formatter,
|
318
360
|
exit_on_rate_limit=self._exit_on_rate_limit,
|
@@ -6,11 +6,20 @@ from dataclasses import InitVar, dataclass, field
|
|
6
6
|
from typing import Any, Mapping, MutableMapping, Optional, Union
|
7
7
|
|
8
8
|
import requests
|
9
|
-
from airbyte_cdk.sources.declarative.decoders import
|
9
|
+
from airbyte_cdk.sources.declarative.decoders import (
|
10
|
+
Decoder,
|
11
|
+
JsonDecoder,
|
12
|
+
PaginationDecoderDecorator,
|
13
|
+
)
|
10
14
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
11
15
|
from airbyte_cdk.sources.declarative.requesters.paginators.paginator import Paginator
|
12
|
-
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import
|
13
|
-
|
16
|
+
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import (
|
17
|
+
PaginationStrategy,
|
18
|
+
)
|
19
|
+
from airbyte_cdk.sources.declarative.requesters.request_option import (
|
20
|
+
RequestOption,
|
21
|
+
RequestOptionType,
|
22
|
+
)
|
14
23
|
from airbyte_cdk.sources.declarative.requesters.request_path import RequestPath
|
15
24
|
from airbyte_cdk.sources.types import Config, Record, StreamSlice, StreamState
|
16
25
|
|
@@ -89,13 +98,17 @@ class DefaultPaginator(Paginator):
|
|
89
98
|
config: Config
|
90
99
|
url_base: Union[InterpolatedString, str]
|
91
100
|
parameters: InitVar[Mapping[str, Any]]
|
92
|
-
decoder: Decoder = field(
|
101
|
+
decoder: Decoder = field(
|
102
|
+
default_factory=lambda: PaginationDecoderDecorator(decoder=JsonDecoder(parameters={}))
|
103
|
+
)
|
93
104
|
page_size_option: Optional[RequestOption] = None
|
94
105
|
page_token_option: Optional[Union[RequestPath, RequestOption]] = None
|
95
106
|
|
96
107
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
97
108
|
if self.page_size_option and not self.pagination_strategy.get_page_size():
|
98
|
-
raise ValueError(
|
109
|
+
raise ValueError(
|
110
|
+
"page_size_option cannot be set if the pagination strategy does not have a page_size"
|
111
|
+
)
|
99
112
|
if isinstance(self.url_base, str):
|
100
113
|
self.url_base = InterpolatedString(string=self.url_base, parameters=parameters)
|
101
114
|
self._token: Optional[Any] = self.pagination_strategy.initial_token
|
@@ -103,14 +116,20 @@ class DefaultPaginator(Paginator):
|
|
103
116
|
def next_page_token(
|
104
117
|
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
105
118
|
) -> Optional[Mapping[str, Any]]:
|
106
|
-
self._token = self.pagination_strategy.next_page_token(
|
119
|
+
self._token = self.pagination_strategy.next_page_token(
|
120
|
+
response, last_page_size, last_record
|
121
|
+
)
|
107
122
|
if self._token:
|
108
123
|
return {"next_page_token": self._token}
|
109
124
|
else:
|
110
125
|
return None
|
111
126
|
|
112
127
|
def path(self) -> Optional[str]:
|
113
|
-
if
|
128
|
+
if (
|
129
|
+
self._token
|
130
|
+
and self.page_token_option
|
131
|
+
and isinstance(self.page_token_option, RequestPath)
|
132
|
+
):
|
114
133
|
# Replace url base to only return the path
|
115
134
|
return str(self._token).replace(self.url_base.eval(self.config), "") # type: ignore # url_base is casted to a InterpolatedString in __post_init__
|
116
135
|
else:
|
@@ -169,8 +188,14 @@ class DefaultPaginator(Paginator):
|
|
169
188
|
and self.page_token_option.inject_into == option_type
|
170
189
|
):
|
171
190
|
options[self.page_token_option.field_name.eval(config=self.config)] = self._token # type: ignore # field_name is always cast to an interpolated string
|
172
|
-
if
|
173
|
-
|
191
|
+
if (
|
192
|
+
self.page_size_option
|
193
|
+
and self.pagination_strategy.get_page_size()
|
194
|
+
and self.page_size_option.inject_into == option_type
|
195
|
+
):
|
196
|
+
options[self.page_size_option.field_name.eval(config=self.config)] = (
|
197
|
+
self.pagination_strategy.get_page_size()
|
198
|
+
) # type: ignore # field_name is always cast to an interpolated string
|
174
199
|
return options
|
175
200
|
|
176
201
|
|
@@ -184,7 +209,9 @@ class PaginatorTestReadDecorator(Paginator):
|
|
184
209
|
|
185
210
|
def __init__(self, decorated: Paginator, maximum_number_of_pages: int = 5) -> None:
|
186
211
|
if maximum_number_of_pages and maximum_number_of_pages < 1:
|
187
|
-
raise ValueError(
|
212
|
+
raise ValueError(
|
213
|
+
f"The maximum number of pages on a test read needs to be strictly positive. Got {maximum_number_of_pages}"
|
214
|
+
)
|
188
215
|
self._maximum_number_of_pages = maximum_number_of_pages
|
189
216
|
self._decorated = decorated
|
190
217
|
self._page_count = self._PAGE_COUNT_BEFORE_FIRST_NEXT_CALL
|
@@ -208,7 +235,9 @@ class PaginatorTestReadDecorator(Paginator):
|
|
208
235
|
stream_slice: Optional[StreamSlice] = None,
|
209
236
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
210
237
|
) -> Mapping[str, Any]:
|
211
|
-
return self._decorated.get_request_params(
|
238
|
+
return self._decorated.get_request_params(
|
239
|
+
stream_state=stream_state, stream_slice=stream_slice, next_page_token=next_page_token
|
240
|
+
)
|
212
241
|
|
213
242
|
def get_request_headers(
|
214
243
|
self,
|
@@ -217,7 +246,9 @@ class PaginatorTestReadDecorator(Paginator):
|
|
217
246
|
stream_slice: Optional[StreamSlice] = None,
|
218
247
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
219
248
|
) -> Mapping[str, str]:
|
220
|
-
return self._decorated.get_request_headers(
|
249
|
+
return self._decorated.get_request_headers(
|
250
|
+
stream_state=stream_state, stream_slice=stream_slice, next_page_token=next_page_token
|
251
|
+
)
|
221
252
|
|
222
253
|
def get_request_body_data(
|
223
254
|
self,
|
@@ -226,7 +257,9 @@ class PaginatorTestReadDecorator(Paginator):
|
|
226
257
|
stream_slice: Optional[StreamSlice] = None,
|
227
258
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
228
259
|
) -> Union[Mapping[str, Any], str]:
|
229
|
-
return self._decorated.get_request_body_data(
|
260
|
+
return self._decorated.get_request_body_data(
|
261
|
+
stream_state=stream_state, stream_slice=stream_slice, next_page_token=next_page_token
|
262
|
+
)
|
230
263
|
|
231
264
|
def get_request_body_json(
|
232
265
|
self,
|
@@ -235,7 +268,9 @@ class PaginatorTestReadDecorator(Paginator):
|
|
235
268
|
stream_slice: Optional[StreamSlice] = None,
|
236
269
|
next_page_token: Optional[Mapping[str, Any]] = None,
|
237
270
|
) -> Mapping[str, Any]:
|
238
|
-
return self._decorated.get_request_body_json(
|
271
|
+
return self._decorated.get_request_body_json(
|
272
|
+
stream_state=stream_state, stream_slice=stream_slice, next_page_token=next_page_token
|
273
|
+
)
|
239
274
|
|
240
275
|
def reset(self, reset_value: Optional[Any] = None) -> None:
|
241
276
|
self._decorated.reset()
|
@@ -57,7 +57,9 @@ class NoPagination(Paginator):
|
|
57
57
|
) -> Mapping[str, Any]:
|
58
58
|
return {}
|
59
59
|
|
60
|
-
def next_page_token(
|
60
|
+
def next_page_token(
|
61
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
62
|
+
) -> Mapping[str, Any]:
|
61
63
|
return {}
|
62
64
|
|
63
65
|
def reset(self, reset_value: Optional[Any] = None) -> None:
|
@@ -7,7 +7,9 @@ from dataclasses import dataclass
|
|
7
7
|
from typing import Any, Mapping, Optional
|
8
8
|
|
9
9
|
import requests
|
10
|
-
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import
|
10
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
11
|
+
RequestOptionsProvider,
|
12
|
+
)
|
11
13
|
from airbyte_cdk.sources.types import Record
|
12
14
|
|
13
15
|
|
airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py
CHANGED
@@ -6,10 +6,16 @@ from dataclasses import InitVar, dataclass, field
|
|
6
6
|
from typing import Any, Dict, Mapping, Optional, Union
|
7
7
|
|
8
8
|
import requests
|
9
|
-
from airbyte_cdk.sources.declarative.decoders import
|
9
|
+
from airbyte_cdk.sources.declarative.decoders import (
|
10
|
+
Decoder,
|
11
|
+
JsonDecoder,
|
12
|
+
PaginationDecoderDecorator,
|
13
|
+
)
|
10
14
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean
|
11
15
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
12
|
-
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import
|
16
|
+
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import (
|
17
|
+
PaginationStrategy,
|
18
|
+
)
|
13
19
|
from airbyte_cdk.sources.types import Config, Record
|
14
20
|
|
15
21
|
|
@@ -31,7 +37,9 @@ class CursorPaginationStrategy(PaginationStrategy):
|
|
31
37
|
parameters: InitVar[Mapping[str, Any]]
|
32
38
|
page_size: Optional[int] = None
|
33
39
|
stop_condition: Optional[Union[InterpolatedBoolean, str]] = None
|
34
|
-
decoder: Decoder = field(
|
40
|
+
decoder: Decoder = field(
|
41
|
+
default_factory=lambda: PaginationDecoderDecorator(decoder=JsonDecoder(parameters={}))
|
42
|
+
)
|
35
43
|
|
36
44
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
37
45
|
self._initial_cursor = None
|
@@ -40,7 +48,9 @@ class CursorPaginationStrategy(PaginationStrategy):
|
|
40
48
|
else:
|
41
49
|
self._cursor_value = self.cursor_value
|
42
50
|
if isinstance(self.stop_condition, str):
|
43
|
-
self._stop_condition: Optional[InterpolatedBoolean] = InterpolatedBoolean(
|
51
|
+
self._stop_condition: Optional[InterpolatedBoolean] = InterpolatedBoolean(
|
52
|
+
condition=self.stop_condition, parameters=parameters
|
53
|
+
)
|
44
54
|
else:
|
45
55
|
self._stop_condition = self.stop_condition
|
46
56
|
|
@@ -48,7 +58,9 @@ class CursorPaginationStrategy(PaginationStrategy):
|
|
48
58
|
def initial_token(self) -> Optional[Any]:
|
49
59
|
return self._initial_cursor
|
50
60
|
|
51
|
-
def next_page_token(
|
61
|
+
def next_page_token(
|
62
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
63
|
+
) -> Optional[Any]:
|
52
64
|
decoded_response = next(self.decoder.decode(response))
|
53
65
|
|
54
66
|
# The default way that link is presented in requests.Response is a string of various links (last, next, etc). This
|
@@ -6,9 +6,15 @@ from dataclasses import InitVar, dataclass, field
|
|
6
6
|
from typing import Any, Mapping, Optional, Union
|
7
7
|
|
8
8
|
import requests
|
9
|
-
from airbyte_cdk.sources.declarative.decoders import
|
9
|
+
from airbyte_cdk.sources.declarative.decoders import (
|
10
|
+
Decoder,
|
11
|
+
JsonDecoder,
|
12
|
+
PaginationDecoderDecorator,
|
13
|
+
)
|
10
14
|
from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
|
11
|
-
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import
|
15
|
+
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import (
|
16
|
+
PaginationStrategy,
|
17
|
+
)
|
12
18
|
from airbyte_cdk.sources.types import Config, Record
|
13
19
|
|
14
20
|
|
@@ -39,14 +45,18 @@ class OffsetIncrement(PaginationStrategy):
|
|
39
45
|
config: Config
|
40
46
|
page_size: Optional[Union[str, int]]
|
41
47
|
parameters: InitVar[Mapping[str, Any]]
|
42
|
-
decoder: Decoder = field(
|
48
|
+
decoder: Decoder = field(
|
49
|
+
default_factory=lambda: PaginationDecoderDecorator(decoder=JsonDecoder(parameters={}))
|
50
|
+
)
|
43
51
|
inject_on_first_request: bool = False
|
44
52
|
|
45
53
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
46
54
|
self._offset = 0
|
47
55
|
page_size = str(self.page_size) if isinstance(self.page_size, int) else self.page_size
|
48
56
|
if page_size:
|
49
|
-
self._page_size: Optional[InterpolatedString] = InterpolatedString(
|
57
|
+
self._page_size: Optional[InterpolatedString] = InterpolatedString(
|
58
|
+
page_size, parameters=parameters
|
59
|
+
)
|
50
60
|
else:
|
51
61
|
self._page_size = None
|
52
62
|
|
@@ -56,11 +66,16 @@ class OffsetIncrement(PaginationStrategy):
|
|
56
66
|
return self._offset
|
57
67
|
return None
|
58
68
|
|
59
|
-
def next_page_token(
|
69
|
+
def next_page_token(
|
70
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
71
|
+
) -> Optional[Any]:
|
60
72
|
decoded_response = next(self.decoder.decode(response))
|
61
73
|
|
62
74
|
# Stop paginating when there are fewer records than the page size or the current page has no records
|
63
|
-
if (
|
75
|
+
if (
|
76
|
+
self._page_size
|
77
|
+
and last_page_size < self._page_size.eval(self.config, response=decoded_response)
|
78
|
+
) or last_page_size == 0:
|
64
79
|
return None
|
65
80
|
else:
|
66
81
|
self._offset += last_page_size
|
@@ -68,7 +83,9 @@ class OffsetIncrement(PaginationStrategy):
|
|
68
83
|
|
69
84
|
def reset(self, reset_value: Optional[Any] = 0) -> None:
|
70
85
|
if not isinstance(reset_value, int):
|
71
|
-
raise ValueError(
|
86
|
+
raise ValueError(
|
87
|
+
f"Reset value {reset_value} for OffsetIncrement pagination strategy was not an integer"
|
88
|
+
)
|
72
89
|
else:
|
73
90
|
self._offset = reset_value
|
74
91
|
|
@@ -7,7 +7,9 @@ from typing import Any, Mapping, Optional, Union
|
|
7
7
|
|
8
8
|
import requests
|
9
9
|
from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
|
10
|
-
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import
|
10
|
+
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import (
|
11
|
+
PaginationStrategy,
|
12
|
+
)
|
11
13
|
from airbyte_cdk.sources.types import Config, Record
|
12
14
|
|
13
15
|
|
@@ -43,7 +45,9 @@ class PageIncrement(PaginationStrategy):
|
|
43
45
|
return self._page
|
44
46
|
return None
|
45
47
|
|
46
|
-
def next_page_token(
|
48
|
+
def next_page_token(
|
49
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
50
|
+
) -> Optional[Any]:
|
47
51
|
# Stop paginating when there are fewer records than the page size or the current page has no records
|
48
52
|
if (self._page_size and last_page_size < self._page_size) or last_page_size == 0:
|
49
53
|
return None
|
@@ -55,7 +59,9 @@ class PageIncrement(PaginationStrategy):
|
|
55
59
|
if reset_value is None:
|
56
60
|
self._page = self.start_from_page
|
57
61
|
elif not isinstance(reset_value, int):
|
58
|
-
raise ValueError(
|
62
|
+
raise ValueError(
|
63
|
+
f"Reset value {reset_value} for PageIncrement pagination strategy was not an integer"
|
64
|
+
)
|
59
65
|
else:
|
60
66
|
self._page = reset_value
|
61
67
|
|
@@ -24,7 +24,9 @@ class PaginationStrategy:
|
|
24
24
|
"""
|
25
25
|
|
26
26
|
@abstractmethod
|
27
|
-
def next_page_token(
|
27
|
+
def next_page_token(
|
28
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
29
|
+
) -> Optional[Any]:
|
28
30
|
"""
|
29
31
|
:param response: response to process
|
30
32
|
:param last_page_size: the number of records read from the response
|
@@ -7,7 +7,9 @@ from typing import Any, Optional
|
|
7
7
|
|
8
8
|
import requests
|
9
9
|
from airbyte_cdk.sources.declarative.incremental.declarative_cursor import DeclarativeCursor
|
10
|
-
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import
|
10
|
+
from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import (
|
11
|
+
PaginationStrategy,
|
12
|
+
)
|
11
13
|
from airbyte_cdk.sources.types import Record
|
12
14
|
|
13
15
|
|
@@ -35,7 +37,9 @@ class StopConditionPaginationStrategyDecorator(PaginationStrategy):
|
|
35
37
|
self._delegate = _delegate
|
36
38
|
self._stop_condition = stop_condition
|
37
39
|
|
38
|
-
def next_page_token(
|
40
|
+
def next_page_token(
|
41
|
+
self, response: requests.Response, last_page_size: int, last_record: Optional[Record]
|
42
|
+
) -> Optional[Any]:
|
39
43
|
# We evaluate in reverse order because the assumption is that most of the APIs using data feed structure will return records in
|
40
44
|
# descending order. In terms of performance/memory, we return the records lazily
|
41
45
|
if last_record and self._stop_condition.is_met(last_record):
|
@@ -6,8 +6,13 @@ from dataclasses import InitVar, dataclass
|
|
6
6
|
from typing import Any, Mapping, MutableMapping, Optional, Union
|
7
7
|
|
8
8
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
9
|
-
from airbyte_cdk.sources.declarative.requesters.request_option import
|
10
|
-
|
9
|
+
from airbyte_cdk.sources.declarative.requesters.request_option import (
|
10
|
+
RequestOption,
|
11
|
+
RequestOptionType,
|
12
|
+
)
|
13
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
14
|
+
RequestOptionsProvider,
|
15
|
+
)
|
11
16
|
from airbyte_cdk.sources.types import Config, StreamSlice, StreamState
|
12
17
|
|
13
18
|
|
@@ -26,8 +31,12 @@ class DatetimeBasedRequestOptionsProvider(RequestOptionsProvider):
|
|
26
31
|
partition_field_end: Optional[str] = None
|
27
32
|
|
28
33
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
29
|
-
self._partition_field_start = InterpolatedString.create(
|
30
|
-
|
34
|
+
self._partition_field_start = InterpolatedString.create(
|
35
|
+
self.partition_field_start or "start_time", parameters=parameters
|
36
|
+
)
|
37
|
+
self._partition_field_end = InterpolatedString.create(
|
38
|
+
self.partition_field_end or "end_time", parameters=parameters
|
39
|
+
)
|
31
40
|
|
32
41
|
def get_request_params(
|
33
42
|
self,
|
@@ -65,7 +74,9 @@ class DatetimeBasedRequestOptionsProvider(RequestOptionsProvider):
|
|
65
74
|
) -> Mapping[str, Any]:
|
66
75
|
return self._get_request_options(RequestOptionType.body_json, stream_slice)
|
67
76
|
|
68
|
-
def _get_request_options(
|
77
|
+
def _get_request_options(
|
78
|
+
self, option_type: RequestOptionType, stream_slice: Optional[StreamSlice]
|
79
|
+
) -> Mapping[str, Any]:
|
69
80
|
options: MutableMapping[str, Any] = {}
|
70
81
|
if not stream_slice:
|
71
82
|
return options
|
@@ -74,5 +85,7 @@ class DatetimeBasedRequestOptionsProvider(RequestOptionsProvider):
|
|
74
85
|
self._partition_field_start.eval(self.config)
|
75
86
|
)
|
76
87
|
if self.end_time_option and self.end_time_option.inject_into == option_type:
|
77
|
-
options[self.end_time_option.field_name.eval(config=self.config)] = stream_slice.get(
|
88
|
+
options[self.end_time_option.field_name.eval(config=self.config)] = stream_slice.get(
|
89
|
+
self._partition_field_end.eval(self.config)
|
90
|
+
) # type: ignore # field_name is always casted to an interpolated string
|
78
91
|
return options
|
airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py
CHANGED
@@ -5,7 +5,9 @@
|
|
5
5
|
from dataclasses import InitVar, dataclass
|
6
6
|
from typing import Any, Mapping, Optional, Union
|
7
7
|
|
8
|
-
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import
|
8
|
+
from airbyte_cdk.sources.declarative.requesters.request_options.request_options_provider import (
|
9
|
+
RequestOptionsProvider,
|
10
|
+
)
|
9
11
|
from airbyte_cdk.sources.types import StreamSlice, StreamState
|
10
12
|
|
11
13
|
|