Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add two generation config flags to raise exceptions #744

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
@@ -1,5 +1,5 @@
from http import HTTPStatus
from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Union

import httpx

Expand Down Expand Up @@ -34,39 +34,38 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> Optional[Any]:
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[Any]:
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),
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


def sync_detailed(
*,
client: Client,
common: Union[Unset, None, str] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
Expand All @@ -79,24 +78,25 @@ def sync_detailed(
**kwargs,
)

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


async def asyncio_detailed(
*,
client: Client,
common: Union[Unset, None, str] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
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
@@ -1,5 +1,5 @@
from http import HTTPStatus
from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Union

import httpx

Expand Down Expand Up @@ -34,39 +34,38 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> Optional[Any]:
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[Any]:
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),
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


def sync_detailed(
*,
client: Client,
common: Union[Unset, None, str] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
Expand All @@ -79,24 +78,25 @@ def sync_detailed(
**kwargs,
)

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


async def asyncio_detailed(
*,
client: Client,
common: Union[Unset, None, str] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
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
@@ -1,5 +1,5 @@
from http import HTTPStatus
from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Union

import httpx

Expand Down Expand Up @@ -53,21 +53,19 @@ def _get_kwargs(
}


def _parse_response(*, client: Client, response: httpx.Response) -> Optional[Any]:
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[Any]:
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),
parsed=_parse_response(response=response), # type: ignore[func-returns-value]
)


Expand All @@ -80,7 +78,7 @@ def sync_detailed(
integer_header: Union[Unset, int] = UNSET,
int_enum_header: Union[Unset, GetLocationHeaderTypesIntEnumHeader] = UNSET,
string_enum_header: Union[Unset, GetLocationHeaderTypesStringEnumHeader] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
boolean_header (Union[Unset, bool]):
Expand All @@ -91,11 +89,12 @@ 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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
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 @@ -125,7 +124,7 @@ async def asyncio_detailed(
integer_header: Union[Unset, int] = UNSET,
int_enum_header: Union[Unset, GetLocationHeaderTypesIntEnumHeader] = UNSET,
string_enum_header: Union[Unset, GetLocationHeaderTypesStringEnumHeader] = UNSET,
) -> Response[Any]:
) -> Response[None]:
"""
Args:
boolean_header (Union[Unset, bool]):
Expand All @@ -136,11 +135,12 @@ 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:
Response[Any]
Response[None]
"""

kwargs = _get_kwargs(
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)