Skip to content

Commit

Permalink
feat: Add two generation config flags to raise exceptions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
robertschweizer committed Apr 1, 2023
1 parent 90aba2c commit 41d739c
Show file tree
Hide file tree
Showing 43 changed files with 614 additions and 556 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,24 @@ By default, the timeout for retrieving the schema file via HTTP is 5 seconds. In

[changelog.md]: CHANGELOG.md
[poetry]: https://python-poetry.org/

### raise_on_error_status

If true, generated endpoint functions raise exceptions on error response codes (status code >= 400).

If false (the default), the parsed response content is returned in the same way both for success and error responses.

Enabling this option also removes the error response types from the return type annotations.

For now, the raised exceptions do not include the parsed response content even if the response code has a schema in the OpenAPI spec.

### raise_on_unexpected_status

Enable this to raise exceptions on undocumented response codes in all generated API call functions.

By default, undocumented response content is parsed as `None`.

Enabling this option also removes `None` from the return type annotations.

This option has identical behavior to setting `Client.raise_on_unexpected_status`, but setting it at
client generation time results in simpler generated code and correct type annotations.
2 changes: 2 additions & 0 deletions end_to_end_tests/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ class_overrides:
class_name: AnEnumValue
module_name: an_enum_value
field_prefix: attr_
raise_on_error_status: True
raise_on_unexpected_status: True
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> None:
def _parse_response(*, response: httpx.Response) -> None:
if response.status_code == HTTPStatus.OK:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
response.raise_for_status()
raise errors.UnexpectedStatus(response.status_code, response.content)


def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
def _build_response(*, response: httpx.Response) -> Response[None]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -62,7 +60,8 @@ def sync_detailed(
common (Union[Unset, None, str]):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.HTTPStatusError: If the server returns an error status code.
errors.UnexpectedStatus: If the server returns an undocumented status code.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
Expand All @@ -79,7 +78,7 @@ def sync_detailed(
**kwargs,
)

return _build_response(client=client, response=response)
return _build_response(response=response)


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

return _build_response(client=client, response=response)
return _build_response(response=response)
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> None:
def _parse_response(*, response: httpx.Response) -> None:
if response.status_code == HTTPStatus.OK:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
response.raise_for_status()
raise errors.UnexpectedStatus(response.status_code, response.content)


def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
def _build_response(*, response: httpx.Response) -> Response[None]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -62,7 +60,8 @@ def sync_detailed(
common (Union[Unset, None, str]):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.HTTPStatusError: If the server returns an error status code.
errors.UnexpectedStatus: If the server returns an undocumented status code.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
Expand All @@ -79,7 +78,7 @@ def sync_detailed(
**kwargs,
)

return _build_response(client=client, response=response)
return _build_response(response=response)


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

return _build_response(client=client, response=response)
return _build_response(response=response)
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> None:
def _parse_response(*, response: httpx.Response) -> None:
if response.status_code == HTTPStatus.OK:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
response.raise_for_status()
raise errors.UnexpectedStatus(response.status_code, response.content)


def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
def _build_response(*, response: httpx.Response) -> Response[None]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -91,7 +89,8 @@ def sync_detailed(
string_enum_header (Union[Unset, GetLocationHeaderTypesStringEnumHeader]):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.HTTPStatusError: If the server returns an error status code.
errors.UnexpectedStatus: If the server returns an undocumented status code.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
Expand All @@ -113,7 +112,7 @@ def sync_detailed(
**kwargs,
)

return _build_response(client=client, response=response)
return _build_response(response=response)


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

return _build_response(client=client, response=response)
return _build_response(response=response)
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> None:
def _parse_response(*, response: httpx.Response) -> None:
if response.status_code == HTTPStatus.OK:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
response.raise_for_status()
raise errors.UnexpectedStatus(response.status_code, response.content)


def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
def _build_response(*, response: httpx.Response) -> Response[None]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -92,7 +90,8 @@ def sync_detailed(
not_null_not_required (Union[Unset, None, datetime.datetime]):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.HTTPStatusError: If the server returns an error status code.
errors.UnexpectedStatus: If the server returns an undocumented status code.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
Expand All @@ -112,7 +111,7 @@ def sync_detailed(
**kwargs,
)

return _build_response(client=client, response=response)
return _build_response(response=response)


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

return _build_response(client=client, response=response)
return _build_response(response=response)
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> None:
def _parse_response(*, response: httpx.Response) -> None:
if response.status_code == HTTPStatus.OK:
return None
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None
response.raise_for_status()
raise errors.UnexpectedStatus(response.status_code, response.content)


def _build_response(*, client: Client, response: httpx.Response) -> Response[None]:
def _build_response(*, response: httpx.Response) -> Response[None]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response), # type: ignore[func-returns-value]
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -83,7 +81,8 @@ def sync_detailed(
cookie_param (Union[Unset, str]):
Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.HTTPStatusError: If the server returns an error status code.
errors.UnexpectedStatus: If the server returns an undocumented status code.
httpx.TimeoutException: If the request takes longer than Client.timeout.
Returns:
Expand All @@ -104,7 +103,7 @@ def sync_detailed(
**kwargs,
)

return _build_response(client=client, response=response)
return _build_response(response=response)


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

return _build_response(client=client, response=response)
return _build_response(response=response)

0 comments on commit 41d739c

Please sign in to comment.