Add compatibility layer for Pydantic V2

This commit is contained in:
François Voron
2023-07-12 10:44:22 +02:00
parent d2a633d2f5
commit e17bb609ae
9 changed files with 68 additions and 37 deletions

View File

@@ -8,6 +8,7 @@ from fastapi_users.authentication.transport.base import (
TransportLogoutNotSupportedError,
)
from fastapi_users.openapi import OpenAPIResponseType
from fastapi_users.schemas import model_dump
class BearerResponse(BaseModel):
@@ -23,7 +24,7 @@ class BearerTransport(Transport):
async def get_login_response(self, token: str) -> Response:
bearer_response = BearerResponse(access_token=token, token_type="bearer")
return JSONResponse(bearer_response.dict())
return JSONResponse(model_dump(bearer_response))
async def get_logout_response(self) -> Response:
raise TransportLogoutNotSupportedError()

View File

@@ -267,6 +267,6 @@ def get_oauth_associate_router(
request,
)
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
return router

View File

@@ -71,6 +71,6 @@ def get_register_router(
},
)
return user_schema.from_orm(created_user)
return schemas.model_validate(user_schema, created_user)
return router

View File

@@ -48,7 +48,7 @@ def get_users_router(
async def me(
user: models.UP = Depends(get_current_active_user),
):
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
@router.patch(
"/me",
@@ -96,7 +96,7 @@ def get_users_router(
user = await user_manager.update(
user_update, user, safe=True, request=request
)
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
except exceptions.InvalidPasswordException as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
@@ -129,7 +129,7 @@ def get_users_router(
},
)
async def get_user(user=Depends(get_user_or_404)):
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
@router.patch(
"/{id}",
@@ -183,7 +183,7 @@ def get_users_router(
user = await user_manager.update(
user_update, user, safe=False, request=request
)
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
except exceptions.InvalidPasswordException as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,

View File

@@ -70,7 +70,7 @@ def get_verify_router(
):
try:
user = await user_manager.verify(token, request)
return user_schema.from_orm(user)
return schemas.model_validate(user_schema, user)
except (exceptions.InvalidVerifyToken, exceptions.UserNotExists):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,

View File

@@ -1,13 +1,35 @@
from typing import Generic, List, Optional, TypeVar
from typing import Any, Dict, Generic, List, Optional, Type, TypeVar
from pydantic import BaseModel, EmailStr
from pydantic import BaseModel, ConfigDict, EmailStr
from pydantic.version import VERSION as PYDANTIC_VERSION
from fastapi_users import models
PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.")
SCHEMA = TypeVar("SCHEMA", bound=BaseModel)
if PYDANTIC_V2:
def model_dump(model: BaseModel, *args, **kwargs) -> Dict[str, Any]:
return model.model_dump(*args, **kwargs)
def model_validate(schema: Type[SCHEMA], obj: Any, *args, **kwargs) -> SCHEMA:
return schema.model_validate(obj, *args, **kwargs)
else:
def model_dump(model: BaseModel, *args, **kwargs) -> Dict[str, Any]:
return model.dict(*args, **kwargs)
def model_validate(schema: Type[SCHEMA], obj: Any, *args, **kwargs) -> SCHEMA:
return schema.from_orm(obj)
class CreateUpdateDictModel(BaseModel):
def create_update_dict(self):
return self.dict(
return model_dump(
self,
exclude_unset=True,
exclude={
"id",
@@ -19,10 +41,10 @@ class CreateUpdateDictModel(BaseModel):
)
def create_update_dict_superuser(self):
return self.dict(exclude_unset=True, exclude={"id"})
return model_dump(self, exclude_unset=True, exclude={"id"})
class BaseUser(Generic[models.ID], CreateUpdateDictModel):
class BaseUser(CreateUpdateDictModel, Generic[models.ID]):
"""Base User model."""
id: models.ID
@@ -31,8 +53,12 @@ class BaseUser(Generic[models.ID], CreateUpdateDictModel):
is_superuser: bool = False
is_verified: bool = False
class Config:
orm_mode = True
if PYDANTIC_V2:
model_config = ConfigDict(from_attributes=True)
else:
class Config:
orm_mode = True
class BaseUserCreate(CreateUpdateDictModel):
@@ -44,11 +70,11 @@ class BaseUserCreate(CreateUpdateDictModel):
class BaseUserUpdate(CreateUpdateDictModel):
password: Optional[str]
email: Optional[EmailStr]
is_active: Optional[bool]
is_superuser: Optional[bool]
is_verified: Optional[bool]
password: Optional[str] = None
email: Optional[EmailStr] = None
is_active: Optional[bool] = None
is_superuser: Optional[bool] = None
is_verified: Optional[bool] = None
U = TypeVar("U", bound=BaseUser)
@@ -56,7 +82,7 @@ UC = TypeVar("UC", bound=BaseUserCreate)
UU = TypeVar("UU", bound=BaseUserUpdate)
class BaseOAuthAccount(Generic[models.ID], BaseModel):
class BaseOAuthAccount(BaseModel, Generic[models.ID]):
"""Base OAuth account model."""
id: models.ID
@@ -67,8 +93,12 @@ class BaseOAuthAccount(Generic[models.ID], BaseModel):
account_id: str
account_email: str
class Config:
orm_mode = True
if PYDANTIC_V2:
model_config = ConfigDict(from_attributes=True)
else:
class Config:
orm_mode = True
class BaseOAuthAccountMixin(BaseModel):