Skip to content

Commit

Permalink
Merge pull request #67 from crowdin/create_addional_kwargs_for_request
Browse files Browse the repository at this point in the history
Add extended params for request
  • Loading branch information
andrii-bodnar authored Feb 20, 2023
2 parents c91a41a + 85516e7 commit df052ce
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 4 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class FirstCrowdinClient(CrowdinClient):
RETRY_DELAY = 0.1 # Optional, sets the delay between failed requests
MAX_RETRIES = 5 # Optional, sets the number of retries
HEADERS = {"Some-Header": ""} # Optional, sets additional http request headers
PAGE_SIZE = 25 # Optional, sets default page size
PAGE_SIZE = 25 # Optional, sets default page size
EXTENDED_REQUEST_PARAMS = {"some-parameters": ""} # Optional, sets additional parameters for request

client = FirstCrowdinClient()

Expand Down
2 changes: 1 addition & 1 deletion crowdin_api/api_resources/source_files/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class DocxFileImportOptions(TypedDict):
importNotes: bool
importHiddenSlides: bool
contentSegmentation: bool
srxStorageId: bool
srxStorageId: int


class OtherImportOptions(TypedDict):
Expand Down
7 changes: 5 additions & 2 deletions crowdin_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class CrowdinClient:
HEADERS = {}
USER_AGENT = "crowdin-api-client-python"
PAGE_SIZE = 25
HEADERS = {}
EXTENDED_REQUEST_PARAMS = None

def __init__(
self,
Expand All @@ -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_request_params: Optional[dict] = None
):
self.ORGANIZATION = organization or self.ORGANIZATION
self.TOKEN = token or self.TOKEN
Expand All @@ -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_REQUEST_PARAMS = extended_request_params or self.EXTENDED_REQUEST_PARAMS
self._api_requestor = None

if self.ORGANIZATION is None:
Expand Down Expand Up @@ -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_REQUEST_PARAMS
)

return self._api_requestor
Expand Down
5 changes: 5 additions & 0 deletions crowdin_api/requester.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 {})
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions crowdin_api/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_REQUEST_PARAMS
)

@pytest.mark.parametrize(
Expand Down
63 changes: 63 additions & 0 deletions crowdin_api/tests/test_requester.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import namedtuple
from copy import copy
from unittest import mock
from unittest.mock import Mock, PropertyMock
Expand All @@ -19,13 +20,15 @@ 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,
timeout=timeout,
retry_delay=retry_delay, # 1s
max_retries=max_retries,
default_headers=default_headers,
extended_params=extended_params
)

headers = copy(requester.default_headers)
Expand All @@ -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):
Expand All @@ -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 <class 'str'>"),
(0, "extended_params must be dict, not <class 'int'>"),
(False, "extended_params must be dict, not <class 'bool'>"),
),
)
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)

Expand Down

0 comments on commit df052ce

Please sign in to comment.