diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4da0816c..6b9d60c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: pip install hatch - name: Test run: | - hatch run test:test-cov-xml + hatch run test-cov-xml - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/README.md b/README.md index d899d2a5..9333a170 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ We use [Hatch](https://hatch.pypa.io/latest/install/) to manage the development You can run all the tests with: ```bash -hatch run test:test +hatch run test ``` ### Format the code diff --git a/fastapi_users/authentication/transport/bearer.py b/fastapi_users/authentication/transport/bearer.py index 7dc6d823..ed96ea7b 100644 --- a/fastapi_users/authentication/transport/bearer.py +++ b/fastapi_users/authentication/transport/bearer.py @@ -8,7 +8,6 @@ from fastapi_users.authentication.transport.base import ( TransportLogoutNotSupportedError, ) from fastapi_users.openapi import OpenAPIResponseType -from fastapi_users.schemas import model_dump class BearerResponse(BaseModel): @@ -24,7 +23,7 @@ class BearerTransport(Transport): async def get_login_response(self, token: str) -> Response: bearer_response = BearerResponse(access_token=token, token_type="bearer") - return JSONResponse(model_dump(bearer_response)) + return JSONResponse(bearer_response.model_dump()) async def get_logout_response(self) -> Response: raise TransportLogoutNotSupportedError() diff --git a/fastapi_users/router/oauth.py b/fastapi_users/router/oauth.py index 6981d3b7..3640aa65 100644 --- a/fastapi_users/router/oauth.py +++ b/fastapi_users/router/oauth.py @@ -265,6 +265,6 @@ def get_oauth_associate_router( request, ) - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) return router diff --git a/fastapi_users/router/register.py b/fastapi_users/router/register.py index 7f3c9c7e..dfd999b0 100644 --- a/fastapi_users/router/register.py +++ b/fastapi_users/router/register.py @@ -69,6 +69,6 @@ def get_register_router( }, ) - return schemas.model_validate(user_schema, created_user) + return user_schema.model_validate(created_user) return router diff --git a/fastapi_users/router/users.py b/fastapi_users/router/users.py index d6c21e18..94964423 100644 --- a/fastapi_users/router/users.py +++ b/fastapi_users/router/users.py @@ -46,7 +46,7 @@ def get_users_router( async def me( user: models.UP = Depends(get_current_active_user), ): - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) @router.patch( "/me", @@ -94,7 +94,7 @@ def get_users_router( user = await user_manager.update( user_update, user, safe=True, request=request ) - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) except exceptions.InvalidPasswordException as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -127,7 +127,7 @@ def get_users_router( }, ) async def get_user(user=Depends(get_user_or_404)): - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) @router.patch( "/{id}", @@ -181,7 +181,7 @@ def get_users_router( user = await user_manager.update( user_update, user, safe=False, request=request ) - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) except exceptions.InvalidPasswordException as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/fastapi_users/router/verify.py b/fastapi_users/router/verify.py index 33a87853..1427dec7 100644 --- a/fastapi_users/router/verify.py +++ b/fastapi_users/router/verify.py @@ -68,7 +68,7 @@ def get_verify_router( ): try: user = await user_manager.verify(token, request) - return schemas.model_validate(user_schema, user) + return user_schema.model_validate(user) except (exceptions.InvalidVerifyToken, exceptions.UserNotExists): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/fastapi_users/schemas.py b/fastapi_users/schemas.py index c4b71edc..b2a8ccf7 100644 --- a/fastapi_users/schemas.py +++ b/fastapi_users/schemas.py @@ -1,35 +1,15 @@ -from typing import Any, Generic, TypeVar +from typing import Generic, TypeVar 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: # pragma: no cover - - def model_dump(model: BaseModel, *args, **kwargs) -> dict[str, Any]: - return model.model_dump(*args, **kwargs) # type: ignore - - def model_validate(schema: type[SCHEMA], obj: Any, *args, **kwargs) -> SCHEMA: - return schema.model_validate(obj, *args, **kwargs) # type: ignore - -else: # pragma: no cover # type: ignore - - def model_dump(model: BaseModel, *args, **kwargs) -> dict[str, Any]: - return model.dict(*args, **kwargs) # type: ignore - - def model_validate(schema: type[SCHEMA], obj: Any, *args, **kwargs) -> SCHEMA: - return schema.from_orm(obj) # type: ignore - class CreateUpdateDictModel(BaseModel): def create_update_dict(self): - return model_dump( - self, + return self.model_dump( exclude_unset=True, exclude={ "id", @@ -41,7 +21,7 @@ class CreateUpdateDictModel(BaseModel): ) def create_update_dict_superuser(self): - return model_dump(self, exclude_unset=True, exclude={"id"}) + return self.model_dump(exclude_unset=True, exclude={"id"}) class BaseUser(CreateUpdateDictModel, Generic[models.ID]): @@ -53,12 +33,7 @@ class BaseUser(CreateUpdateDictModel, Generic[models.ID]): is_superuser: bool = False is_verified: bool = False - if PYDANTIC_V2: # pragma: no cover - model_config = ConfigDict(from_attributes=True) # type: ignore - else: # pragma: no cover - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class BaseUserCreate(CreateUpdateDictModel): @@ -93,12 +68,7 @@ class BaseOAuthAccount(BaseModel, Generic[models.ID]): account_id: str account_email: str - if PYDANTIC_V2: # pragma: no cover - model_config = ConfigDict(from_attributes=True) # type: ignore - else: # pragma: no cover - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class BaseOAuthAccountMixin(BaseModel): diff --git a/pyproject.toml b/pyproject.toml index e222f1c6..4b026a27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,22 +96,9 @@ lint-check = [ "mypy fastapi_users/", ] docs = "mkdocs serve" - -[tool.hatch.envs.test] - -[tool.hatch.envs.test.scripts] test = "pytest --cov=fastapi_users/ --cov-report=term-missing --cov-fail-under=100" test-cov-xml = "pytest --cov=fastapi_users/ --cov-report=xml --cov-fail-under=100" -[[tool.hatch.envs.test.matrix]] -pydantic = ["v1", "v2"] - -[tool.hatch.envs.test.overrides] -matrix.pydantic.extra-dependencies = [ - {value = "pydantic<2.0", if = ["v1"]}, - {value = "pydantic>=2.0", if = ["v2"]}, -] - [tool.hatch.build.targets.sdist] support-legacy = true # Create setup.py diff --git a/tests/test_fastapi_users.py b/tests/test_fastapi_users.py index 52149f7d..13d7b9d7 100644 --- a/tests/test_fastapi_users.py +++ b/tests/test_fastapi_users.py @@ -5,7 +5,7 @@ import pytest import pytest_asyncio from fastapi import Depends, FastAPI, status -from fastapi_users import FastAPIUsers, schemas +from fastapi_users import FastAPIUsers from tests.conftest import IDType, User, UserCreate, UserModel, UserUpdate @@ -77,7 +77,7 @@ async def test_app_client( def optional_current_user( user: UserModel | None = Depends(fastapi_users.current_user(optional=True)), ): - return schemas.model_validate(User, user) if user else None + return User.model_validate(user) if user else None @app.get("/optional-current-active-user") def optional_current_active_user( @@ -85,7 +85,7 @@ async def test_app_client( fastapi_users.current_user(optional=True, active=True) ), ): - return schemas.model_validate(User, user) if user else None + return User.model_validate(user) if user else None @app.get("/optional-current-verified-user") def optional_current_verified_user( @@ -93,7 +93,7 @@ async def test_app_client( fastapi_users.current_user(optional=True, verified=True) ), ): - return schemas.model_validate(User, user) if user else None + return User.model_validate(user) if user else None @app.get("/optional-current-superuser") def optional_current_superuser( @@ -101,7 +101,7 @@ async def test_app_client( fastapi_users.current_user(optional=True, active=True, superuser=True) ), ): - return schemas.model_validate(User, user) if user else None + return User.model_validate(user) if user else None @app.get("/optional-current-verified-superuser") def optional_current_verified_superuser( @@ -111,7 +111,7 @@ async def test_app_client( ) ), ): - return schemas.model_validate(User, user) if user else None + return User.model_validate(user) if user else None async for client in get_test_client(app): yield client