Skip to content

Commit

Permalink
low-code connectors: convert request headers to string before submitt…
Browse files Browse the repository at this point in the history
…ing them (airbytehq#15336)

* convert values to strings

* introduce variable

* kwargs

* bump version
  • Loading branch information
girarda authored Aug 6, 2022
1 parent 2d92864 commit 6f1715e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 7 deletions.
6 changes: 6 additions & 0 deletions airbyte-cdk/python/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.1.71
- Refactor declarative package to dataclasses
- Bugfix: Requester header always converted to string
- Bugfix: Reset paginator state between stream slices
- Bugfix: Record selector handles single records

## 0.1.70
- Bugfix: DatetimeStreamSlicer cast interpolated result to string before converting to datetime
- Bugfix: Set stream slicer's request options in SimpleRetriever
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,14 @@ def request_headers(
Specifies request headers.
Authentication headers will overwrite any overlapping headers returned from this method.
"""
return self._get_request_options(
headers = self._get_request_options(
stream_slice,
next_page_token,
self.requester.get_request_headers,
self.paginator.get_request_headers,
self.stream_slicer.get_request_headers,
)
return {str(k): str(v) for k, v in headers.items()}

def request_params(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ def get_request_params(
stream_slice: Optional[StreamSlice] = None,
next_page_token: Optional[Mapping[str, Any]] = None,
) -> Mapping[str, Any]:
return dict(ChainMap(*[s.get_request_params() for s in self.stream_slicers]))
return dict(
ChainMap(
*[
s.get_request_params(stream_state=stream_state, stream_slice=stream_slice, next_page_token=next_page_token)
for s in self.stream_slicers
]
)
)

def get_request_headers(
self,
Expand Down
2 changes: 1 addition & 1 deletion airbyte-cdk/python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

setup(
name="airbyte-cdk",
version="0.1.70",
version="0.1.71",
description="A framework for writing Airbyte Connectors.",
long_description=README,
long_description_content_type="text/markdown",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,21 +193,19 @@ def test_backoff_time(test_name, response_action, retry_in, expected_backoff_tim
],
)
def test_get_request_options_from_pagination(test_name, paginator_mapping, stream_slicer_mapping, expected_mapping):
# This test does not test request headers because they must be strings
paginator = MagicMock()
paginator.get_request_headers.return_value = paginator_mapping
paginator.get_request_params.return_value = paginator_mapping
paginator.get_request_body_data.return_value = paginator_mapping
paginator.get_request_body_json.return_value = paginator_mapping

stream_slicer = MagicMock()
stream_slicer.get_request_headers.return_value = stream_slicer_mapping
stream_slicer.get_request_params.return_value = stream_slicer_mapping
stream_slicer.get_request_body_data.return_value = stream_slicer_mapping
stream_slicer.get_request_body_json.return_value = stream_slicer_mapping

base_mapping = {"key": "value"}
requester = MagicMock()
requester.get_request_headers.return_value = base_mapping
requester.get_request_params.return_value = base_mapping
requester.get_request_body_data.return_value = base_mapping
requester.get_request_body_json.return_value = base_mapping
Expand All @@ -224,7 +222,6 @@ def test_get_request_options_from_pagination(test_name, paginator_mapping, strea
)

request_option_type_to_method = {
RequestOptionType.header: retriever.request_headers,
RequestOptionType.request_parameter: retriever.request_params,
RequestOptionType.body_data: retriever.request_body_data,
RequestOptionType.body_json: retriever.request_body_json,
Expand All @@ -242,6 +239,44 @@ def test_get_request_options_from_pagination(test_name, paginator_mapping, strea
pass


@pytest.mark.parametrize(
"test_name, paginator_mapping, expected_mapping",
[
("test_only_base_headers", {}, {"key": "value"}),
("test_header_from_pagination", {"offset": 1000}, {"key": "value", "offset": "1000"}),
("test_duplicate_header", {"key": 1000}, None),
],
)
def test_get_request_headers(test_name, paginator_mapping, expected_mapping):
# This test is separate from the other request options because request headers must be strings
paginator = MagicMock()
paginator.get_request_headers.return_value = paginator_mapping
requester = MagicMock()

base_mapping = {"key": "value"}
requester.get_request_headers.return_value = base_mapping

record_selector = MagicMock()
retriever = SimpleRetriever(
name="stream_name", primary_key=primary_key, requester=requester, record_selector=record_selector, paginator=paginator, options={}
)

request_option_type_to_method = {
RequestOptionType.header: retriever.request_headers,
}

for _, method in request_option_type_to_method.items():
if expected_mapping:
actual_mapping = method(None, None, None)
assert expected_mapping == actual_mapping
else:
try:
method(None, None, None)
assert False
except ValueError:
pass


@pytest.mark.parametrize(
"test_name, requester_body_data, paginator_body_data, expected_body_data",
[
Expand Down

0 comments on commit 6f1715e

Please sign in to comment.