Skip to content

Commit d81d854

Browse files
committed
Merge branch 'main' into request-octet-stream
# Conflicts: # openapi_python_client/parser/openapi.py
2 parents 5b7fa14 + 87b969c commit d81d854

File tree

17 files changed

+352
-75
lines changed

17 files changed

+352
-75
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
default: minor
3+
---
4+
5+
# Support all `text/*` content types in responses
6+
7+
Within an API response, any content type which starts with `text/` will now be treated the same as `text/html` already was—they will return the `response.text` attribute from the [httpx Response](https://www.python-httpx.org/api/#response).
8+
9+
Thanks to @fdintino for the initial implementation, and thanks for the discussions from @kairntech, @rubenfiszel, and @antoneladestito.
10+
11+
Closes #797 and #821.

end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/responses/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import types
44

5-
from . import post_responses_unions_simple_before_complex
5+
from . import post_responses_unions_simple_before_complex, text_response
66

77

88
class ResponsesEndpoints:
@@ -12,3 +12,10 @@ def post_responses_unions_simple_before_complex(cls) -> types.ModuleType:
1212
Regression test for #603
1313
"""
1414
return post_responses_unions_simple_before_complex
15+
16+
@classmethod
17+
def text_response(cls) -> types.ModuleType:
18+
"""
19+
Text Response
20+
"""
21+
return text_response
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
from http import HTTPStatus
2+
from typing import Any, Dict, Optional, Union
3+
4+
import httpx
5+
6+
from ... import errors
7+
from ...client import AuthenticatedClient, Client
8+
from ...types import Response
9+
10+
11+
def _get_kwargs() -> Dict[str, Any]:
12+
return {
13+
"method": "post",
14+
"url": "/responses/text",
15+
}
16+
17+
18+
def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[str]:
19+
if response.status_code == HTTPStatus.OK:
20+
response_200 = response.text
21+
return response_200
22+
if client.raise_on_unexpected_status:
23+
raise errors.UnexpectedStatus(response.status_code, response.content)
24+
else:
25+
return None
26+
27+
28+
def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[str]:
29+
return Response(
30+
status_code=HTTPStatus(response.status_code),
31+
content=response.content,
32+
headers=response.headers,
33+
parsed=_parse_response(client=client, response=response),
34+
)
35+
36+
37+
def sync_detailed(
38+
*,
39+
client: Union[AuthenticatedClient, Client],
40+
) -> Response[str]:
41+
"""Text Response
42+
43+
Raises:
44+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
45+
httpx.TimeoutException: If the request takes longer than Client.timeout.
46+
47+
Returns:
48+
Response[str]
49+
"""
50+
51+
kwargs = _get_kwargs()
52+
53+
response = client.get_httpx_client().request(
54+
**kwargs,
55+
)
56+
57+
return _build_response(client=client, response=response)
58+
59+
60+
def sync(
61+
*,
62+
client: Union[AuthenticatedClient, Client],
63+
) -> Optional[str]:
64+
"""Text Response
65+
66+
Raises:
67+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
68+
httpx.TimeoutException: If the request takes longer than Client.timeout.
69+
70+
Returns:
71+
str
72+
"""
73+
74+
return sync_detailed(
75+
client=client,
76+
).parsed
77+
78+
79+
async def asyncio_detailed(
80+
*,
81+
client: Union[AuthenticatedClient, Client],
82+
) -> Response[str]:
83+
"""Text Response
84+
85+
Raises:
86+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
87+
httpx.TimeoutException: If the request takes longer than Client.timeout.
88+
89+
Returns:
90+
Response[str]
91+
"""
92+
93+
kwargs = _get_kwargs()
94+
95+
response = await client.get_async_httpx_client().request(**kwargs)
96+
97+
return _build_response(client=client, response=response)
98+
99+
100+
async def asyncio(
101+
*,
102+
client: Union[AuthenticatedClient, Client],
103+
) -> Optional[str]:
104+
"""Text Response
105+
106+
Raises:
107+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
108+
httpx.TimeoutException: If the request takes longer than Client.timeout.
109+
110+
Returns:
111+
str
112+
"""
113+
114+
return (
115+
await asyncio_detailed(
116+
client=client,
117+
)
118+
).parsed

end_to_end_tests/golden-record/my_test_api_client/api/tests/callback_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from http import HTTPStatus
2-
from typing import Any, Dict, Optional, Union, cast
2+
from typing import Any, Dict, Optional, Union
33

44
import httpx
55

@@ -27,7 +27,7 @@ def _parse_response(
2727
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
2828
) -> Optional[Union[Any, HTTPValidationError]]:
2929
if response.status_code == HTTPStatus.OK:
30-
response_200 = cast(Any, response.json())
30+
response_200 = response.json()
3131
return response_200
3232
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
3333
response_422 = HTTPValidationError.from_dict(response.json())

end_to_end_tests/golden-record/my_test_api_client/api/tests/defaults_tests_defaults_post.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime
22
from http import HTTPStatus
3-
from typing import Any, Dict, List, Optional, Union, cast
3+
from typing import Any, Dict, List, Optional, Union
44

55
import httpx
66
from dateutil.parser import isoparse
@@ -94,7 +94,7 @@ def _parse_response(
9494
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
9595
) -> Optional[Union[Any, HTTPValidationError]]:
9696
if response.status_code == HTTPStatus.OK:
97-
response_200 = cast(Any, response.json())
97+
response_200 = response.json()
9898
return response_200
9999
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
100100
response_422 = HTTPValidationError.from_dict(response.json())

end_to_end_tests/golden-record/my_test_api_client/api/tests/int_enum_tests_int_enum_post.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from http import HTTPStatus
2-
from typing import Any, Dict, Optional, Union, cast
2+
from typing import Any, Dict, Optional, Union
33

44
import httpx
55

@@ -32,7 +32,7 @@ def _parse_response(
3232
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
3333
) -> Optional[Union[Any, HTTPValidationError]]:
3434
if response.status_code == HTTPStatus.OK:
35-
response_200 = cast(Any, response.json())
35+
response_200 = response.json()
3636
return response_200
3737
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
3838
response_422 = HTTPValidationError.from_dict(response.json())

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from http import HTTPStatus
2-
from typing import Any, Dict, Optional, Union, cast
2+
from typing import Any, Dict, Optional, Union
33

44
import httpx
55

@@ -27,7 +27,7 @@ def _parse_response(
2727
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
2828
) -> Optional[Union[Any, HTTPValidationError]]:
2929
if response.status_code == HTTPStatus.OK:
30-
response_200 = cast(Any, response.json())
30+
response_200 = response.json()
3131
return response_200
3232
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
3333
response_422 = HTTPValidationError.from_dict(response.json())

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from http import HTTPStatus
2-
from typing import Any, Dict, Optional, Union, cast
2+
from typing import Any, Dict, Optional, Union
33

44
import httpx
55

@@ -27,7 +27,7 @@ def _parse_response(
2727
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
2828
) -> Optional[Union[Any, HTTPValidationError]]:
2929
if response.status_code == HTTPStatus.OK:
30-
response_200 = cast(Any, response.json())
30+
response_200 = response.json()
3131
return response_200
3232
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
3333
response_422 = HTTPValidationError.from_dict(response.json())

end_to_end_tests/golden-record/my_test_api_client/api/tests/upload_multiple_files_tests_upload_post.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from http import HTTPStatus
2-
from typing import Any, Dict, List, Optional, Union, cast
2+
from typing import Any, Dict, List, Optional, Union
33

44
import httpx
55

@@ -30,7 +30,7 @@ def _parse_response(
3030
*, client: Union[AuthenticatedClient, Client], response: httpx.Response
3131
) -> Optional[Union[Any, HTTPValidationError]]:
3232
if response.status_code == HTTPStatus.OK:
33-
response_200 = cast(Any, response.json())
33+
response_200 = response.json()
3434
return response_200
3535
if response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY:
3636
response_422 = HTTPValidationError.from_dict(response.json())

end_to_end_tests/openapi.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,27 @@
821821
}
822822
}
823823
},
824+
"/responses/text": {
825+
"post": {
826+
"tags": [
827+
"responses"
828+
],
829+
"summary": "Text Response",
830+
"operationId": "text_response",
831+
"responses": {
832+
"200": {
833+
"description": "Text response",
834+
"content": {
835+
"text/plain": {
836+
"schema": {
837+
"type": "string"
838+
}
839+
}
840+
}
841+
}
842+
}
843+
}
844+
},
824845
"/auth/token_with_cookie": {
825846
"get": {
826847
"tags": [

integration-tests/poetry.lock

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

integration-tests/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pytest = "^7.0.0"
2020
mypy = "*"
2121

2222
[tool.poetry.group.dev.dependencies]
23-
pytest-asyncio = "^0.21.0"
23+
pytest-asyncio = "*"
2424

2525
[build-system]
2626
requires = ["poetry>=1.0"]

0 commit comments

Comments
 (0)