From 552f313d76a9549afd06361102ced75d7778777c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Voron?= Date: Sun, 6 Oct 2019 08:53:13 +0200 Subject: [PATCH] Add database abstraction --- Pipfile | 1 + Pipfile.lock | 10 +++++++++- fastapi_users/db/__init__.py | 19 +++++++++++++++++++ fastapi_users/models.py | 3 ++- fastapi_users/router.py | 18 +++++++++++++----- setup.cfg | 9 +++++++++ tests/test_router.py | 17 ++++++++++++++--- 7 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 fastapi_users/db/__init__.py create mode 100644 setup.cfg diff --git a/Pipfile b/Pipfile index 2bfcc74b..4e2dc29e 100644 --- a/Pipfile +++ b/Pipfile @@ -7,6 +7,7 @@ verify_ssl = true flake8 = "*" pytest = "*" requests = "*" +isort = "*" [packages] fastapi = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 665e00fb..aba5cb3a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "91ae09ea534335646c2472e3a9266d8e870b1316f4a857946ca34925cf4a595c" + "sha256": "4879f37c108087df2ecbcee271a3d58de6bfd9d58013d3f9bf0127ef7e7acf92" }, "pipfile-spec": 6, "requires": { @@ -200,6 +200,14 @@ "markers": "python_version < '3.8'", "version": "==0.23" }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "index": "pypi", + "version": "==4.3.21" + }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", diff --git a/fastapi_users/db/__init__.py b/fastapi_users/db/__init__.py new file mode 100644 index 00000000..a3e41e3f --- /dev/null +++ b/fastapi_users/db/__init__.py @@ -0,0 +1,19 @@ +from typing import List + +from ..models import UserDB + + +class UserDBInterface: + """ + Common interface exposing methods to list, get, create and update users in + the database. + """ + + async def list(self) -> List[UserDB]: + raise NotImplementedError() + + async def get_by_email(self, email: str) -> UserDB: + raise NotImplementedError() + + async def create(self, user: UserDB) -> UserDB: + raise NotImplementedError() diff --git a/fastapi_users/models.py b/fastapi_users/models.py index 15634cc1..a2ac3768 100644 --- a/fastapi_users/models.py +++ b/fastapi_users/models.py @@ -1,7 +1,8 @@ import uuid +from typing import Optional + from pydantic import BaseModel from pydantic.types import EmailStr -from typing import Optional class UserBase(BaseModel): diff --git a/fastapi_users/router.py b/fastapi_users/router.py index 7d16e60d..0879b045 100644 --- a/fastapi_users/router.py +++ b/fastapi_users/router.py @@ -1,12 +1,20 @@ from fastapi import APIRouter +from .db import UserDBInterface from .models import UserCreate, UserDB from .password import get_password_hash -router = APIRouter() +class UserRouter: -@router.post('/register') -async def register(user: UserCreate): - hashed_password = get_password_hash(user.password) - return UserDB(**user.dict(), hashed_password=hashed_password) + def __new__(cls, userDB: UserDBInterface) -> APIRouter: + router = APIRouter() + + @router.post('/register') + async def register(user: UserCreate): + hashed_password = get_password_hash(user.password) + db_user = UserDB(**user.dict(), hashed_password=hashed_password) + created_user = await userDB.create(db_user) + return created_user + + return router diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..10d7ac2a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,9 @@ +[flake8] +exclude = docs +max-line-length = 119 + +[isort] +atomic = true +multi_line_output = 5 +known_standard_library = types +known_third_party = pytest,_pytest diff --git a/tests/test_router.py b/tests/test_router.py index 59f4245e..c606d31a 100644 --- a/tests/test_router.py +++ b/tests/test_router.py @@ -1,15 +1,26 @@ +import pytest from starlette import status from starlette.testclient import TestClient -import pytest + +from fastapi_users.db import UserDBInterface +from fastapi_users.models import UserDB + + +class MockUserDBInterface(UserDBInterface): + + async def create(self, user: UserDB) -> UserDB: + return user @pytest.fixture def test_app_client() -> TestClient: from fastapi import FastAPI - from fastapi_users.router import router + from fastapi_users.router import UserRouter + + userRouter = UserRouter(MockUserDBInterface()) app = FastAPI() - app.include_router(router) + app.include_router(userRouter) return TestClient(app)