diff --git a/airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py b/airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py index f58aa30e5..28b378508 100644 --- a/airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +++ b/airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py @@ -2277,9 +2277,6 @@ def create_default_error_handler( response_filters.append( self._create_component_from_model(model=response_filter_model, config=config) ) - response_filters.append( - HttpResponseFilter(config=config, parameters=model.parameters or {}) - ) return DefaultErrorHandler( backoff_strategies=backoff_strategies, diff --git a/airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py b/airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py index c09f18727..fc338c8e7 100644 --- a/airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py +++ b/airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py @@ -58,25 +58,13 @@ def max_time(self) -> Optional[int]: def interpret_response( self, response_or_exception: Optional[Union[requests.Response, Exception]] - ) -> ErrorResolution: - matched_error_resolution = None + ) -> Optional[ErrorResolution]: for error_handler in self.error_handlers: matched_error_resolution = error_handler.interpret_response(response_or_exception) - if not isinstance(matched_error_resolution, ErrorResolution): - continue - - if matched_error_resolution.response_action in [ - ResponseAction.SUCCESS, - ResponseAction.RETRY, - ResponseAction.IGNORE, - ResponseAction.RESET_PAGINATION, - ]: + if isinstance(matched_error_resolution, ErrorResolution): return matched_error_resolution - if matched_error_resolution: - return matched_error_resolution - return create_fallback_error_resolution(response_or_exception) @property diff --git a/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py b/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py index b70ceaaeb..354e30a60 100644 --- a/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +++ b/airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py @@ -122,8 +122,8 @@ def interpret_response( if response_or_exception.ok: return SUCCESS_RESOLUTION - default_reponse_filter = DefaultHttpResponseFilter(parameters={}, config=self.config) - default_response_filter_resolution = default_reponse_filter.matches(response_or_exception) + default_response_filter = DefaultHttpResponseFilter(parameters={}, config=self.config) + default_response_filter_resolution = default_response_filter.matches(response_or_exception) return ( default_response_filter_resolution diff --git a/airbyte_cdk/sources/streams/http/error_handlers/error_handler.py b/airbyte_cdk/sources/streams/http/error_handlers/error_handler.py index b231e72e0..a38409f83 100644 --- a/airbyte_cdk/sources/streams/http/error_handlers/error_handler.py +++ b/airbyte_cdk/sources/streams/http/error_handlers/error_handler.py @@ -32,7 +32,7 @@ def max_time(self) -> Optional[int]: @abstractmethod def interpret_response( self, response: Optional[Union[requests.Response, Exception]] - ) -> ErrorResolution: + ) -> Optional[ErrorResolution]: """ Interpret the response or exception and return the corresponding response action, failure type, and error message. diff --git a/airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py b/airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py index 18daca3de..819bcc3e6 100644 --- a/airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py +++ b/airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py @@ -47,7 +47,7 @@ def max_time(self) -> Optional[int]: def interpret_response( self, response_or_exception: Optional[Union[requests.Response, Exception]] = None - ) -> ErrorResolution: + ) -> Optional[ErrorResolution]: """ Interpret the response and return the corresponding response action, failure type, and error message. diff --git a/airbyte_cdk/sources/streams/http/error_handlers/response_models.py b/airbyte_cdk/sources/streams/http/error_handlers/response_models.py index 7199d1982..4c8c7ee3e 100644 --- a/airbyte_cdk/sources/streams/http/error_handlers/response_models.py +++ b/airbyte_cdk/sources/streams/http/error_handlers/response_models.py @@ -45,20 +45,8 @@ def _format_response_error_message(response: requests.Response) -> str: def create_fallback_error_resolution( response_or_exception: Optional[Union[requests.Response, Exception]], -) -> ErrorResolution: - if response_or_exception is None: - # We do not expect this case to happen but if it does, it would be good to understand the cause and improve the error message - error_message = "Error handler did not receive a valid response or exception. This is unexpected please contact Airbyte Support" - elif isinstance(response_or_exception, Exception): - error_message = _format_exception_error_message(response_or_exception) - else: - error_message = _format_response_error_message(response_or_exception) - - return ErrorResolution( - response_action=ResponseAction.RETRY, - failure_type=FailureType.system_error, - error_message=error_message, - ) +) -> None: + return None SUCCESS_RESOLUTION = ErrorResolution( diff --git a/airbyte_cdk/sources/streams/http/http.py b/airbyte_cdk/sources/streams/http/http.py index fbf4fe35d..16deea680 100644 --- a/airbyte_cdk/sources/streams/http/http.py +++ b/airbyte_cdk/sources/streams/http/http.py @@ -628,7 +628,7 @@ def __init__(self, stream: HttpStream, **kwargs): # type: ignore # noqa def interpret_response( self, response_or_exception: Optional[Union[requests.Response, Exception]] = None - ) -> ErrorResolution: + ) -> Optional[ErrorResolution]: if isinstance(response_or_exception, Exception): return super().interpret_response(response_or_exception) elif isinstance(response_or_exception, requests.Response): diff --git a/airbyte_cdk/sources/streams/http/http_client.py b/airbyte_cdk/sources/streams/http/http_client.py index e9fc5add2..37a228023 100644 --- a/airbyte_cdk/sources/streams/http/http_client.py +++ b/airbyte_cdk/sources/streams/http/http_client.py @@ -342,7 +342,7 @@ def _send( except requests.RequestException as e: exc = e - error_resolution: ErrorResolution = self._error_handler.interpret_response( + error_resolution: Optional[ErrorResolution] = self._error_handler.interpret_response( response if response is not None else exc ) @@ -380,7 +380,7 @@ def _send( response=response, exc=exc, request=request, - error_resolution=error_resolution, + error_resolution=error_resolution if error_resolution else ErrorResolution(ResponseAction.SUCCESS), exit_on_rate_limit=exit_on_rate_limit, ) diff --git a/unit_tests/sources/streams/http/error_handlers/test_response_models.py b/unit_tests/sources/streams/http/error_handlers/test_response_models.py index a6672d912..e7a10ffdc 100644 --- a/unit_tests/sources/streams/http/error_handlers/test_response_models.py +++ b/unit_tests/sources/streams/http/error_handlers/test_response_models.py @@ -1,6 +1,7 @@ # Copyright (c) 2024 Airbyte, Inc., all rights reserved. from unittest import TestCase +from unittest.mock import Mock import requests import requests_mock @@ -27,56 +28,8 @@ def tearDown(self) -> None: def test_given_none_when_create_fallback_error_resolution_then_return_error_resolution( self, ) -> None: - error_resolution = create_fallback_error_resolution(None) - - assert error_resolution.failure_type == FailureType.system_error - assert error_resolution.response_action == ResponseAction.RETRY - assert ( - error_resolution.error_message - == "Error handler did not receive a valid response or exception. This is unexpected please contact Airbyte Support" - ) - - def test_given_exception_when_create_fallback_error_resolution_then_return_error_resolution( - self, - ) -> None: - exception = ValueError("This is an exception") - - error_resolution = create_fallback_error_resolution(exception) - - assert error_resolution.failure_type == FailureType.system_error - assert error_resolution.response_action == ResponseAction.RETRY - assert error_resolution.error_message - assert "ValueError" in error_resolution.error_message - assert str(exception) in error_resolution.error_message - - def test_given_response_can_raise_for_status_when_create_fallback_error_resolution_then_error_resolution( - self, - ) -> None: - response = self._create_response(512) - - error_resolution = create_fallback_error_resolution(response) - - assert error_resolution.failure_type == FailureType.system_error - assert error_resolution.response_action == ResponseAction.RETRY - assert ( - error_resolution.error_message - and "512 Server Error: None for url: https://a-url.com/" - in error_resolution.error_message - ) - - def test_given_response_is_ok_when_create_fallback_error_resolution_then_error_resolution( - self, - ) -> None: - response = self._create_response(205) - - error_resolution = create_fallback_error_resolution(response) - - assert error_resolution.failure_type == FailureType.system_error - assert error_resolution.response_action == ResponseAction.RETRY - assert ( - error_resolution.error_message - and str(response.status_code) in error_resolution.error_message - ) + any_response_or_exception = Mock() + assert create_fallback_error_resolution(any_response_or_exception) is None def _create_response(self, status_code: int) -> requests.Response: with requests_mock.Mocker() as http_mocker: