Skip to content

Commit 76acfb8

Browse files
authored
[low-code] Propagate options to InterpolatedRequestInputProvider (#18050)
* properly propagate options * cleanup * turn into dataclass * rename * no need for deepcopy * fix test * bump * cleaner
1 parent b347829 commit 76acfb8

File tree

6 files changed

+44
-30
lines changed

6 files changed

+44
-30
lines changed

airbyte-cdk/python/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 0.2.3
4+
- Propagate options to InterpolatedRequestInputProvider
5+
36
## 0.2.2
47
- Report config validation errors as failed connection status during `check`.
58
- Report config validation errors as `config_error` failure type.

airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,35 @@
22
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
33
#
44

5+
from dataclasses import InitVar, dataclass, field
56
from typing import Any, Mapping, Optional, Union
67

78
from airbyte_cdk.sources.declarative.interpolation.interpolated_mapping import InterpolatedMapping
89
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
910
from airbyte_cdk.sources.declarative.types import Config, StreamSlice, StreamState
1011

1112

13+
@dataclass
1214
class InterpolatedRequestInputProvider:
1315
"""
1416
Helper class that generically performs string interpolation on the provided dictionary or string input
1517
"""
1618

17-
def __init__(
18-
self, *, config: Config, request_inputs: Optional[Union[str, Mapping[str, str]]] = None, **options: Optional[Mapping[str, Any]]
19-
):
20-
"""
21-
:param config: The user-provided configuration as specified by the source's spec
22-
:param request_inputs: The dictionary to interpolate
23-
:param options: Additional runtime parameters to be used for string interpolation
24-
"""
19+
options: InitVar[Mapping[str, Any]]
20+
request_inputs: Optional[Union[str, Mapping[str, str]]] = field(default=None)
21+
config: Config = field(default_factory=dict)
22+
_interpolator: Union[InterpolatedString, InterpolatedMapping] = field(init=False, repr=False, default=None)
23+
_request_inputs: Union[str, Mapping[str, str]] = field(init=False, repr=False, default=None)
2524

26-
self._config = config
25+
def __post_init__(self, options: Mapping[str, Any]):
2726

28-
if request_inputs is None:
29-
request_inputs = {}
30-
if isinstance(request_inputs, str):
31-
self._interpolator = InterpolatedString(request_inputs, default="", options=options)
27+
self._request_inputs = self.request_inputs or {}
28+
if isinstance(self.request_inputs, str):
29+
self._interpolator = InterpolatedString(self.request_inputs, default="", options=options)
3230
else:
33-
self._interpolator = InterpolatedMapping(request_inputs, options=options)
31+
self._interpolator = InterpolatedMapping(self._request_inputs, options=options)
3432

35-
def request_inputs(
33+
def eval_request_inputs(
3634
self, stream_state: StreamState, stream_slice: Optional[StreamSlice] = None, next_page_token: Mapping[str, Any] = None
3735
) -> Mapping[str, Any]:
3836
"""
@@ -44,7 +42,7 @@ def request_inputs(
4442
:return: The request inputs to set on an outgoing HTTP request
4543
"""
4644
kwargs = {"stream_state": stream_state, "stream_slice": stream_slice, "next_page_token": next_page_token}
47-
interpolated_value = self._interpolator.eval(self._config, **kwargs)
45+
interpolated_value = self._interpolator.eval(self.config, **kwargs)
4846

4947
if isinstance(interpolated_value, dict):
5048
non_null_tokens = {k: v for k, v in interpolated_value.items() if v}

airbyte-cdk/python/airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,18 @@ def __post_init__(self, options: Mapping[str, Any]):
4646
if self.request_body_json and self.request_body_data:
4747
raise ValueError("RequestOptionsProvider should only contain either 'request_body_data' or 'request_body_json' not both")
4848

49-
self._parameter_interpolator = InterpolatedRequestInputProvider(config=self.config, request_inputs=self.request_parameters)
50-
self._headers_interpolator = InterpolatedRequestInputProvider(config=self.config, request_inputs=self.request_headers)
51-
self._body_data_interpolator = InterpolatedRequestInputProvider(config=self.config, request_inputs=self.request_body_data)
52-
self._body_json_interpolator = InterpolatedRequestInputProvider(config=self.config, request_inputs=self.request_body_json)
49+
self._parameter_interpolator = InterpolatedRequestInputProvider(
50+
config=self.config, request_inputs=self.request_parameters, options=options
51+
)
52+
self._headers_interpolator = InterpolatedRequestInputProvider(
53+
config=self.config, request_inputs=self.request_headers, options=options
54+
)
55+
self._body_data_interpolator = InterpolatedRequestInputProvider(
56+
config=self.config, request_inputs=self.request_body_data, options=options
57+
)
58+
self._body_json_interpolator = InterpolatedRequestInputProvider(
59+
config=self.config, request_inputs=self.request_body_json, options=options
60+
)
5361

5462
def get_request_params(
5563
self,
@@ -58,7 +66,7 @@ def get_request_params(
5866
stream_slice: Optional[StreamSlice] = None,
5967
next_page_token: Optional[Mapping[str, Any]] = None,
6068
) -> MutableMapping[str, Any]:
61-
interpolated_value = self._parameter_interpolator.request_inputs(stream_state, stream_slice, next_page_token)
69+
interpolated_value = self._parameter_interpolator.eval_request_inputs(stream_state, stream_slice, next_page_token)
6270
if isinstance(interpolated_value, dict):
6371
return interpolated_value
6472
return {}
@@ -70,7 +78,7 @@ def get_request_headers(
7078
stream_slice: Optional[StreamSlice] = None,
7179
next_page_token: Optional[Mapping[str, Any]] = None,
7280
) -> Mapping[str, Any]:
73-
return self._headers_interpolator.request_inputs(stream_state, stream_slice, next_page_token)
81+
return self._headers_interpolator.eval_request_inputs(stream_state, stream_slice, next_page_token)
7482

7583
def get_request_body_data(
7684
self,
@@ -79,7 +87,7 @@ def get_request_body_data(
7987
stream_slice: Optional[StreamSlice] = None,
8088
next_page_token: Optional[Mapping[str, Any]] = None,
8189
) -> Optional[Union[Mapping, str]]:
82-
return self._body_data_interpolator.request_inputs(stream_state, stream_slice, next_page_token)
90+
return self._body_data_interpolator.eval_request_inputs(stream_state, stream_slice, next_page_token)
8391

8492
def get_request_body_json(
8593
self,
@@ -88,4 +96,4 @@ def get_request_body_json(
8896
stream_slice: Optional[StreamSlice] = None,
8997
next_page_token: Optional[Mapping[str, Any]] = None,
9098
) -> Optional[Mapping]:
91-
return self._body_json_interpolator.request_inputs(stream_state, stream_slice, next_page_token)
99+
return self._body_json_interpolator.eval_request_inputs(stream_state, stream_slice, next_page_token)

airbyte-cdk/python/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
setup(
1717
name="airbyte-cdk",
18-
version="0.2.2",
18+
version="0.2.3",
1919
description="A framework for writing Airbyte Connectors.",
2020
long_description=README,
2121
long_description_content_type="text/markdown",

airbyte-cdk/python/unit_tests/sources/declarative/requesters/test_interpolated_request_input_provider.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@
1313
("test_static_map_data", {"a_static_request_param": "a_static_value"}, {"a_static_request_param": "a_static_value"}),
1414
("test_map_depends_on_stream_slice", {"read_from_slice": "{{ stream_slice['slice_key'] }}"}, {"read_from_slice": "slice_value"}),
1515
("test_map_depends_on_config", {"read_from_config": "{{ config['config_key'] }}"}, {"read_from_config": "value_of_config"}),
16+
(
17+
"test_map_depends_on_options",
18+
{"read_from_options": "{{ options['read_from_options'] }}"},
19+
{"read_from_options": "value_of_options"},
20+
),
1621
("test_defaults_to_empty_dictionary", None, {}),
1722
],
1823
)
1924
def test_initialize_interpolated_mapping_request_input_provider(test_name, input_request_data, expected_request_data):
2025
config = {"config_key": "value_of_config"}
2126
stream_slice = {"slice_key": "slice_value"}
22-
23-
provider = InterpolatedRequestInputProvider(config=config, request_inputs=input_request_data)
24-
actual_request_data = provider.request_inputs(stream_state={}, stream_slice=stream_slice)
27+
options = {"read_from_options": "value_of_options"}
28+
provider = InterpolatedRequestInputProvider(request_inputs=input_request_data, config=config, options=options)
29+
actual_request_data = provider.eval_request_inputs(stream_state={}, stream_slice=stream_slice)
2530

2631
assert isinstance(provider._interpolator, InterpolatedMapping)
2732
assert actual_request_data == expected_request_data

airbyte-cdk/python/unit_tests/sources/declarative/test_factory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ def test_factory():
6969
request_options_provider = factory.create_component(config["request_options"], input_config)()
7070

7171
assert type(request_options_provider) == InterpolatedRequestOptionsProvider
72-
assert request_options_provider._parameter_interpolator._config == input_config
72+
assert request_options_provider._parameter_interpolator.config == input_config
7373
assert request_options_provider._parameter_interpolator._interpolator.mapping["offset"] == "{{ next_page_token['offset'] }}"
74-
assert request_options_provider._body_json_interpolator._config == input_config
74+
assert request_options_provider._body_json_interpolator.config == input_config
7575
assert request_options_provider._body_json_interpolator._interpolator.mapping["body_offset"] == "{{ next_page_token['offset'] }}"
7676

7777

0 commit comments

Comments
 (0)