🐛 Remove Required shadowing from fastapi using Pydantic v2#12197
Conversation
|
|
||
| @app.get("/items/") | ||
| async def read_items(q: Annotated[str, Query(min_length=3)] = Required): | ||
| async def read_items(q: Annotated[str, Query(min_length=3)] = ...): |
There was a problem hiding this comment.
These examples seemed old, and I don't see them in the published docs. Guidance wanted on whether these need to be updated, deleted, or left untouched.
There was a problem hiding this comment.
This has been deleted from the (English) docs in PR #10469, but the Russian documentation does in fact still reference it in docs/ru/tutorial/query-params-str-validations.md. Ideally, we probably should remove the reference from the Russian docs as well, and then remove this file altogether, but I would suggest to do that in a separate PR to avoid mixing up different issues - it's always easier to review atomic PRs.
|
📝 Docs preview for commit cc0ef63 at: https://db1b6e45.fastapitiangolo.pages.dev |
|
📝 Docs preview for commit b55c86b at: https://3a774e90.fastapitiangolo.pages.dev |
|
📝 Docs preview for commit 82addc4 at: https://f985d679.fastapitiangolo.pages.dev |
ba2b2f2 to
a651737
Compare
|
📝 Docs preview for commit a651737 at: https://96a7c93a.fastapitiangolo.pages.dev |
a651737 to
f619617
Compare
|
📝 Docs preview for commit f619617 at: https://d78181ad.fastapitiangolo.pages.dev |
Required shadowing from fastapi using Pydantic v2
|
Thanks for the PR and the detailed description and links! It looks like you've done some great digging 🙏 |
svlandeg
left a comment
There was a problem hiding this comment.
Thanks again for the digging! The proposed fix here makes sense to me and avoids further confusion with Required. I only had a few minor nitpicking comments. I'll ask Tiangolo to review as well 🙏
|
📝 Docs preview for commit f68466c at: https://c664766a.fastapitiangolo.pages.dev |
|
📝 Docs preview for commit b6b2921 at: https://86077f7f.fastapitiangolo.pages.dev |
Co-authored-by: Sofie Van Landeghem <[email protected]>
Co-authored-by: Sofie Van Landeghem <[email protected]>
b6b2921 to
d7b0eb2
Compare
|
📝 Docs preview for commit d7b0eb2 at: https://d5ffc61e.fastapitiangolo.pages.dev |
|
Will this be merged soon? I'm encountering a related issue with vLLM |
|
Great job with all the detective work @pachewise! And thanks for the very clear explanation and references. Thanks a lot @svlandeg for all your help and review! 🙇 This will be available in the next hours in FastAPI |
…#12197) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sofie Van Landeghem <[email protected]>
Re:
(and potentially others)
I think I found the underlying cause. We're still supporting
pydantic.Requiredin FastAPI, which has the possibility to shadow the newRequiredtype. To me, this seems like a Pydantic + fastapi bug. Here's how 0.113.0 introduced it:fastapihas the newget_model_fields()function, which deals withTypeAdapter(), and is called for every fieldglobalnsfrom thesys._getframe(), meaning it gets the ns from_compat. This is important because pydantic bases their type evaluations from thatglobalns. Why they are doing this is a question for later.Required = PydanticUndefinedis in _compat.py, we are getting that value set in theglobalnsopenaiusesTypedDictwith theRequiredannotations in its fields.vllm(and potentially other libs) usesfastapi+pydantic+openaiTypedDict classesThe smoking gun was:
TypeError: 'pydantic_core._pydantic_core.PydanticUndefinedType' object is not subscriptableFocusing on vllm-project/vllm#8450, the offending type annotation was
Required[Union[str, Iterable[X]]. It needed to have beenRequiredthat was aPydanticUndefinedType, otherwise it would be complaining aboutUnion[str, Iterable[X]], or some other annotation. I ran the snippet here usingfastapi 0.114.1, pydantic 2.9.0, vllm 0.6.1, python = 3.8.20, and was able to reproduce the issue again. Usingpdb.pm(), I was able to inspect the globalns and connect the dots.How to test
Run the code example in this comment Python 3.8. It will fail without the changes, and pass with the changes.