Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/support_non_standard_http_codes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
default: minor
---

# Summary

Added support for responses with non-standard HTTP Status Codes. Off by default, enabled with `allow_int_response_codes`.

# Problem

Currently if a response with a status code that does not exist in `http.HTTPStatusCode` a `ValueError` is raised. For example: `ValueError: 490 is not a valid HTTPStatus`.

# Edge Case

If a non-standard status code is received from an endpoint that doesn't define any responses with non-standard status codes the old behavior will appear.
21 changes: 21 additions & 0 deletions end_to_end_tests/baseline_openapi_3.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,27 @@
}
}
},
"/tests/nonstandard-response-code": {
"get": {
"tags": [
"tests"
],
"summary": "Test nonstandard response code",
"description": "Test endpoint with nonstandard response code",
"operationId": "nonstandard_response_code",
"responses": {
"200": {
"description": "Successful response"
},
"499": {
"description": "Nonstandard response code"
},
"99999": {
"description": "Nonstandard response code"
}
}
}
},
"/config/content-type-override": {
"post": {
"tags": [
Expand Down
21 changes: 21 additions & 0 deletions end_to_end_tests/baseline_openapi_3.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,27 @@ info:
}
}
},
"/tests/nonstandard-response-code": {
"get": {
"tags": [
"tests"
],
"summary": "Test nonstandard response code",
"description": "Test endpoint with nonstandard response code",
"operationId": "nonstandard_response_code",
"responses": {
"200": {
"description": "Successful response"
},
"499": {
"description": "Nonstandard response code"
},
"99999": {
"description": "Nonstandard response code"
}
}
}
},
"/config/content-type-override": {
"post": {
"tags": [
Expand Down
1 change: 1 addition & 0 deletions end_to_end_tests/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ field_prefix: attr_
content_type_overrides:
openapi/python/client: application/json
generate_all_tags: true
allow_int_response_codes: true
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
get_user_list,
json_body_tests_json_body_post,
no_response_tests_no_response_get,
nonstandard_response_code,
octet_stream_tests_octet_stream_get,
octet_stream_tests_octet_stream_post,
post_form_data,
Expand Down Expand Up @@ -150,3 +151,10 @@ def description_with_backslash(cls) -> types.ModuleType:
Test description with \
"""
return description_with_backslash

@classmethod
def nonstandard_response_code(cls) -> types.ModuleType:
"""
Test endpoint with nonstandard response code
"""
return nonstandard_response_code
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ def to_tuple(self) -> FileTypes:


T = TypeVar("T")
S = TypeVar("S", bound=HTTPStatus | int)


@define
class Response(Generic[T]):
class Response(Generic[T, S]):
"""A response from an endpoint"""

status_code: HTTPStatus
status_code: S
content: bytes
headers: MutableMapping[str, str]
parsed: T | None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any

import httpx
Expand All @@ -8,6 +8,8 @@
from ...models.json_like_body import JsonLikeBody
from ...types import UNSET, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -39,7 +41,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -52,7 +54,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
body: JsonLikeBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""A content type that works like json but isn't application/json

Args:
Expand Down Expand Up @@ -81,7 +83,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
body: JsonLikeBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""A content type that works like json but isn't application/json

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any

import httpx
Expand All @@ -8,6 +8,8 @@
from ...models.optional_body_body import OptionalBodyBody
from ...types import UNSET, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -39,7 +41,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -52,7 +54,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
body: OptionalBodyBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test optional request body

Args:
Expand Down Expand Up @@ -81,7 +83,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
body: OptionalBodyBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test optional request body

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any

import httpx
Expand All @@ -10,6 +10,8 @@
from ...models.post_bodies_multiple_json_body import PostBodiesMultipleJsonBody
from ...types import UNSET, File, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -57,7 +59,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -70,7 +72,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
body: PostBodiesMultipleJsonBody | File | PostBodiesMultipleDataBody | PostBodiesMultipleFilesBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test multiple bodies

Args:
Expand Down Expand Up @@ -102,7 +104,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
body: PostBodiesMultipleJsonBody | File | PostBodiesMultipleDataBody | PostBodiesMultipleFilesBody | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test multiple bodies

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any

import httpx
Expand All @@ -8,6 +8,8 @@
from ...models.a_model import AModel
from ...types import UNSET, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -39,7 +41,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -52,7 +54,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
body: AModel | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test request body defined via ref

Args:
Expand Down Expand Up @@ -81,7 +83,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
body: AModel | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""Test request body defined via ref

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any, cast

import httpx
Expand All @@ -7,6 +7,8 @@
from ...client import AuthenticatedClient, Client
from ...types import UNSET, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -39,7 +41,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[str]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[str, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -52,7 +54,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
body: str | Unset = UNSET,
) -> Response[str]:
) -> Response[str, HTTPStatus]:
"""Content Type Override

Args:
Expand Down Expand Up @@ -105,7 +107,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
body: str | Unset = UNSET,
) -> Response[str]:
) -> Response[str, HTTPStatus]:
"""Content Type Override

Args:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from http import HTTPStatus
import http
from typing import Any

import httpx
Expand All @@ -7,6 +7,8 @@
from ...client import AuthenticatedClient, Client
from ...types import UNSET, Response, Unset

HTTPStatus = http.HTTPStatus


def _get_kwargs(
*,
Expand Down Expand Up @@ -37,7 +39,7 @@ def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Res
return None


def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]:
def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any, HTTPStatus]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
Expand All @@ -50,7 +52,7 @@ def sync_detailed(
*,
client: AuthenticatedClient | Client,
common: str | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""
Args:
common (str | Unset):
Expand Down Expand Up @@ -78,7 +80,7 @@ async def asyncio_detailed(
*,
client: AuthenticatedClient | Client,
common: str | Unset = UNSET,
) -> Response[Any]:
) -> Response[Any, HTTPStatus]:
"""
Args:
common (str | Unset):
Expand Down
Loading