Skip to content

Commit 4e213e6

Browse files
feat: Add two generation config flags to raise exceptions
raise_on_error_status raises a `httpx.HTTPStatusError` on all error response codes without decoding. raise_on_unexpected_status is identical to the existing `Client.raise_on_unexpected_status` runtime setting, but leads to better return type annotations.
1 parent afa1de3 commit 4e213e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+614
-556
lines changed

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,24 @@ By default, the timeout for retrieving the schema file via HTTP is 5 seconds. In
170170

171171
[changelog.md]: CHANGELOG.md
172172
[poetry]: https://python-poetry.org/
173+
174+
### raise_on_error_status
175+
176+
If true, generated endpoint functions raise exceptions on error response codes (status code >= 400).
177+
178+
If false (the default), the parsed response content is returned in the same way both for success and error responses.
179+
180+
Enabling this option also removes the error response types from the return type annotations.
181+
182+
For now, the raised exceptions do not include the parsed response content even if the response code has a schema in the OpenAPI spec.
183+
184+
### raise_on_unexpected_status
185+
186+
Enable this to raise exceptions on undocumented response codes in all generated API call functions.
187+
188+
By default, undocumented response content is parsed as `None`.
189+
190+
Enabling this option also removes `None` from the return type annotations.
191+
192+
This option has identical behavior to setting `Client.raise_on_unexpected_status`, but setting it at
193+
client generation time results in simpler generated code and correct type annotations.

end_to_end_tests/config.yml

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ class_overrides:
99
class_name: AnEnumValue
1010
module_name: an_enum_value
1111
field_prefix: attr_
12+
raise_on_error_status: True
13+
raise_on_unexpected_status: True

end_to_end_tests/golden-record/my_test_api_client/api/default/get_common_parameters.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,19 @@ def _get_kwargs(
3434
}
3535

3636

37-
def _parse_response(*, client: Client, response: httpx.Response) -> None:
37+
def _parse_response(*, response: httpx.Response) -> None:
3838
if response.status_code == HTTPStatus.OK:
3939
return None
40-
if client.raise_on_unexpected_status:
41-
raise errors.UnexpectedStatus(response.status_code, response.content)
42-
else:
43-
return None
40+
response.raise_for_status()
41+
raise errors.UnexpectedStatus(response.status_code, response.content)
4442

4543

46-
def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
44+
def _build_response(*, response: httpx.Response) -> Response[None]:
4745
return Response(
4846
status_code=HTTPStatus(response.status_code),
4947
content=response.content,
5048
headers=response.headers,
51-
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
49+
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
5250
)
5351

5452

