diff --git a/crowdin_api/client.py b/crowdin_api/client.py index 74e507f..4dd2c2f 100644 --- a/crowdin_api/client.py +++ b/crowdin_api/client.py @@ -20,7 +20,7 @@ class CrowdinClient: HEADERS = {} USER_AGENT = "crowdin-api-client-python" PAGE_SIZE = 25 - HEADERS = {} + EXTENDED_PARAMS_REQUEST = None def __init__( self, @@ -35,7 +35,8 @@ def __init__( retry_delay: Union[int, float, None] = None, max_retries: Optional[int] = None, http_protocol: Optional[str] = None, - headers: Optional[dict] = None + headers: Optional[dict] = None, + extended_params_request: Optional[dict] = None ): self.ORGANIZATION = organization or self.ORGANIZATION self.TOKEN = token or self.TOKEN @@ -47,6 +48,7 @@ def __init__( self.MAX_RETRIES = max_retries or self.MAX_RETRIES self.HTTP_PROTOCOL = http_protocol or self.HTTP_PROTOCOL self.HEADERS = headers or self.HEADERS + self.EXTENDED_PARAMS_REQUEST = extended_params_request or self.EXTENDED_PARAMS_REQUEST self._api_requestor = None if self.ORGANIZATION is None: @@ -82,6 +84,7 @@ def get_api_requestor(self) -> APIRequester: base_url=self.url, timeout=self.TIMEOUT, default_headers=self.get_default_headers(), + extended_params=self.EXTENDED_PARAMS_REQUEST ) return self._api_requestor diff --git a/crowdin_api/requester.py b/crowdin_api/requester.py index da39053..fb0930c 100644 --- a/crowdin_api/requester.py +++ b/crowdin_api/requester.py @@ -48,11 +48,15 @@ def __init__( retry_delay: Union[int, float] = 0.1, # 100 ms max_retries: int = 5, default_headers: Optional[Dict] = None, + extended_params: Optional[Dict] = None, ): self.base_url = base_url self._session = requests.Session() self._retry_delay = retry_delay self._max_retries = max_retries + self._extended_params = {} if extended_params is None else extended_params + if not isinstance(self._extended_params, dict): + raise TypeError(f"extended_params must be dict, not {type(self._extended_params)}") headers = copy(self.default_headers) headers.update(default_headers or {}) @@ -113,6 +117,7 @@ def _request( else: request_data = dumps(self._clear_data(request_data)) + kwargs = {**self._extended_params, **kwargs} result = self.session.request( method, urljoin(self.base_url, path), diff --git a/crowdin_api/tests/test_client.py b/crowdin_api/tests/test_client.py index 42650ca..eec85d8 100644 --- a/crowdin_api/tests/test_client.py +++ b/crowdin_api/tests/test_client.py @@ -130,6 +130,7 @@ def test_api_requestor(self, m_APIRequester): base_url=client.url, timeout=client.TIMEOUT, default_headers=client.get_default_headers(), + extended_params=client.EXTENDED_PARAMS_REQUEST ) @pytest.mark.parametrize( diff --git a/crowdin_api/tests/test_requester.py b/crowdin_api/tests/test_requester.py index 13658fa..66093ca 100644 --- a/crowdin_api/tests/test_requester.py +++ b/crowdin_api/tests/test_requester.py @@ -1,3 +1,4 @@ +from collections import namedtuple from copy import copy from unittest import mock from unittest.mock import Mock, PropertyMock @@ -19,6 +20,7 @@ def test_init_custom_params(self, m_session, base_absolut_url): timeout = 100 retry_delay = 1 # 1s max_retries = 5 + extended_params = {"some_custom_param": "custom_value"} requester = APIRequester( base_url=base_absolut_url, @@ -26,6 +28,7 @@ def test_init_custom_params(self, m_session, base_absolut_url): retry_delay=retry_delay, # 1s max_retries=max_retries, default_headers=default_headers, + extended_params=extended_params ) headers = copy(requester.default_headers) @@ -36,6 +39,7 @@ def test_init_custom_params(self, m_session, base_absolut_url): assert requester._timeout == timeout assert requester._retry_delay == retry_delay assert requester._max_retries == max_retries + assert requester._extended_params is extended_params @mock.patch("crowdin_api.requester.APIRequester.session", new_callable=PropertyMock) def test_init_default_params(self, m_session, base_absolut_url): @@ -47,6 +51,65 @@ def test_init_default_params(self, m_session, base_absolut_url): session.headers.update.assert_called_once_with(requester.default_headers) assert requester.base_url == base_absolut_url + @pytest.mark.parametrize( + "in_extended_params,out_extended_params", + ( + (None, {}), + ({"some_custom_param": "value"}, {"some_custom_param": "value"}), + ), + ) + def test_init_extended_params(self, base_absolut_url, in_extended_params, out_extended_params): + requester = APIRequester(base_url=base_absolut_url, extended_params=in_extended_params) + assert requester._extended_params == out_extended_params + + @pytest.mark.parametrize( + "extended_params, error_msg", + ( + ("", "extended_params must be dict, not "), + (0, "extended_params must be dict, not "), + (False, "extended_params must be dict, not "), + ), + ) + def test_init_extended_params_raise_error(self, base_absolut_url, extended_params, error_msg): + with pytest.raises(TypeError, match=error_msg): + APIRequester(base_url=base_absolut_url, extended_params=extended_params) + + @pytest.mark.parametrize( + "in_extended_params, in_kwargs, expected_result", + ( + ({"cert": "value"}, {}, {"cert": "value"}), + ({"cert": "value"}, {"cert": "new_value"}, {"cert": "new_value"}), + ({"cert": "value"}, {"stream": "stream_value"}, + {"cert": "value", "stream": "stream_value"}), + ({"cert": "value"}, {"stream": "stream_value", "cert": "new_value"}, + {"cert": "new_value", "stream": "stream_value"}), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.session", new_callable=PropertyMock) + def test__request_with_extended_params( + self, m_session, base_absolut_url, in_extended_params, in_kwargs, expected_result + ): + path = "test" + ResponseMock = namedtuple("ResponseMock", "status_code content headers") + fixture_response_mock = ResponseMock(status_code=200, content=None, headers=None) + + session = Mock() + session.request = Mock(return_value=fixture_response_mock) + m_session.return_value = session + + requester = APIRequester(base_url=base_absolut_url, extended_params=in_extended_params) + requester._request(method="get", path=path, **in_kwargs) + + session.request.assert_called_once_with( + "get", + urljoin(base_absolut_url, path), + params={}, + headers=None, + data="null", + timeout=80, + **expected_result, + ) + def test_session_property(self, base_absolut_url): requester = APIRequester(base_url=base_absolut_url)