airbyte-cdk 6.48.1__py3-none-any.whl → 6.48.2__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/connector_builder/test_reader/reader.py +11 -0
- airbyte_cdk/manifest_migrations/migrations/registry.yaml +1 -1
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +80 -5
- airbyte_cdk/sources/declarative/declarative_source.py +10 -1
- airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +1 -1
- airbyte_cdk/sources/declarative/manifest_declarative_source.py +6 -0
- airbyte_cdk/sources/declarative/models/base_model_with_deprecations.py +144 -0
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +54 -5
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +58 -7
- airbyte_cdk/sources/declarative/requesters/http_requester.py +62 -17
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +24 -2
- airbyte_cdk/sources/declarative/requesters/requester.py +12 -0
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/METADATA +1 -1
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/RECORD +18 -17
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/WHEEL +0 -0
- {airbyte_cdk-6.48.1.dist-info → airbyte_cdk-6.48.2.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
|
6
6
|
import logging
|
7
|
+
from math import log
|
7
8
|
from typing import Any, ClassVar, Dict, Iterator, List, Mapping, Optional, Union
|
8
9
|
|
9
10
|
from airbyte_cdk.connector_builder.models import (
|
@@ -112,11 +113,16 @@ class TestReader:
|
|
112
113
|
record_limit = self._check_record_limit(record_limit)
|
113
114
|
# The connector builder currently only supports reading from a single stream at a time
|
114
115
|
stream = source.streams(config)[0]
|
116
|
+
|
117
|
+
# get any deprecation warnings during the component creation
|
118
|
+
deprecation_warnings: List[LogMessage] = source.deprecation_warnings()
|
119
|
+
|
115
120
|
schema_inferrer = SchemaInferrer(
|
116
121
|
self._pk_to_nested_and_composite_field(stream.primary_key),
|
117
122
|
self._cursor_field_to_nested_and_composite_field(stream.cursor_field),
|
118
123
|
)
|
119
124
|
datetime_format_inferrer = DatetimeFormatInferrer()
|
125
|
+
|
120
126
|
message_group = get_message_groups(
|
121
127
|
self._read_stream(source, config, configured_catalog, state),
|
122
128
|
schema_inferrer,
|
@@ -127,6 +133,10 @@ class TestReader:
|
|
127
133
|
slices, log_messages, auxiliary_requests, latest_config_update = self._categorise_groups(
|
128
134
|
message_group
|
129
135
|
)
|
136
|
+
|
137
|
+
# extend log messages with deprecation warnings
|
138
|
+
log_messages.extend(deprecation_warnings)
|
139
|
+
|
130
140
|
schema, log_messages = self._get_infered_schema(
|
131
141
|
configured_catalog, schema_inferrer, log_messages
|
132
142
|
)
|
@@ -269,6 +279,7 @@ class TestReader:
|
|
269
279
|
auxiliary_requests = []
|
270
280
|
latest_config_update: Optional[AirbyteControlMessage] = None
|
271
281
|
|
282
|
+
# process the message groups first
|
272
283
|
for message_group in message_groups:
|
273
284
|
match message_group:
|
274
285
|
case AirbyteLogMessage():
|
@@ -1911,15 +1911,16 @@ definitions:
|
|
1911
1911
|
type: object
|
1912
1912
|
required:
|
1913
1913
|
- type
|
1914
|
-
- url_base
|
1915
1914
|
properties:
|
1916
1915
|
type:
|
1917
1916
|
type: string
|
1918
1917
|
enum: [HttpRequester]
|
1919
1918
|
url_base:
|
1920
|
-
|
1919
|
+
deprecated: true
|
1920
|
+
deprecation_message: "Use `url` field instead."
|
1921
1921
|
title: API Base URL
|
1922
|
-
description:
|
1922
|
+
description: Deprecated, use the `url` instead. Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
|
1923
|
+
linkable: true
|
1923
1924
|
type: string
|
1924
1925
|
interpolation_context:
|
1925
1926
|
- config
|
@@ -1935,9 +1936,29 @@ definitions:
|
|
1935
1936
|
- "{{ config['base_url'] or 'https://app.posthog.com'}}/api"
|
1936
1937
|
- "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups"
|
1937
1938
|
- "https://example.com/api/v1/resource/{{ next_page_token['id'] }}"
|
1939
|
+
url:
|
1940
|
+
title: The URL of an API endpoint
|
1941
|
+
description: The URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
|
1942
|
+
type: string
|
1943
|
+
interpolation_context:
|
1944
|
+
- config
|
1945
|
+
- next_page_token
|
1946
|
+
- stream_interval
|
1947
|
+
- stream_partition
|
1948
|
+
- stream_slice
|
1949
|
+
- creation_response
|
1950
|
+
- polling_response
|
1951
|
+
- download_target
|
1952
|
+
examples:
|
1953
|
+
- "https://connect.squareup.com/v2"
|
1954
|
+
- "{{ config['url'] or 'https://app.posthog.com'}}/api"
|
1955
|
+
- "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups"
|
1956
|
+
- "https://example.com/api/v1/resource/{{ next_page_token['id'] }}"
|
1938
1957
|
path:
|
1958
|
+
deprecated: true
|
1959
|
+
deprecation_message: "Use `url` field instead."
|
1939
1960
|
title: URL Path
|
1940
|
-
description:
|
1961
|
+
description: Deprecated, use the `url` instead. Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
|
1941
1962
|
type: string
|
1942
1963
|
interpolation_context:
|
1943
1964
|
- config
|
@@ -1983,6 +2004,8 @@ definitions:
|
|
1983
2004
|
description: Allows for retrieving a dynamic set of properties from an API endpoint which can be injected into outbound request using the stream_partition.extra_fields.
|
1984
2005
|
"$ref": "#/definitions/PropertiesFromEndpoint"
|
1985
2006
|
request_body_data:
|
2007
|
+
deprecated: true
|
2008
|
+
deprecation_message: "Use `request_body` field instead."
|
1986
2009
|
title: Request Body Payload (Non-JSON)
|
1987
2010
|
description: Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.
|
1988
2011
|
anyOf:
|
@@ -2001,6 +2024,8 @@ definitions:
|
|
2001
2024
|
[{"value": {{ stream_interval['start_time'] | int * 1000 }} }]
|
2002
2025
|
}, "orderBy": 1, "columnName": "Timestamp"}]/
|
2003
2026
|
request_body_json:
|
2027
|
+
deprecated: true
|
2028
|
+
deprecation_message: "Use `request_body` field instead."
|
2004
2029
|
title: Request Body JSON Payload
|
2005
2030
|
description: Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.
|
2006
2031
|
anyOf:
|
@@ -2019,6 +2044,35 @@ definitions:
|
|
2019
2044
|
- sort:
|
2020
2045
|
field: "updated_at"
|
2021
2046
|
order: "ascending"
|
2047
|
+
request_body:
|
2048
|
+
title: Request Body Payload to be send as a part of the API request.
|
2049
|
+
description: Specifies how to populate the body of the request with a payload. Can contain nested objects.
|
2050
|
+
anyOf:
|
2051
|
+
- "$ref": "#/definitions/RequestBody"
|
2052
|
+
interpolation_context:
|
2053
|
+
- next_page_token
|
2054
|
+
- stream_interval
|
2055
|
+
- stream_partition
|
2056
|
+
- stream_slice
|
2057
|
+
examples:
|
2058
|
+
- type: RequestBodyJson
|
2059
|
+
value:
|
2060
|
+
sort_order: "ASC"
|
2061
|
+
sort_field: "CREATED_AT"
|
2062
|
+
- type: RequestBodyJson
|
2063
|
+
value:
|
2064
|
+
key: "{{ config['value'] }}"
|
2065
|
+
- type: RequestBodyJson
|
2066
|
+
value:
|
2067
|
+
sort:
|
2068
|
+
field: "updated_at"
|
2069
|
+
order: "ascending"
|
2070
|
+
- type: RequestBodyData
|
2071
|
+
value: "plain_text_body"
|
2072
|
+
- type: RequestBodyData
|
2073
|
+
value:
|
2074
|
+
param1: "value1"
|
2075
|
+
param2: "{{ config['param2_value'] }}"
|
2022
2076
|
request_headers:
|
2023
2077
|
title: Request Headers
|
2024
2078
|
description: Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.
|
@@ -4019,6 +4073,27 @@ definitions:
|
|
4019
4073
|
- type
|
4020
4074
|
- stream_template
|
4021
4075
|
- components_resolver
|
4076
|
+
RequestBody:
|
4077
|
+
type: object
|
4078
|
+
description: The request body payload. Can be either URL encoded data or JSON.
|
4079
|
+
properties:
|
4080
|
+
type:
|
4081
|
+
anyOf:
|
4082
|
+
- type: string
|
4083
|
+
enum: [RequestBodyData]
|
4084
|
+
- type: string
|
4085
|
+
enum: [RequestBodyJson]
|
4086
|
+
value:
|
4087
|
+
anyOf:
|
4088
|
+
- type: string
|
4089
|
+
description: The request body payload as a string.
|
4090
|
+
- type: object
|
4091
|
+
description: The request body payload as a Non-JSON object (url-encoded data).
|
4092
|
+
additionalProperties:
|
4093
|
+
type: string
|
4094
|
+
- type: object
|
4095
|
+
description: The request body payload as a JSON object (json-encoded data).
|
4096
|
+
additionalProperties: true
|
4022
4097
|
interpolation:
|
4023
4098
|
variables:
|
4024
4099
|
- title: config
|
@@ -4227,4 +4302,4 @@ interpolation:
|
|
4227
4302
|
regex: The regular expression to search for. It must include a capture group.
|
4228
4303
|
return_type: str
|
4229
4304
|
examples:
|
4230
|
-
- '{{ "goodbye, cruel world" | regex_search("goodbye,\s(.*)$") }} -> "cruel world"'
|
4305
|
+
- '{{ "goodbye, cruel world" | regex_search("goodbye,\s(.*)$") }} -> "cruel world"'
|
@@ -4,8 +4,11 @@
|
|
4
4
|
|
5
5
|
import logging
|
6
6
|
from abc import abstractmethod
|
7
|
-
from typing import Any, Mapping, Tuple
|
7
|
+
from typing import Any, List, Mapping, Tuple
|
8
8
|
|
9
|
+
from airbyte_cdk.connector_builder.models import (
|
10
|
+
LogMessage as ConnectorBuilderLogMessage,
|
11
|
+
)
|
9
12
|
from airbyte_cdk.sources.abstract_source import AbstractSource
|
10
13
|
from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
|
11
14
|
|
@@ -34,3 +37,9 @@ class DeclarativeSource(AbstractSource):
|
|
34
37
|
The error object will be cast to string to display the problem to the user.
|
35
38
|
"""
|
36
39
|
return self.connection_checker.check_connection(self, logger, config)
|
40
|
+
|
41
|
+
def deprecation_warnings(self) -> List[ConnectorBuilderLogMessage]:
|
42
|
+
"""
|
43
|
+
Returns a list of deprecation warnings for the source.
|
44
|
+
"""
|
45
|
+
return []
|
@@ -12,7 +12,7 @@ from airbyte_cdk.sources.types import Config
|
|
12
12
|
NestedMappingEntry = Union[
|
13
13
|
dict[str, "NestedMapping"], list["NestedMapping"], str, int, float, bool, None
|
14
14
|
]
|
15
|
-
NestedMapping = Union[dict[str, NestedMappingEntry], str]
|
15
|
+
NestedMapping = Union[dict[str, NestedMappingEntry], str, dict[str, Any]]
|
16
16
|
|
17
17
|
|
18
18
|
@dataclass
|
@@ -15,6 +15,9 @@ from jsonschema.exceptions import ValidationError
|
|
15
15
|
from jsonschema.validators import validate
|
16
16
|
from packaging.version import InvalidVersion, Version
|
17
17
|
|
18
|
+
from airbyte_cdk.connector_builder.models import (
|
19
|
+
LogMessage as ConnectorBuilderLogMessage,
|
20
|
+
)
|
18
21
|
from airbyte_cdk.manifest_migrations.migration_handler import (
|
19
22
|
ManifestMigrationHandler,
|
20
23
|
)
|
@@ -230,6 +233,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
|
|
230
233
|
with_dynamic_stream_name=True,
|
231
234
|
)
|
232
235
|
|
236
|
+
def deprecation_warnings(self) -> List[ConnectorBuilderLogMessage]:
|
237
|
+
return self._constructor.get_model_deprecations()
|
238
|
+
|
233
239
|
@property
|
234
240
|
def connection_checker(self) -> ConnectionChecker:
|
235
241
|
check = self._source_config["check"]
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
|
2
|
+
|
3
|
+
# THIS IS A STATIC CLASS MODEL USED TO DISPLAY DEPRECATION WARNINGS
|
4
|
+
# WHEN DEPRECATED FIELDS ARE ACCESSED
|
5
|
+
|
6
|
+
import warnings
|
7
|
+
from typing import Any, List
|
8
|
+
|
9
|
+
from pydantic.v1 import BaseModel
|
10
|
+
|
11
|
+
from airbyte_cdk.connector_builder.models import LogMessage as ConnectorBuilderLogMessage
|
12
|
+
|
13
|
+
# format the warning message
|
14
|
+
warnings.formatwarning = (
|
15
|
+
lambda message, category, *args, **kwargs: f"{category.__name__}: {message}"
|
16
|
+
)
|
17
|
+
|
18
|
+
FIELDS_TAG = "__fields__"
|
19
|
+
DEPRECATED = "deprecated"
|
20
|
+
DEPRECATION_MESSAGE = "deprecation_message"
|
21
|
+
DEPRECATION_LOGS_TAG = "_deprecation_logs"
|
22
|
+
|
23
|
+
|
24
|
+
class BaseModelWithDeprecations(BaseModel):
|
25
|
+
"""
|
26
|
+
Pydantic BaseModel that warns when deprecated fields are accessed.
|
27
|
+
The deprecation message is stored in the field's extra attributes.
|
28
|
+
This class is used to create models that can have deprecated fields
|
29
|
+
and show warnings when those fields are accessed or initialized.
|
30
|
+
|
31
|
+
The `_deprecation_logs` attribute is stored in the model itself.
|
32
|
+
The collected deprecation warnings are further propagated to the Airbyte log messages,
|
33
|
+
during the component creation process, in `model_to_component._collect_model_deprecations()`.
|
34
|
+
|
35
|
+
The component implementation is not responsible for handling the deprecation warnings,
|
36
|
+
since the deprecation warnings are already handled in the model itself.
|
37
|
+
"""
|
38
|
+
|
39
|
+
class Config:
|
40
|
+
"""
|
41
|
+
Allow extra fields in the model. In case the model restricts extra fields.
|
42
|
+
"""
|
43
|
+
|
44
|
+
extra = "allow"
|
45
|
+
|
46
|
+
def __init__(self, **model_fields: Any) -> None:
|
47
|
+
"""
|
48
|
+
Show warnings for deprecated fields during component initialization.
|
49
|
+
"""
|
50
|
+
# call the parent constructor first to initialize Pydantic internals
|
51
|
+
super().__init__(**model_fields)
|
52
|
+
# set the placeholder for the default deprecation messages
|
53
|
+
self._default_deprecation_messages: List[str] = []
|
54
|
+
# set the placeholder for the deprecation logs
|
55
|
+
self._deprecation_logs: List[ConnectorBuilderLogMessage] = []
|
56
|
+
# process deprecated fields, if present
|
57
|
+
self._process_fields(model_fields)
|
58
|
+
# emit default deprecation messages
|
59
|
+
self._emit_default_deprecation_messages()
|
60
|
+
# set the deprecation logs attribute to the model
|
61
|
+
self._set_deprecation_logs_attr_to_model()
|
62
|
+
|
63
|
+
def _is_deprecated_field(self, field_name: str) -> bool:
|
64
|
+
return (
|
65
|
+
self.__fields__[field_name].field_info.extra.get(DEPRECATED, False)
|
66
|
+
if field_name in self.__fields__.keys()
|
67
|
+
else False
|
68
|
+
)
|
69
|
+
|
70
|
+
def _get_deprecation_message(self, field_name: str) -> str:
|
71
|
+
return (
|
72
|
+
self.__fields__[field_name].field_info.extra.get(
|
73
|
+
DEPRECATION_MESSAGE, "<missing_deprecation_message>"
|
74
|
+
)
|
75
|
+
if field_name in self.__fields__.keys()
|
76
|
+
else "<missing_deprecation_message>"
|
77
|
+
)
|
78
|
+
|
79
|
+
def _process_fields(self, model_fields: Any) -> None:
|
80
|
+
"""
|
81
|
+
Processes the fields in the provided model data, checking for deprecated fields.
|
82
|
+
|
83
|
+
For each field in the input `model_fields`, this method checks if the field exists in the model's defined fields.
|
84
|
+
If the field is marked as deprecated (using the `DEPRECATED` flag in its metadata), it triggers a deprecation warning
|
85
|
+
by calling the `_create_warning` method with the field name and an optional deprecation message.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
model_fields (Any): The data containing fields to be processed.
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
None
|
92
|
+
"""
|
93
|
+
|
94
|
+
if hasattr(self, FIELDS_TAG):
|
95
|
+
for field_name in model_fields.keys():
|
96
|
+
if self._is_deprecated_field(field_name):
|
97
|
+
self._create_warning(
|
98
|
+
field_name,
|
99
|
+
self._get_deprecation_message(field_name),
|
100
|
+
)
|
101
|
+
|
102
|
+
def _set_deprecation_logs_attr_to_model(self) -> None:
|
103
|
+
"""
|
104
|
+
Sets the deprecation logs attribute on the model instance.
|
105
|
+
|
106
|
+
This method attaches the current instance's deprecation logs to the model by setting
|
107
|
+
an attribute named by `DEPRECATION_LOGS_TAG` to the value of `self._deprecation_logs`.
|
108
|
+
This is typically used to track or log deprecated features or configurations within the model.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
None
|
112
|
+
"""
|
113
|
+
setattr(self, DEPRECATION_LOGS_TAG, self._deprecation_logs)
|
114
|
+
|
115
|
+
def _create_warning(self, field_name: str, message: str) -> None:
|
116
|
+
"""
|
117
|
+
Show a warning message for deprecated fields (to stdout).
|
118
|
+
Args:
|
119
|
+
field_name (str): Name of the deprecated field.
|
120
|
+
message (str): Warning message to be displayed.
|
121
|
+
"""
|
122
|
+
|
123
|
+
deprecated_message = f"Component type: `{self.__class__.__name__}`. Field '{field_name}' is deprecated. {message}"
|
124
|
+
|
125
|
+
if deprecated_message not in self._default_deprecation_messages:
|
126
|
+
# Avoid duplicates in the default deprecation messages
|
127
|
+
self._default_deprecation_messages.append(deprecated_message)
|
128
|
+
|
129
|
+
# Create an Airbyte deprecation log message
|
130
|
+
deprecation_log_message = ConnectorBuilderLogMessage(
|
131
|
+
level="WARN", message=deprecated_message
|
132
|
+
)
|
133
|
+
# Add the deprecation message to the Airbyte log messages,
|
134
|
+
# this logs are displayed in the Connector Builder.
|
135
|
+
if deprecation_log_message not in self._deprecation_logs:
|
136
|
+
# Avoid duplicates in the deprecation logs
|
137
|
+
self._deprecation_logs.append(deprecation_log_message)
|
138
|
+
|
139
|
+
def _emit_default_deprecation_messages(self) -> None:
|
140
|
+
"""
|
141
|
+
Emit default deprecation messages for deprecated fields to STDOUT.
|
142
|
+
"""
|
143
|
+
for message in self._default_deprecation_messages:
|
144
|
+
warnings.warn(message, DeprecationWarning)
|
@@ -10,6 +10,10 @@ from typing import Any, Dict, List, Literal, Optional, Union
|
|
10
10
|
|
11
11
|
from pydantic.v1 import BaseModel, Extra, Field
|
12
12
|
|
13
|
+
from airbyte_cdk.sources.declarative.models.base_model_with_deprecations import (
|
14
|
+
BaseModelWithDeprecations,
|
15
|
+
)
|
16
|
+
|
13
17
|
|
14
18
|
class AuthFlowType(Enum):
|
15
19
|
oauth2_0 = "oauth2.0"
|
@@ -1497,6 +1501,11 @@ class ConfigComponentsResolver(BaseModel):
|
|
1497
1501
|
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
1498
1502
|
|
1499
1503
|
|
1504
|
+
class RequestBody(BaseModel):
|
1505
|
+
type: Optional[Union[Literal["RequestBodyData"], Literal["RequestBodyJson"]]] = None
|
1506
|
+
value: Optional[Union[str, Dict[str, str], Dict[str, Any]]] = None
|
1507
|
+
|
1508
|
+
|
1500
1509
|
class AddedFieldDefinition(BaseModel):
|
1501
1510
|
type: Literal["AddedFieldDefinition"]
|
1502
1511
|
path: List[str] = Field(
|
@@ -2207,11 +2216,13 @@ class SessionTokenAuthenticator(BaseModel):
|
|
2207
2216
|
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
2208
2217
|
|
2209
2218
|
|
2210
|
-
class HttpRequester(
|
2219
|
+
class HttpRequester(BaseModelWithDeprecations):
|
2211
2220
|
type: Literal["HttpRequester"]
|
2212
|
-
url_base: str = Field(
|
2213
|
-
|
2214
|
-
|
2221
|
+
url_base: Optional[str] = Field(
|
2222
|
+
None,
|
2223
|
+
deprecated=True,
|
2224
|
+
deprecation_message="Use `url` field instead.",
|
2225
|
+
description="Deprecated, use the `url` instead. Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
|
2215
2226
|
examples=[
|
2216
2227
|
"https://connect.squareup.com/v2",
|
2217
2228
|
"{{ config['base_url'] or 'https://app.posthog.com'}}/api",
|
@@ -2220,9 +2231,22 @@ class HttpRequester(BaseModel):
|
|
2220
2231
|
],
|
2221
2232
|
title="API Base URL",
|
2222
2233
|
)
|
2234
|
+
url: Optional[str] = Field(
|
2235
|
+
None,
|
2236
|
+
description="The URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
|
2237
|
+
examples=[
|
2238
|
+
"https://connect.squareup.com/v2",
|
2239
|
+
"{{ config['url'] or 'https://app.posthog.com'}}/api",
|
2240
|
+
"https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups",
|
2241
|
+
"https://example.com/api/v1/resource/{{ next_page_token['id'] }}",
|
2242
|
+
],
|
2243
|
+
title="The URL of an API endpoint",
|
2244
|
+
)
|
2223
2245
|
path: Optional[str] = Field(
|
2224
2246
|
None,
|
2225
|
-
|
2247
|
+
deprecated=True,
|
2248
|
+
deprecation_message="Use `url` field instead.",
|
2249
|
+
description="Deprecated, use the `url` instead. Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
|
2226
2250
|
examples=[
|
2227
2251
|
"/products",
|
2228
2252
|
"/quotes/{{ stream_partition['id'] }}/quote_line_groups",
|
@@ -2261,6 +2285,8 @@ class HttpRequester(BaseModel):
|
|
2261
2285
|
)
|
2262
2286
|
request_body_data: Optional[Union[Dict[str, str], str]] = Field(
|
2263
2287
|
None,
|
2288
|
+
deprecated=True,
|
2289
|
+
deprecation_message="Use `request_body` field instead.",
|
2264
2290
|
description="Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.",
|
2265
2291
|
examples=[
|
2266
2292
|
'[{"clause": {"type": "timestamp", "operator": 10, "parameters":\n [{"value": {{ stream_interval[\'start_time\'] | int * 1000 }} }]\n }, "orderBy": 1, "columnName": "Timestamp"}]/\n'
|
@@ -2269,6 +2295,8 @@ class HttpRequester(BaseModel):
|
|
2269
2295
|
)
|
2270
2296
|
request_body_json: Optional[Union[Dict[str, Any], str]] = Field(
|
2271
2297
|
None,
|
2298
|
+
deprecated=True,
|
2299
|
+
deprecation_message="Use `request_body` field instead.",
|
2272
2300
|
description="Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.",
|
2273
2301
|
examples=[
|
2274
2302
|
{"sort_order": "ASC", "sort_field": "CREATED_AT"},
|
@@ -2277,6 +2305,27 @@ class HttpRequester(BaseModel):
|
|
2277
2305
|
],
|
2278
2306
|
title="Request Body JSON Payload",
|
2279
2307
|
)
|
2308
|
+
request_body: Optional[RequestBody] = Field(
|
2309
|
+
None,
|
2310
|
+
description="Specifies how to populate the body of the request with a payload. Can contain nested objects.",
|
2311
|
+
examples=[
|
2312
|
+
{
|
2313
|
+
"type": "RequestBodyJson",
|
2314
|
+
"value": {"sort_order": "ASC", "sort_field": "CREATED_AT"},
|
2315
|
+
},
|
2316
|
+
{"type": "RequestBodyJson", "value": {"key": "{{ config['value'] }}"}},
|
2317
|
+
{
|
2318
|
+
"type": "RequestBodyJson",
|
2319
|
+
"value": {"sort": {"field": "updated_at", "order": "ascending"}},
|
2320
|
+
},
|
2321
|
+
{"type": "RequestBodyData", "value": "plain_text_body"},
|
2322
|
+
{
|
2323
|
+
"type": "RequestBodyData",
|
2324
|
+
"value": {"param1": "value1", "param2": "{{ config['param2_value'] }}"},
|
2325
|
+
},
|
2326
|
+
],
|
2327
|
+
title="Request Body Payload to be send as a part of the API request.",
|
2328
|
+
)
|
2280
2329
|
request_headers: Optional[Union[Dict[str, str], str]] = Field(
|
2281
2330
|
None,
|
2282
2331
|
description="Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.",
|
@@ -27,6 +27,9 @@ from typing import (
|
|
27
27
|
from isodate import parse_duration
|
28
28
|
from pydantic.v1 import BaseModel
|
29
29
|
|
30
|
+
from airbyte_cdk.connector_builder.models import (
|
31
|
+
LogMessage as ConnectorBuilderLogMessage,
|
32
|
+
)
|
30
33
|
from airbyte_cdk.models import FailureType, Level
|
31
34
|
from airbyte_cdk.sources.connector_state_manager import ConnectorStateManager
|
32
35
|
from airbyte_cdk.sources.declarative.async_job.job_orchestrator import AsyncJobOrchestrator
|
@@ -107,6 +110,10 @@ from airbyte_cdk.sources.declarative.migrations.legacy_to_per_partition_state_mi
|
|
107
110
|
from airbyte_cdk.sources.declarative.models import (
|
108
111
|
CustomStateMigration,
|
109
112
|
)
|
113
|
+
from airbyte_cdk.sources.declarative.models.base_model_with_deprecations import (
|
114
|
+
DEPRECATION_LOGS_TAG,
|
115
|
+
BaseModelWithDeprecations,
|
116
|
+
)
|
110
117
|
from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
|
111
118
|
AddedFieldDefinition as AddedFieldDefinitionModel,
|
112
119
|
)
|
@@ -593,6 +600,8 @@ class ModelToComponentFactory:
|
|
593
600
|
self._connector_state_manager = connector_state_manager or ConnectorStateManager()
|
594
601
|
self._api_budget: Optional[Union[APIBudget, HttpAPIBudget]] = None
|
595
602
|
self._job_tracker: JobTracker = JobTracker(max_concurrent_async_job_count or 1)
|
603
|
+
# placeholder for deprecation warnings
|
604
|
+
self._collected_deprecation_logs: List[ConnectorBuilderLogMessage] = []
|
596
605
|
|
597
606
|
def _init_mappings(self) -> None:
|
598
607
|
self.PYDANTIC_MODEL_TO_CONSTRUCTOR: Mapping[Type[BaseModel], Callable[..., Any]] = {
|
@@ -740,8 +749,34 @@ class ModelToComponentFactory:
|
|
740
749
|
component_constructor = self.PYDANTIC_MODEL_TO_CONSTRUCTOR.get(model.__class__)
|
741
750
|
if not component_constructor:
|
742
751
|
raise ValueError(f"Could not find constructor for {model.__class__}")
|
752
|
+
|
753
|
+
# collect deprecation warnings for supported models.
|
754
|
+
if isinstance(model, BaseModelWithDeprecations):
|
755
|
+
self._collect_model_deprecations(model)
|
756
|
+
|
743
757
|
return component_constructor(model=model, config=config, **kwargs)
|
744
758
|
|
759
|
+
def get_model_deprecations(self) -> List[ConnectorBuilderLogMessage]:
|
760
|
+
"""
|
761
|
+
Returns the deprecation warnings that were collected during the creation of components.
|
762
|
+
"""
|
763
|
+
return self._collected_deprecation_logs
|
764
|
+
|
765
|
+
def _collect_model_deprecations(self, model: BaseModelWithDeprecations) -> None:
|
766
|
+
"""
|
767
|
+
Collects deprecation logs from the given model and appends any new logs to the internal collection.
|
768
|
+
|
769
|
+
This method checks if the provided model has deprecation logs (identified by the presence of the DEPRECATION_LOGS_TAG attribute and a non-None `_deprecation_logs` property). It iterates through each deprecation log in the model and appends it to the `_collected_deprecation_logs` list if it has not already been collected, ensuring that duplicate logs are avoided.
|
770
|
+
|
771
|
+
Args:
|
772
|
+
model (BaseModelWithDeprecations): The model instance from which to collect deprecation logs.
|
773
|
+
"""
|
774
|
+
if hasattr(model, DEPRECATION_LOGS_TAG) and model._deprecation_logs is not None:
|
775
|
+
for log in model._deprecation_logs:
|
776
|
+
# avoid duplicates for deprecation logs observed.
|
777
|
+
if log not in self._collected_deprecation_logs:
|
778
|
+
self._collected_deprecation_logs.append(log)
|
779
|
+
|
745
780
|
@staticmethod
|
746
781
|
def create_added_field_definition(
|
747
782
|
model: AddedFieldDefinitionModel, config: Config, **kwargs: Any
|
@@ -2180,7 +2215,7 @@ class ModelToComponentFactory:
|
|
2180
2215
|
self._create_component_from_model(
|
2181
2216
|
model=model.authenticator,
|
2182
2217
|
config=config,
|
2183
|
-
url_base=model.url_base,
|
2218
|
+
url_base=model.url or model.url_base,
|
2184
2219
|
name=name,
|
2185
2220
|
decoder=decoder,
|
2186
2221
|
)
|
@@ -2210,6 +2245,7 @@ class ModelToComponentFactory:
|
|
2210
2245
|
request_parameters = model.request_parameters
|
2211
2246
|
|
2212
2247
|
request_options_provider = InterpolatedRequestOptionsProvider(
|
2248
|
+
request_body=model.request_body,
|
2213
2249
|
request_body_data=model.request_body_data,
|
2214
2250
|
request_body_json=model.request_body_json,
|
2215
2251
|
request_headers=model.request_headers,
|
@@ -2226,6 +2262,7 @@ class ModelToComponentFactory:
|
|
2226
2262
|
|
2227
2263
|
return HttpRequester(
|
2228
2264
|
name=name,
|
2265
|
+
url=model.url,
|
2229
2266
|
url_base=model.url_base,
|
2230
2267
|
path=model.path,
|
2231
2268
|
authenticator=authenticator,
|
@@ -2934,6 +2971,25 @@ class ModelToComponentFactory:
|
|
2934
2971
|
use_cache: Optional[bool] = None,
|
2935
2972
|
**kwargs: Any,
|
2936
2973
|
) -> SimpleRetriever:
|
2974
|
+
def _get_url() -> str:
|
2975
|
+
"""
|
2976
|
+
Closure to get the URL from the requester. This is used to get the URL in the case of a lazy retriever.
|
2977
|
+
This is needed because the URL is not set until the requester is created.
|
2978
|
+
"""
|
2979
|
+
|
2980
|
+
_url = (
|
2981
|
+
model.requester.url
|
2982
|
+
if hasattr(model.requester, "url") and model.requester.url is not None
|
2983
|
+
else requester.get_url()
|
2984
|
+
)
|
2985
|
+
_url_base = (
|
2986
|
+
model.requester.url_base
|
2987
|
+
if hasattr(model.requester, "url_base") and model.requester.url_base is not None
|
2988
|
+
else requester.get_url_base()
|
2989
|
+
)
|
2990
|
+
|
2991
|
+
return _url or _url_base
|
2992
|
+
|
2937
2993
|
decoder = (
|
2938
2994
|
self._create_component_from_model(model=model.decoder, config=config)
|
2939
2995
|
if model.decoder
|
@@ -3001,11 +3057,6 @@ class ModelToComponentFactory:
|
|
3001
3057
|
use_cache=use_cache,
|
3002
3058
|
config=config,
|
3003
3059
|
)
|
3004
|
-
url_base = (
|
3005
|
-
model.requester.url_base
|
3006
|
-
if hasattr(model.requester, "url_base")
|
3007
|
-
else requester.get_url_base()
|
3008
|
-
)
|
3009
3060
|
|
3010
3061
|
# Define cursor only if per partition or common incremental support is needed
|
3011
3062
|
cursor = stream_slicer if isinstance(stream_slicer, DeclarativeCursor) else None
|
@@ -3029,7 +3080,7 @@ class ModelToComponentFactory:
|
|
3029
3080
|
self._create_component_from_model(
|
3030
3081
|
model=model.paginator,
|
3031
3082
|
config=config,
|
3032
|
-
url_base=
|
3083
|
+
url_base=_get_url(),
|
3033
3084
|
extractor_model=model.record_selector.extractor,
|
3034
3085
|
decoder=decoder,
|
3035
3086
|
cursor_used_for_stop_condition=cursor_used_for_stop_condition,
|
@@ -3,7 +3,6 @@
|
|
3
3
|
#
|
4
4
|
|
5
5
|
import logging
|
6
|
-
import os
|
7
6
|
from dataclasses import InitVar, dataclass, field
|
8
7
|
from typing import Any, Callable, Mapping, MutableMapping, Optional, Union
|
9
8
|
from urllib.parse import urljoin
|
@@ -53,10 +52,11 @@ class HttpRequester(Requester):
|
|
53
52
|
"""
|
54
53
|
|
55
54
|
name: str
|
56
|
-
url_base: Union[InterpolatedString, str]
|
57
55
|
config: Config
|
58
56
|
parameters: InitVar[Mapping[str, Any]]
|
59
57
|
|
58
|
+
url: Optional[Union[InterpolatedString, str]] = None
|
59
|
+
url_base: Optional[Union[InterpolatedString, str]] = None
|
60
60
|
path: Optional[Union[InterpolatedString, str]] = None
|
61
61
|
authenticator: Optional[DeclarativeAuthenticator] = None
|
62
62
|
http_method: Union[str, HttpMethod] = HttpMethod.GET
|
@@ -71,7 +71,14 @@ class HttpRequester(Requester):
|
|
71
71
|
decoder: Decoder = field(default_factory=lambda: JsonDecoder(parameters={}))
|
72
72
|
|
73
73
|
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
74
|
-
self.
|
74
|
+
self._url = InterpolatedString.create(
|
75
|
+
self.url if self.url else EmptyString, parameters=parameters
|
76
|
+
)
|
77
|
+
# deprecated
|
78
|
+
self._url_base = InterpolatedString.create(
|
79
|
+
self.url_base if self.url_base else EmptyString, parameters=parameters
|
80
|
+
)
|
81
|
+
# deprecated
|
75
82
|
self._path = InterpolatedString.create(
|
76
83
|
self.path if self.path else EmptyString, parameters=parameters
|
77
84
|
)
|
@@ -120,6 +127,51 @@ class HttpRequester(Requester):
|
|
120
127
|
def get_authenticator(self) -> DeclarativeAuthenticator:
|
121
128
|
return self._authenticator
|
122
129
|
|
130
|
+
def get_url(
|
131
|
+
self,
|
132
|
+
*,
|
133
|
+
stream_state: Optional[StreamState] = None,
|
134
|
+
stream_slice: Optional[StreamSlice] = None,
|
135
|
+
next_page_token: Optional[Mapping[str, Any]] = None,
|
136
|
+
) -> str:
|
137
|
+
interpolation_context = get_interpolation_context(
|
138
|
+
stream_state=stream_state,
|
139
|
+
stream_slice=stream_slice,
|
140
|
+
next_page_token=next_page_token,
|
141
|
+
)
|
142
|
+
|
143
|
+
return str(self._url.eval(self.config, **interpolation_context))
|
144
|
+
|
145
|
+
def _get_url(
|
146
|
+
self,
|
147
|
+
*,
|
148
|
+
path: Optional[str] = None,
|
149
|
+
stream_state: Optional[StreamState] = None,
|
150
|
+
stream_slice: Optional[StreamSlice] = None,
|
151
|
+
next_page_token: Optional[Mapping[str, Any]] = None,
|
152
|
+
) -> str:
|
153
|
+
url = self.get_url(
|
154
|
+
stream_state=stream_state,
|
155
|
+
stream_slice=stream_slice,
|
156
|
+
next_page_token=next_page_token,
|
157
|
+
)
|
158
|
+
|
159
|
+
url_base = self.get_url_base(
|
160
|
+
stream_state=stream_state,
|
161
|
+
stream_slice=stream_slice,
|
162
|
+
next_page_token=next_page_token,
|
163
|
+
)
|
164
|
+
|
165
|
+
path = path or self.get_path(
|
166
|
+
stream_state=stream_state,
|
167
|
+
stream_slice=stream_slice,
|
168
|
+
next_page_token=next_page_token,
|
169
|
+
)
|
170
|
+
|
171
|
+
full_url = self._join_url(url_base, path) if url_base else url + path if path else url
|
172
|
+
|
173
|
+
return full_url
|
174
|
+
|
123
175
|
def get_url_base(
|
124
176
|
self,
|
125
177
|
*,
|
@@ -349,7 +401,7 @@ class HttpRequester(Requester):
|
|
349
401
|
return options
|
350
402
|
|
351
403
|
@classmethod
|
352
|
-
def _join_url(cls, url_base: str, path: str) -> str:
|
404
|
+
def _join_url(cls, url_base: str, path: Optional[str] = None) -> str:
|
353
405
|
"""
|
354
406
|
Joins a base URL with a given path and returns the resulting URL with any trailing slash removed.
|
355
407
|
|
@@ -358,7 +410,7 @@ class HttpRequester(Requester):
|
|
358
410
|
|
359
411
|
Args:
|
360
412
|
url_base (str): The base URL to which the path will be appended.
|
361
|
-
path (str): The path to join with the base URL.
|
413
|
+
path (Optional[str]): The path to join with the base URL.
|
362
414
|
|
363
415
|
Returns:
|
364
416
|
str: The resulting joined URL.
|
@@ -399,18 +451,11 @@ class HttpRequester(Requester):
|
|
399
451
|
) -> Optional[requests.Response]:
|
400
452
|
request, response = self._http_client.send_request(
|
401
453
|
http_method=self.get_method().value,
|
402
|
-
url=self.
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
),
|
408
|
-
path
|
409
|
-
or self.get_path(
|
410
|
-
stream_state=stream_state,
|
411
|
-
stream_slice=stream_slice,
|
412
|
-
next_page_token=next_page_token,
|
413
|
-
),
|
454
|
+
url=self._get_url(
|
455
|
+
path=path,
|
456
|
+
stream_state=stream_state,
|
457
|
+
stream_slice=stream_slice,
|
458
|
+
next_page_token=next_page_token,
|
414
459
|
),
|
415
460
|
request_kwargs={"stream": self.stream_response},
|
416
461
|
headers=self._request_headers(
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py
CHANGED
@@ -6,6 +6,9 @@ from dataclasses import InitVar, dataclass, field
|
|
6
6
|
from typing import Any, List, Mapping, MutableMapping, Optional, Union
|
7
7
|
|
8
8
|
from airbyte_cdk.sources.declarative.interpolation.interpolated_nested_mapping import NestedMapping
|
9
|
+
from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
|
10
|
+
RequestBody,
|
11
|
+
)
|
9
12
|
from airbyte_cdk.sources.declarative.requesters.request_options.interpolated_nested_request_input_provider import (
|
10
13
|
InterpolatedNestedRequestInputProvider,
|
11
14
|
)
|
@@ -38,6 +41,7 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
38
41
|
config: Config = field(default_factory=dict)
|
39
42
|
request_parameters: Optional[RequestInput] = None
|
40
43
|
request_headers: Optional[RequestInput] = None
|
44
|
+
request_body: Optional[RequestBody] = None
|
41
45
|
request_body_data: Optional[RequestInput] = None
|
42
46
|
request_body_json: Optional[NestedMapping] = None
|
43
47
|
query_properties_key: Optional[str] = None
|
@@ -47,16 +51,19 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
47
51
|
self.request_parameters = {}
|
48
52
|
if self.request_headers is None:
|
49
53
|
self.request_headers = {}
|
54
|
+
# resolve the request body to either data or json
|
55
|
+
self._resolve_request_body()
|
56
|
+
# If request_body is not provided, set request_body_data and request_body_json to empty dicts
|
50
57
|
if self.request_body_data is None:
|
51
58
|
self.request_body_data = {}
|
52
59
|
if self.request_body_json is None:
|
53
60
|
self.request_body_json = {}
|
54
|
-
|
61
|
+
# If both request_body_data and request_body_json are provided, raise an error
|
55
62
|
if self.request_body_json and self.request_body_data:
|
56
63
|
raise ValueError(
|
57
64
|
"RequestOptionsProvider should only contain either 'request_body_data' or 'request_body_json' not both"
|
58
65
|
)
|
59
|
-
|
66
|
+
# set interpolators
|
60
67
|
self._parameter_interpolator = InterpolatedRequestInputProvider(
|
61
68
|
config=self.config, request_inputs=self.request_parameters, parameters=parameters
|
62
69
|
)
|
@@ -70,6 +77,21 @@ class InterpolatedRequestOptionsProvider(RequestOptionsProvider):
|
|
70
77
|
config=self.config, request_inputs=self.request_body_json, parameters=parameters
|
71
78
|
)
|
72
79
|
|
80
|
+
def _resolve_request_body(self) -> None:
|
81
|
+
"""
|
82
|
+
Resolves the request body configuration by setting either `request_body_data` or `request_body_json`
|
83
|
+
based on the type specified in `self.request_body`. If neither is provided, both are initialized as empty
|
84
|
+
dictionaries. Raises a ValueError if both `request_body_data` and `request_body_json` are set simultaneously.
|
85
|
+
Raises:
|
86
|
+
ValueError: If both `request_body_data` and `request_body_json` are provided.
|
87
|
+
"""
|
88
|
+
# Resolve the request body to either data or json
|
89
|
+
if self.request_body is not None and self.request_body.type is not None:
|
90
|
+
if self.request_body.type == "RequestBodyData":
|
91
|
+
self.request_body_data = self.request_body.value
|
92
|
+
elif self.request_body.type == "RequestBodyJson":
|
93
|
+
self.request_body_json = self.request_body.value
|
94
|
+
|
73
95
|
def get_request_params(
|
74
96
|
self,
|
75
97
|
*,
|
@@ -34,6 +34,18 @@ class Requester(RequestOptionsProvider):
|
|
34
34
|
"""
|
35
35
|
pass
|
36
36
|
|
37
|
+
@abstractmethod
|
38
|
+
def get_url(
|
39
|
+
self,
|
40
|
+
*,
|
41
|
+
stream_state: Optional[StreamState],
|
42
|
+
stream_slice: Optional[StreamSlice],
|
43
|
+
next_page_token: Optional[Mapping[str, Any]],
|
44
|
+
) -> str:
|
45
|
+
"""
|
46
|
+
:return: URL base for the API endpoint e.g: if you wanted to hit https://myapi.com/v1/some_entity then this should return "https://myapi.com/v1/"
|
47
|
+
"""
|
48
|
+
|
37
49
|
@abstractmethod
|
38
50
|
def get_url_base(
|
39
51
|
self,
|
@@ -20,7 +20,7 @@ airbyte_cdk/connector_builder/models.py,sha256=9pIZ98LW_d6fRS39VdnUOf3cxGt4TkC5M
|
|
20
20
|
airbyte_cdk/connector_builder/test_reader/__init__.py,sha256=iTwBMoI9vaJotEgpqZbFjlxRcbxXYypSVJ9YxeHk7wc,120
|
21
21
|
airbyte_cdk/connector_builder/test_reader/helpers.py,sha256=Iczn-_iczS2CaIAunWwyFcX0uLTra8Wh9JVfzm1Gfxo,26765
|
22
22
|
airbyte_cdk/connector_builder/test_reader/message_grouper.py,sha256=84BAEPIBHMq3WCfO14WNvh_q7OsjGgDt0q1FTu8eW-w,6918
|
23
|
-
airbyte_cdk/connector_builder/test_reader/reader.py,sha256=
|
23
|
+
airbyte_cdk/connector_builder/test_reader/reader.py,sha256=mP1yHK5vG38KxoKoT2QQ7ZNbkdLA1rMAU3EKpucjHls,21098
|
24
24
|
airbyte_cdk/connector_builder/test_reader/types.py,sha256=hPZG3jO03kBaPyW94NI3JHRS1jxXGSNBcN1HFzOxo5Y,2528
|
25
25
|
airbyte_cdk/destinations/__init__.py,sha256=FyDp28PT_YceJD5HDFhA-mrGfX9AONIyMQ4d68CHNxQ,213
|
26
26
|
airbyte_cdk/destinations/destination.py,sha256=CIq-yb8C_0QvcKCtmStaHfiqn53GEfRAIGGCkJhKP1Q,5880
|
@@ -45,7 +45,7 @@ airbyte_cdk/manifest_migrations/migrations/__init__.py,sha256=SJ7imfOgCRYOVaFkW2
|
|
45
45
|
airbyte_cdk/manifest_migrations/migrations/http_requester_path_to_url.py,sha256=IIn2SjRh1v2yaSBFUCDyBHpX6mBhlckhvbsSg55mREI,2153
|
46
46
|
airbyte_cdk/manifest_migrations/migrations/http_requester_request_body_json_data_to_request_body.py,sha256=70md8yDu8SWl2JkkFcEs8kyXUbP0F_obIzyHsygyR9k,1777
|
47
47
|
airbyte_cdk/manifest_migrations/migrations/http_requester_url_base_to_url.py,sha256=EX1MVYVpoWypA28qoH48wA0SYZjGdlR8bcSixTDzfgo,1346
|
48
|
-
airbyte_cdk/manifest_migrations/migrations/registry.yaml,sha256=
|
48
|
+
airbyte_cdk/manifest_migrations/migrations/registry.yaml,sha256=pMG4JzHQyxvTjxhTZpzUXHb0BhwkY7w_6CtTwaUZ_K0,960
|
49
49
|
airbyte_cdk/manifest_migrations/migrations_registry.py,sha256=zly2fwaOxDukqC7eowzrDlvhA2v71FjW74kDzvRXhSY,2619
|
50
50
|
airbyte_cdk/models/__init__.py,sha256=Et9wJWs5VOWynGbb-3aJRhsdAHAiLkNNLxdwqJAuqkw,2114
|
51
51
|
airbyte_cdk/models/airbyte_protocol.py,sha256=oZdKsZ7yPjUt9hvxdWNpxCtgjSV2RWhf4R9Np03sqyY,3613
|
@@ -89,8 +89,8 @@ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=GoZJ8Oxb
|
|
89
89
|
airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
|
90
90
|
airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=_zGNGq31RNy_0QBLt_EcTvgPyhj7urPdx6oA3M5-r3o,3150
|
91
91
|
airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
|
92
|
-
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=
|
93
|
-
airbyte_cdk/sources/declarative/declarative_source.py,sha256=
|
92
|
+
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=C_hjPvQHfNGNTt2rXp9nCl8T_tPZBoPx0D5yEBi6ZWg,165127
|
93
|
+
airbyte_cdk/sources/declarative/declarative_source.py,sha256=qmyMnnet92eGc3C22yBtpvD5UZjqdhsAafP_zxI5wp8,1814
|
94
94
|
airbyte_cdk/sources/declarative/declarative_stream.py,sha256=dCRlddBUSaJmBNBz1pSO1r2rTw8AP5d2_vlmIeGs2gg,10767
|
95
95
|
airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=JHb_0d3SE6kNY10mxA5YBEKPeSbsWYjByq1gUQxepoE,953
|
96
96
|
airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py,sha256=Jd7URkDQBoHSDQHQuYUqzeex1HYfLRtGcY_-dVW33pA,7884
|
@@ -122,24 +122,25 @@ airbyte_cdk/sources/declarative/interpolation/__init__.py,sha256=Kh7FxhfetyNVDnA
|
|
122
122
|
airbyte_cdk/sources/declarative/interpolation/filters.py,sha256=cYap5zzOxIJWCLIfbkNlpyfUhjZ8FklLroIG4WGzYVs,5537
|
123
123
|
airbyte_cdk/sources/declarative/interpolation/interpolated_boolean.py,sha256=8F3ntT_Mfo8cO9n6dCq8rTfJIpfKmzRCsVtVdhzaoGc,1964
|
124
124
|
airbyte_cdk/sources/declarative/interpolation/interpolated_mapping.py,sha256=h36RIng4GZ9v4o_fRmgJjTNOtWmhK7NOILU1oSKPE4Q,2083
|
125
|
-
airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py,sha256=
|
125
|
+
airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py,sha256=myVaNtFqxOAwrbp93rgd1dhkqyuvXvET9rsimQ89ktc,1873
|
126
126
|
airbyte_cdk/sources/declarative/interpolation/interpolated_string.py,sha256=CQkHqGlfa87G6VYMtBAQWin7ECKpfMdrDcg0JO5_rhc,3212
|
127
127
|
airbyte_cdk/sources/declarative/interpolation/interpolation.py,sha256=9IoeuWam3L6GyN10L6U8xNWXmkt9cnahSDNkez1OmFY,982
|
128
128
|
airbyte_cdk/sources/declarative/interpolation/jinja.py,sha256=UQeuS4Vpyp4hlOn-R3tRyeBX0e9IoV6jQ6gH-Jz8lY0,7182
|
129
129
|
airbyte_cdk/sources/declarative/interpolation/macros.py,sha256=UYSJ5gW7TkHALYnNvUnRP3RlyGwGuRMObF3BHuNzjJM,5320
|
130
|
-
airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256=
|
130
|
+
airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256=cZNUOeIogrCmCS7RXeJqQIlnsANigz1cngpLko02M2g,23191
|
131
131
|
airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
132
132
|
airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
|
133
133
|
airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
|
134
134
|
airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
|
135
|
-
airbyte_cdk/sources/declarative/models/
|
135
|
+
airbyte_cdk/sources/declarative/models/base_model_with_deprecations.py,sha256=Rq5kzR5bflqBf6td2ZAgw6lP3iN_mNi4tjntn_R01_o,5851
|
136
|
+
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=Vf8LSt-leRKOpxQVQsGxWpG2aq9s9yvZKi4DYbpmf0s,117147
|
136
137
|
airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
|
137
138
|
airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=nlVvHC511NUyDEEIRBkoeDTAvLqKNp-hRy8D19z8tdk,5941
|
138
139
|
airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=wnRUP0Xeru9Rbu5OexXSDN9QWDo8YU4tT9M2LDVOgGA,802
|
139
140
|
airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=RUyFZS0zslLb7UfQrvqMC--k5CVLNSp7zHw6kbosvKE,9688
|
140
141
|
airbyte_cdk/sources/declarative/parsers/manifest_normalizer.py,sha256=laBy7ebjA-PiNwc-50U4FHvMqS_mmHvnabxgFs4CjGw,17069
|
141
142
|
airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=pJmg78vqE5VfUrF_KJnWjucQ4k9IWFULeAxHCowrHXE,6806
|
142
|
-
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=
|
143
|
+
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=YZ7WtSFKZ-0HfBq6l-OvmLGkcKcPSg-9wwYMRGYBU0g,166254
|
143
144
|
airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=TBC9AkGaUqHm2IKHMPN6punBIcY5tWGULowcLoAVkfw,1109
|
144
145
|
airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
|
145
146
|
airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
|
@@ -164,7 +165,7 @@ airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_
|
|
164
165
|
airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py,sha256=Tan66odx8VHzfdyyXMQkXz2pJYksllGqvxmpoajgcK4,669
|
165
166
|
airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py,sha256=E-fQbt4ShfxZVoqfnmOx69C6FUPWZz8BIqI3DN9Kcjs,7935
|
166
167
|
airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=uDyLvNsJ183oh3TT-O1PDOgpGt7OD1uqpLTDWTyb9PA,14271
|
167
|
-
airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=
|
168
|
+
airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=1qUqNxJ6I_4uSkW4KYXEtygVioURIEmiaDU8GMl_Jcs,18833
|
168
169
|
airbyte_cdk/sources/declarative/requesters/paginators/__init__.py,sha256=uArbKs9JKNCt7t9tZoeWwjDpyI1HoPp29FNW0JzvaEM,644
|
169
170
|
airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=SB-Af3CRb4mJwhm4EKNxzl_PK2w5QS4tqrSNNMO2IV4,12760
|
170
171
|
airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py,sha256=b1-zKxYOUMHn7ahdWpzKEzfG4A7s_WQWy-vzRqZWzME,2152
|
@@ -188,10 +189,10 @@ airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_reques
|
|
188
189
|
airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py,sha256=SRROdPJZ5kuqHLOlkh115pWP9nDGfDxRYPgH9oD3hPo,1798
|
189
190
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py,sha256=86YozYuBDfu0t9NbevIvQoGU0vqTP4rt3dRSTsHz3PA,2269
|
190
191
|
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py,sha256=rR00kE64U2yL0McU1gPr4_W5_sLUqwDgL3Nvj691nRU,2884
|
191
|
-
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py,sha256=
|
192
|
+
airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py,sha256=TKerU1oGJJRGPk9_AXpKnaQVdNNIYpdLG1lK3HfaHS8,7741
|
192
193
|
airbyte_cdk/sources/declarative/requesters/request_options/request_options_provider.py,sha256=8YRiDzjYvqJ-aMmKFcjqzv_-e8OZ5QG_TbpZ-nuCu6s,2590
|
193
194
|
airbyte_cdk/sources/declarative/requesters/request_path.py,sha256=S3MeFvcaQrMbOkSY2W2VbXLNomqt_3eXqVd9ZhgNwUs,299
|
194
|
-
airbyte_cdk/sources/declarative/requesters/requester.py,sha256=
|
195
|
+
airbyte_cdk/sources/declarative/requesters/requester.py,sha256=T6tMx_Bx4iT-0YVjY7IzgRil-gaIu9n01b1iwpTh3Ek,5516
|
195
196
|
airbyte_cdk/sources/declarative/resolvers/__init__.py,sha256=NiDcz5qi8HPsfX94MUmnX0Rgs_kQXGvucOmJjNWlxKQ,1207
|
196
197
|
airbyte_cdk/sources/declarative/resolvers/components_resolver.py,sha256=KPjKc0yb9artL4ZkeqN8RmEykHH6FJgqXD7fCEnh1X0,1936
|
197
198
|
airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py,sha256=dz4iJV9liD_LzY_Mn4XmAStoUll60R3MIGWV4aN3pgg,5223
|
@@ -407,9 +408,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
|
|
407
408
|
airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
|
408
409
|
airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
|
409
410
|
airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
|
410
|
-
airbyte_cdk-6.48.
|
411
|
-
airbyte_cdk-6.48.
|
412
|
-
airbyte_cdk-6.48.
|
413
|
-
airbyte_cdk-6.48.
|
414
|
-
airbyte_cdk-6.48.
|
415
|
-
airbyte_cdk-6.48.
|
411
|
+
airbyte_cdk-6.48.2.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
|
412
|
+
airbyte_cdk-6.48.2.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
|
413
|
+
airbyte_cdk-6.48.2.dist-info/METADATA,sha256=0SCcRtnWh4AI7620nilMQ_4gxFiiTljCCpb5AB6B_R4,6323
|
414
|
+
airbyte_cdk-6.48.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
415
|
+
airbyte_cdk-6.48.2.dist-info/entry_points.txt,sha256=AKWbEkHfpzzk9nF9tqBUaw1MbvTM4mGtEzmZQm0ZWvM,139
|
416
|
+
airbyte_cdk-6.48.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|