Pydantic 2.0 seems to have drastically changed.
Previously with FastAPI and Pydantic 1.X I could define the schema like this, where receipt is optional:
class VerifyReceiptIn(BaseModel):
device_id: str
device_type: DeviceType
receipt: Optional[str]
Then in FastAPI endpoint I could do this:
@router_verify_receipt.post(
"/",
status_code=201,
response_model=VerifyReceiptOut,
responses={201: {"model": VerifyReceiptOut}, 400: {"model": HTTPError}},
)
async def verify_receipt(body: VerifyReceiptIn):
auth_service = AuthService()
...
And the unit test without receipt in body was fine with it, but now with Pydantic 2.0 it's failing. Now it claims that Receipt is required and throws a 422 error.
response = await client.post(
"/verify-receipt/",
headers={"api-token": "abc123"},
json={
"device_id": "u1",
"device_type": DeviceType.ANDROID.value,
},
)
But this is why we had Optional. Why do I have to pass receipt=None
in body? This is not ideal as it will break everything on production. Is there a way around this? Thanks
Indeed Pydantic v2 changed the behavior of Optional
to a more strict and correct one. The Pydantic 2.0 Migration Guide has a special section describing the new behavior.
According to the Guide Optional[str]
is now treated as required but allowed to have None
as its value. See the example:
from pydantic import BaseModel
class Model(BaseModel):
value: Optional[str]
m = Model(value='abc') # passes
m = Model(value=None) # passes
m = Model() # fails
Think of Optional[str]
as of str | None
. And in general A | B
requires the value to be of type A
or B
.
For the value to be not required it has to have a default value like in the following example:
from pydantic import BaseModel
class Model(BaseModel):
value: str | None = 'nothing'
m = Model(value='abc') # passes
m = Model(value=None) # passes
m = Model() # passes and sets `value` to `'nothing'`
If you'd change value: str | None = 'nothing'
to value: str | None = None
you'll get a value that is not required and has a default value None
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With