litestar
litestar copied to clipboard
Bug: OpenAPI error: type object '<MyInputModel>' has no attribute '__parameters__'
Description
Hello, I come to you with an annoying little bug which cannot reproduce. :shrug:
When trying to browse to http://127.0.0.1:8080/schema
I get this wonderful error:
AttributeError on GET /schema
type object 'MyInputModel' has no attribute '__parameters__'
.venv/lib/python3.12/site-packages/litestar/utils/typing.py</span> in get_type_hints_with_generics_resolved at line 263:
origin = get_origin(annotation)
if origin is None:
# Implies the generic types have not been specified in the annotation
if type_hints is None: # pragma: no cover
type_hints = get_type_hints(annotation, globalns=globalns, localns=localns, include_extras=include_extras)
typevar_map = {p: p for p in annotation.__parameters__}
else:
if type_hints is None: # pragma: no cover
type_hints = get_type_hints(origin, globalns=globalns, localns=localns, include_extras=include_extras)
# the __parameters__ is only available on the origin itself and not the annotation
typevar_map = dict(zip(origin.__parameters__, get_args(annotation)))
return {n: _substitute_typevars(type_, typevar_map) for n, type_ in type_hints.items()}
The cause seems to be a generic class (see MyInputModel
in MCVE). When debugging into the litestar code that model does indeed not have a __parameters__
attribute. If I understand this and this correctly, __parameters__
might not always exist. Read: "Note that generics with ParamSpec may not have correct parameters after substitution in some cases because they are intended primarily for static type checking."
Unfortunately, I cannot reproduce this (the model in the MCVE has the same structure, but always has __parameters__
when I test it). Nonetheless, it seems that get_type_hints_with_generics_resolved
should account for that.
My non-reproducible example model works, if I replace line 263 in litestar/utils/typing.py
:
- typevar_map = {p: p for p in annotation.__parameters__}
+ typevar_map = {p: p for p in annotation.__type_params__}
I assume it is not as straight forward as that, as __type_params__
seems not to be available before python 3.12 PEP 695. But I am no expert so, maybe it is. ;)
Cheers
URL to code causing the issue
No response
MCVE
import litestar
import msgspec
import uvicorn
class Base(msgspec.Struct, frozen=True):
field: int = 0
class A(Base, frozen=True, kw_only=True):
x: int
class B(Base, frozen=True, kw_only=True):
x: str
class OtherModel(Base, frozen=True, kw_only=True):
x: float
class MyInputModel[T: A | B](Base, frozen=True, kw_only=True):
items: list[T]
@litestar.post()
async def handler(data: MyInputModel | OtherModel) -> None:
if isinstance(data, OtherModel):
data = MyInputModel(items=[A(x=0, field=0)], field=0)
print(data)
app = litestar.Litestar(route_handlers=[handler])
uvicorn.run(app, host="127.0.0.1", port=8000)
Steps to reproduce
Unknown
Screenshots
No response
Logs
No response
Litestar Version
2.10.0
Platform
- [X] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)
[!NOTE]
While we are open for sponsoring on GitHub Sponsors and OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.Check out all issues funded or available for funding on our Polar.sh dashboard
- If you would like to see an issue prioritized, make a pledge towards it!
- We receive the pledge once the issue is completed & verified
- This, along with engagement in the community, helps us know which features are a priority to our users.