Skip to content

Commit f19022a

Browse files
committed
Added proposal to allow less strict TypedDicts.
1 parent dd71b87 commit f19022a

2 files changed

Lines changed: 28 additions & 18 deletions

File tree

src/quart_schema/conversion.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
from dataclasses import fields, is_dataclass
55
from inspect import isclass
6-
from typing import Any, Literal, TypeGuard, TypeVar
6+
from typing import Any, get_origin, Literal, TypeGuard, TypeVar
77

88
import humps
99
from quart import current_app
@@ -255,31 +255,36 @@ def _is_list_or_dict(type_: type) -> bool:
255255
return origin in (dict, dict, list, list)
256256

257257

258+
def _valid_model_class(model_class: type) -> bool:
259+
"""Validate if a type can be used as a schema class.
260+
261+
Returns True for types that don't require conversion:
262+
- TypedDict, dataclasses, and attrs classes
263+
- Built-in dict/list and their generic aliases (e.g., dict[str, int])
264+
"""
265+
if (
266+
_is_list_or_dict(model_class)
267+
or is_dataclass(model_class)
268+
or is_typeddict(model_class)
269+
# Generic aliases: https://github.com/python/cpython/issues/149574
270+
or is_dataclass(get_origin(model_class))
271+
or is_typeddict(get_origin(model_class))
272+
):
273+
return True
274+
return False
275+
276+
258277
def _use_pydantic(model_class: type, preference: str | None) -> bool:
259278
return PYDANTIC_INSTALLED and (
260279
is_pydantic_dataclass(model_class)
261280
or (isclass(model_class) and issubclass(model_class, BaseModel))
262-
or (
263-
(
264-
_is_list_or_dict(model_class)
265-
or is_dataclass(model_class)
266-
or is_typeddict(model_class)
267-
)
268-
and preference != "msgspec"
269-
)
281+
or (_valid_model_class(model_class) and preference != "msgspec")
270282
)
271283

272284

273285
def _use_msgspec(model_class: type, preference: str | None) -> bool:
274286
return MSGSPEC_INSTALLED and (
275287
(isclass(model_class) and issubclass(model_class, Struct))
276288
or is_attrs(model_class)
277-
or (
278-
(
279-
_is_list_or_dict(model_class)
280-
or is_dataclass(model_class)
281-
or is_typeddict(model_class)
282-
)
283-
and preference != "pydantic"
284-
)
289+
or (_valid_model_class(model_class) and preference != "pydantic")
285290
)

tests/helpers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
from dataclasses import dataclass
3-
from typing import Annotated, Generic, NotRequired, TypeVar
3+
from typing import Annotated, Generic, TypeVar
44

55
from attrs import define
66
from msgspec import Struct
@@ -12,6 +12,11 @@
1212
else:
1313
from typing_extensions import TypedDict
1414

15+
try:
16+
from typing import NotRequired
17+
except ImportError:
18+
from typing_extensions import NotRequired
19+
1520

1621
@define
1722
class ADetails:

0 commit comments

Comments
 (0)