Skip to content

Commit fad604a

Browse files
committed
Support headers, cookies, and timeout config in Client.
1 parent f385be8 commit fad604a

15 files changed

+102
-33
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
the `sync()` and `asyncio()` functions for a path operation will return `None`. This means all return types are now
1717
`Optional`, so mypy will require you to handle potential errors (or explicitly ignore them).
1818
- Moved `models.types` generated module up a level, so just `types`.
19+
- `Client` and `AuthenticatedClient` are now declared using the `attrs` package instead of builtin `dataclass`
1920

2021
### Additions
2122
- Every generated API module will have a `sync_detailed()` and `asyncio_detailed()` function which work like their
2223
non-detailed counterparts, but return a `types.Response[T]` instead of an `Optional[T]` (where T is the parsed body type).
2324
`types.Response` contains `status_code`, `content` (bytes of returned content), `headers`, and `parsed` (the
2425
parsed return type you would get from the non-detailed function). (#115)
26+
- It's now possible to include custom headers and cookies in requests, as well as set a custom timeout. This can be done
27+
either by directly setting those parameters on a `Client` (e.g. `my_client.headers = {"Header": "Value"}`) or using
28+
a fluid api (e.g. `my_endpoint.sync(my_client.with_cookies({"MyCookie": "cookie"}).with_timeout(10.0))`).
2529

2630

2731
## 0.5.4 - Unreleased

end_to_end_tests/golden-master/my_test_api_client/api/default/ping_ping_get.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def _get_kwargs(
1818
return {
1919
"url": url,
2020
"headers": headers,
21+
"cookies": client.get_cookies(),
22+
"timeout": client.get_timeout(),
2123
}
2224

2325

end_to_end_tests/golden-master/my_test_api_client/api/tests/get_user_list.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def _get_kwargs(
4141
return {
4242
"url": url,
4343
"headers": headers,
44+
"cookies": client.get_cookies(),
45+
"timeout": client.get_timeout(),
4446
"params": params,
4547
}
4648

end_to_end_tests/golden-master/my_test_api_client/api/tests/json_body_tests_json_body_post.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def _get_kwargs(
2323
return {
2424
"url": url,
2525
"headers": headers,
26+
"cookies": client.get_cookies(),
27+
"timeout": client.get_timeout(),
2628
"json": json_json_body,
2729
}
2830

end_to_end_tests/golden-master/my_test_api_client/api/tests/test_defaults_tests_test_defaults_post.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def _get_kwargs(
7575
return {
7676
"url": url,
7777
"headers": headers,
78+
"cookies": client.get_cookies(),
79+
"timeout": client.get_timeout(),
7880
"json": json_json_body,
7981
"params": params,
8082
}

end_to_end_tests/golden-master/my_test_api_client/api/tests/test_octet_stream_tests_test_octet_stream_get.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def _get_kwargs(
1818
return {
1919
"url": url,
2020
"headers": headers,
21+
"cookies": client.get_cookies(),
22+
"timeout": client.get_timeout(),
2123
}
2224

2325

end_to_end_tests/golden-master/my_test_api_client/api/tests/upload_file_tests_upload_post.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ def _get_kwargs(
1818
url = "{}/tests/upload".format(client.base_url)
1919

2020
headers: Dict[str, Any] = client.get_headers()
21+
2122
if keep_alive is not None:
2223
headers["keep-alive"] = keep_alive
2324

2425
return {
2526
"url": url,
2627
"headers": headers,
28+
"cookies": client.get_cookies(),
29+
"timeout": client.get_timeout(),
2730
"files": multipart_data.to_dict(),
2831
}
2932

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,46 @@
1-
from dataclasses import dataclass
2-
from typing import Dict, Union
1+
from typing import Dict
32

3+
import attr
44

5-
@dataclass
5+
6+
@attr.s
67
class Client:
78
""" A class for keeping track of data related to the API """
89

910
base_url: str
11+
cookies: Dict[str, str] = attr.ib(factory=dict, kw_only=True)
12+
headers: Dict[str, str] = attr.ib(factory=dict, kw_only=True)
13+
timeout: float = attr.ib(5.0, kw_only=True)
1014

1115
def get_headers(self) -> Dict[str, str]:
1216
""" Get headers to be used in all endpoints """
13-
return {}
17+
return {**self.headers}
18+
19+
def with_headers(self, headers: Dict[str, str]) -> "Client":
20+
""" Get a new client matching this one with additional headers """
21+
return attr.evolve(self, headers={**self.headers, **headers})
22+
23+
def get_cookies(self) -> Dict[str, str]:
24+
return {**self.cookies}
25+
26+
def with_cookies(self, cookies: Dict[str, str]) -> "Client":
27+
""" Get a new client matching this one with additional cookies """
28+
return attr.evolve(self, cookies={**self.cookies, **cookies})
29+
30+
def get_timeout(self) -> float:
31+
return self.timeout
32+
33+
def with_timeout(self, timeout: float) -> "Client":
34+
""" Get a new client matching this one with a new timeout (in seconds) """
35+
return attr.evolve(self, timeout=timeout)
1436

1537

16-
@dataclass
38+
@attr.s
1739
class AuthenticatedClient(Client):
1840
""" A Client which has been authenticated for use on secured endpoints """
1941

2042
token: str
2143

2244
def get_headers(self) -> Dict[str, str]:
2345
""" Get headers to be used in authenticated endpoints """
24-
return {"Authorization": f"Bearer {self.token}"}
46+
return {"Authorization": f"Bearer {self.token}", **self.headers}

end_to_end_tests/golden-master/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ include = ["CHANGELOG.md", "my_test_api_client/py.typed"]
1515
[tool.poetry.dependencies]
1616
python = "^3.8"
1717
httpx = "^0.13.3"
18+
attrs = "^20.1.0"
1819

1920
[tool.black]
2021
line-length = 120
Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,44 @@
1-
from dataclasses import dataclass
2-
from typing import Dict, Union
1+
from typing import Dict
32

4-
@dataclass
3+
import attr
4+
5+
@attr.s
56
class Client:
67
""" A class for keeping track of data related to the API """
78

89
base_url: str
10+
cookies: Dict[str, str] = attr.ib(factory=dict, kw_only=True)
11+
headers: Dict[str, str] = attr.ib(factory=dict, kw_only=True)
12+
timeout: float = attr.ib(5.0, kw_only=True)
913

1014
def get_headers(self) -> Dict[str, str]:
1115
""" Get headers to be used in all endpoints """
12-
return {}
16+
return {**self.headers}
17+
18+
def with_headers(self, headers: Dict[str, str]) -> "Client":
19+
""" Get a new client matching this one with additional headers """
20+
return attr.evolve(self, headers={**self.headers, **headers})
21+
22+
def get_cookies(self) -> Dict[str, str]:
23+
return {**self.cookies}
24+
25+
def with_cookies(self, cookies: Dict[str, str]) -> "Client":
26+
""" Get a new client matching this one with additional cookies """
27+
return attr.evolve(self, cookies={**self.cookies, **cookies})
28+
29+
def get_timeout(self) -> float:
30+
return self.timeout
31+
32+
def with_timeout(self, timeout: float) -> "Client":
33+
""" Get a new client matching this one with a new timeout (in seconds) """
34+
return attr.evolve(self, timeout=timeout)
1335

14-
@dataclass
36+
@attr.s
1537
class AuthenticatedClient(Client):
1638
""" A Client which has been authenticated for use on secured endpoints """
1739

1840
token: str
1941

2042
def get_headers(self) -> Dict[str, str]:
2143
""" Get headers to be used in authenticated endpoints """
22-
return {"Authorization": f"Bearer {self.token}"}
44+
return {"Authorization": f"Bearer {self.token}", **self.headers}

openapi_python_client/templates/endpoint_module.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def _get_kwargs(
2323
)
2424

2525
headers: Dict[str, Any] = client.get_headers()
26+
2627
{{ header_params(endpoint) | indent(4) }}
2728

2829
{{ query_params(endpoint) | indent(4) }}
@@ -32,6 +33,8 @@ def _get_kwargs(
3233
return {
3334
"url": url,
3435
"headers": headers,
36+
"cookies": client.get_cookies(),
37+
"timeout": client.get_timeout(),
3538
{% if endpoint.form_body_reference %}
3639
"data": asdict(form_data),
3740
{% endif %}

openapi_python_client/templates/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ include = ["CHANGELOG.md", "{{ package_name }}/py.typed"]
1515
[tool.poetry.dependencies]
1616
python = "^3.8"
1717
httpx = "^0.13.3"
18+
attrs = "^20.1.0"
1819

1920
[tool.black]
2021
line-length = 120

poetry.lock

Lines changed: 21 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ isort = "^5.0.5"
3131
pyyaml = "^5.3.1"
3232
importlib_metadata = {version = "^1.6.0", python = "==3.7"}
3333
pydantic = "^1.6.1"
34+
attrs = "^20.1.0"
3435

3536
[tool.poetry.scripts]
3637
openapi-python-client = "openapi_python_client.cli:app"

tests/test_templates/endpoint_module.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def _get_kwargs(
2020
return {
2121
"url": url,
2222
"headers": headers,
23+
"cookies": client.get_cookies(),
24+
"timeout": client.get_timeout(),
2325
"data": asdict(form_data),
2426
"files": multipart_data.to_dict(),
2527
"json": json_json_body,

0 commit comments

Comments
 (0)