Breaking change with path parameters when updating to pydantic>=2 from pydantic<2
Kludex opened this issue · 1 comments
Discussed in #11250
Originally posted by ThirVondukr March 5, 2024
First Check
- I added a very descriptive title here.
- I used the GitHub search to find a similar question and didn't find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google "How to X in FastAPI" and didn't find any information.
- I already read and followed all the tutorial in the docs and didn't find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
Commit to Help
- I commit to help with one of those options 👆
Example Code
from uuid import UUID
from fastapi import FastAPI
app = FastAPI()
@app.get("/int/{path}")
async def int_(path: int | str):
return str(type(path))
@app.get("/uuid/{path}")
async def uuid_(path: UUID | str):
return str(type(path))
Description
With pydantic<2 parameters are correctly parsed as int and UUID if an appropriate string is passed, with pydantic 2 they're always interpreted as str, I presume this will work the same way with all other types that you can pass into path parameters.
I also observed the same behavior with query, so I assume it behaves the same way with all FastAPI parameters (headers, body, etc).
Operating System
Windows
Operating System Details
No response
FastAPI Version
0.110.0
Pydantic Version
1.10.14 / 2.6.3
Python Version
Python 3.11.5
Additional Context
No response
A workaround for anyone facing this (NB: this assumes availability of typing.Annotated and pydantic.Field):
@app.get("/uuid/{path}")
-async def uuid_(path: UUID | str):
+async def uuid_(path: Annotated[UUID | str, Field(union_mode='left_to_right')]):
return str(type(path))
Pydantic v2 switched to union_mode='smart' as the default, which in cases like this will always prefer str (since it's an exact type match).
It's also necessary to do this in any dependencies (as far as I can tell, type annotations set on direct path parameters and function parameters of dependencies aren't shared).