@@ -62,7 +60,8 @@ def sync_detailed(
6260
common (Union[Unset, None, str]):
6361
6462
Raises:
65-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
63+
httpx.HTTPStatusError: If the server returns an error status code.
64+
errors.UnexpectedStatus: If the server returns an undocumented status code.
6665
httpx.TimeoutException: If the request takes longer than Client.timeout.
6766
6867
Returns:
@@ -79,7 +78,7 @@ def sync_detailed(
7978
**kwargs,
8079
)
8180

82-
return _build_response(client=client, response=response)
81+
return _build_response(response=response)
8382

8483

8584
async def asyncio_detailed(
@@ -92,7 +91,8 @@ async def asyncio_detailed(
9291
common (Union[Unset, None, str]):
9392
9493
Raises:
95-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
94+
httpx.HTTPStatusError: If the server returns an error status code.
95+
errors.UnexpectedStatus: If the server returns an undocumented status code.
9696
httpx.TimeoutException: If the request takes longer than Client.timeout.
9797
9898
Returns:
@@ -107,4 +107,4 @@ async def asyncio_detailed(
107107
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
108108
response = await _client.request(**kwargs)
109109

110-
return _build_response(client=client, response=response)
110+
return _build_response(response=response)

end_to_end_tests/golden-record/my_test_api_client/api/default/post_common_parameters.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,19 @@ def _get_kwargs(
3434
}
3535

3636

37-
def _parse_response(*, client: Client, response: httpx.Response) -> None:
37+
def _parse_response(*, response: httpx.Response) -> None:
3838
if response.status_code == HTTPStatus.OK:
3939
return None
40-
if client.raise_on_unexpected_status:
41-
raise errors.UnexpectedStatus(response.status_code, response.content)
42-
else:
43-
return None
40+
response.raise_for_status()
41+
raise errors.UnexpectedStatus(response.status_code, response.content)
4442

4543

46-
def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
44+
def _build_response(*, response: httpx.Response) -> Response[None]:
4745
return Response(
4846
status_code=HTTPStatus(response.status_code),
4947
content=response.content,
5048
headers=response.headers,
51-
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
49+
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
5250
)
5351

5452

@@ -62,7 +60,8 @@ def sync_detailed(
6260
common (Union[Unset, None, str]):
6361
6462
Raises:
65-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
63+
httpx.HTTPStatusError: If the server returns an error status code.
64+
errors.UnexpectedStatus: If the server returns an undocumented status code.
6665
httpx.TimeoutException: If the request takes longer than Client.timeout.
6766
6867
Returns:
@@ -79,7 +78,7 @@ def sync_detailed(
7978
**kwargs,
8079
)
8180

82-
return _build_response(client=client, response=response)
81+
return _build_response(response=response)
8382

8483

8584
async def asyncio_detailed(
@@ -92,7 +91,8 @@ async def asyncio_detailed(
9291
common (Union[Unset, None, str]):
9392
9493
Raises:
95-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
94+
httpx.HTTPStatusError: If the server returns an error status code.
95+
errors.UnexpectedStatus: If the server returns an undocumented status code.
9696
httpx.TimeoutException: If the request takes longer than Client.timeout.
9797
9898
Returns:
@@ -107,4 +107,4 @@ async def asyncio_detailed(
107107
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
108108
response = await _client.request(**kwargs)
109109

110-
return _build_response(client=client, response=response)
110+
return _build_response(response=response)

end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_header_types.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,19 @@ def _get_kwargs(
5353
}
5454

5555

56-
def _parse_response(*, client: Client, response: httpx.Response) -> None:
56+
def _parse_response(*, response: httpx.Response) -> None:
5757
if response.status_code == HTTPStatus.OK:
5858
return None
59-
if client.raise_on_unexpected_status:
60-
raise errors.UnexpectedStatus(response.status_code, response.content)
61-
else:
62-
return None
59+
response.raise_for_status()
60+
raise errors.UnexpectedStatus(response.status_code, response.content)
6361

6462

65-
def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
63+
def _build_response(*, response: httpx.Response) -> Response[None]:
6664
return Response(
6765
status_code=HTTPStatus(response.status_code),
6866
content=response.content,
6967
headers=response.headers,
70-
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
68+
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
7169
)
7270

7371

@@ -91,7 +89,8 @@ def sync_detailed(
9189
string_enum_header (Union[Unset, GetLocationHeaderTypesStringEnumHeader]):
9290
9391
Raises:
94-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
92+
httpx.HTTPStatusError: If the server returns an error status code.
93+
errors.UnexpectedStatus: If the server returns an undocumented status code.
9594
httpx.TimeoutException: If the request takes longer than Client.timeout.
9695
9796
Returns:
@@ -113,7 +112,7 @@ def sync_detailed(
113112
**kwargs,
114113
)
115114

116-
return _build_response(client=client, response=response)
115+
return _build_response(response=response)
117116

118117

119118
async def asyncio_detailed(
@@ -136,7 +135,8 @@ async def asyncio_detailed(
136135
string_enum_header (Union[Unset, GetLocationHeaderTypesStringEnumHeader]):
137136
138137
Raises:
139-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
138+
httpx.HTTPStatusError: If the server returns an error status code.
139+
errors.UnexpectedStatus: If the server returns an undocumented status code.
140140
httpx.TimeoutException: If the request takes longer than Client.timeout.
141141
142142
Returns:
@@ -156,4 +156,4 @@ async def asyncio_detailed(
156156
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
157157
response = await _client.request(**kwargs)
158158

159-
return _build_response(client=client, response=response)
159+
return _build_response(response=response)

end_to_end_tests/golden-record/my_test_api_client/api/location/get_location_query_optionality.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,19 @@ def _get_kwargs(
5858
}
5959

6060

61-
def _parse_response(*, client: Client, response: httpx.Response) -> None:
61+
def _parse_response(*, response: httpx.Response) -> None:
6262
if response.status_code == HTTPStatus.OK:
6363
return None
64-
if client.raise_on_unexpected_status:
65-
raise errors.UnexpectedStatus(response.status_code, response.content)
66-
else:
67-
return None
64+
response.raise_for_status()
65+
raise errors.UnexpectedStatus(response.status_code, response.content)
6866

6967

70-
def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
68+
def _build_response(*, response: httpx.Response) -> Response[None]:
7169
return Response(
7270
status_code=HTTPStatus(response.status_code),
7371
content=response.content,
7472
headers=response.headers,
75-
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
73+
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
7674
)
7775

7876

@@ -92,7 +90,8 @@ def sync_detailed(
9290
not_null_not_required (Union[Unset, None, datetime.datetime]):
9391
9492
Raises:
95-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
93+
httpx.HTTPStatusError: If the server returns an error status code.
94+
errors.UnexpectedStatus: If the server returns an undocumented status code.
9695
httpx.TimeoutException: If the request takes longer than Client.timeout.
9796
9897
Returns:
@@ -112,7 +111,7 @@ def sync_detailed(
112111
**kwargs,
113112
)
114113

115-
return _build_response(client=client, response=response)
114+
return _build_response(response=response)
116115

117116

118117
async def asyncio_detailed(
@@ -131,7 +130,8 @@ async def asyncio_detailed(
131130
not_null_not_required (Union[Unset, None, datetime.datetime]):
132131
133132
Raises:
134-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
133+
httpx.HTTPStatusError: If the server returns an error status code.
134+
errors.UnexpectedStatus: If the server returns an undocumented status code.
135135
httpx.TimeoutException: If the request takes longer than Client.timeout.
136136
137137
Returns:
@@ -149,4 +149,4 @@ async def asyncio_detailed(
149149
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
150150
response = await _client.request(**kwargs)
151151

152-
return _build_response(client=client, response=response)
152+
return _build_response(response=response)

end_to_end_tests/golden-record/my_test_api_client/api/parameter_references/get_parameter_references_path_param.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,19 @@ def _get_kwargs(
4646
}
4747

4848

49-
def _parse_response(*, client: Client, response: httpx.Response) -> None:
49+
def _parse_response(*, response: httpx.Response) -> None:
5050
if response.status_code == HTTPStatus.OK:
5151
return None
52-
if client.raise_on_unexpected_status:
53-
raise errors.UnexpectedStatus(response.status_code, response.content)
54-
else:
55-
return None
52+
response.raise_for_status()
53+
raise errors.UnexpectedStatus(response.status_code, response.content)
5654

5755

58-
def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
56+
def _build_response(*, response: httpx.Response) -> Response[None]:
5957
return Response(
6058
status_code=HTTPStatus(response.status_code),
6159
content=response.content,
6260
headers=response.headers,
63-
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
61+
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
6462
)
6563

6664

@@ -83,7 +81,8 @@ def sync_detailed(
8381
cookie_param (Union[Unset, str]):
8482
8583
Raises:
86-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
84+
httpx.HTTPStatusError: If the server returns an error status code.
85+
errors.UnexpectedStatus: If the server returns an undocumented status code.
8786
httpx.TimeoutException: If the request takes longer than Client.timeout.
8887
8988
Returns:
@@ -104,7 +103,7 @@ def sync_detailed(
104103
**kwargs,
105104
)
106105

107-
return _build_response(client=client, response=response)
106+
return _build_response(response=response)
108107

109108

110109
async def asyncio_detailed(
@@ -126,7 +125,8 @@ async def asyncio_detailed(
126125
cookie_param (Union[Unset, str]):
127126
128127
Raises:
129-
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
128+
httpx.HTTPStatusError: If the server returns an error status code.
129+
errors.UnexpectedStatus: If the server returns an undocumented status code.
130130
httpx.TimeoutException: If the request takes longer than Client.timeout.
131131
132132
Returns:
@@ -145,4 +145,4 @@ async def asyncio_detailed(
145145
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
146146
response = await _client.request(**kwargs)
147147

148-
return _build_response(client=client, response=response)
148+
return _build_response(response=response)

0 commit comments

Comments
 (0)