From a6fac4a95be8cde3fde31c25adf65e3c48666e13 Mon Sep 17 00:00:00 2001 From: Artem Litvinov Date: Wed, 27 Sep 2023 19:44:48 +0100 Subject: [PATCH] feat: postgres async session maker --- src/fastapi_app/.env.example | 1 + src/fastapi_app/lib/app/app.py | 27 +++++-- .../lib/app/split_settings/postgres.py | 35 ++++++++- src/fastapi_app/lib/clients/__init__.py | 3 + src/fastapi_app/lib/clients/postgres.py | 24 +++++++ src/fastapi_app/lib/db/base.py | 3 - src/fastapi_app/lib/db/postgres.py | 38 ---------- src/fastapi_app/lib/models/__init__.py | 3 + src/fastapi_app/lib/models/base_sqlalchemy.py | 3 + src/fastapi_app/lib/{db => utils}/__init__.py | 0 src/fastapi_app/poetry.lock | 71 ++++++++++++++++++- src/fastapi_app/pyproject.toml | 2 + 12 files changed, 163 insertions(+), 47 deletions(-) create mode 100644 src/fastapi_app/lib/clients/__init__.py create mode 100644 src/fastapi_app/lib/clients/postgres.py delete mode 100644 src/fastapi_app/lib/db/base.py delete mode 100644 src/fastapi_app/lib/db/postgres.py create mode 100644 src/fastapi_app/lib/models/__init__.py create mode 100644 src/fastapi_app/lib/models/base_sqlalchemy.py rename src/fastapi_app/lib/{db => utils}/__init__.py (100%) diff --git a/src/fastapi_app/.env.example b/src/fastapi_app/.env.example index 59d34a6..77af5a2 100644 --- a/src/fastapi_app/.env.example +++ b/src/fastapi_app/.env.example @@ -1,3 +1,4 @@ +POSTGRES_PROTOCOL=postgresql+asyncpg POSTGRES_HOST=db POSTGRES_PORT=5432 POSTGRES_USER=user diff --git a/src/fastapi_app/lib/app/app.py b/src/fastapi_app/lib/app/app.py index 6e24e89..97c86b4 100644 --- a/src/fastapi_app/lib/app/app.py +++ b/src/fastapi_app/lib/app/app.py @@ -1,19 +1,27 @@ import logging import fastapi +import sqlalchemy +import sqlalchemy.ext.asyncio as sa_asyncio import lib.app.settings as app_settings +import lib.clients as clients + +# import sqlalchemy.ext.asyncio as sa_asyncio + logger = logging.getLogger(__name__) class Application: def __init__(self) -> None: - self.settings = app_settings + self.settings = app_settings.settings self.logger = logging.getLogger(__name__) self.producer = None - def create_app(self) -> fastapi.FastAPI: + async def create_app(self) -> fastapi.FastAPI: + postgres_client = clients.get_async_session(self.settings.postgres) + app = fastapi.FastAPI( title="FastAPI", version="0.1.0", @@ -22,15 +30,26 @@ class Application: default_response_class=fastapi.responses.ORJSONResponse, ) + router = fastapi.APIRouter() + + @router.get("/health") + async def health(get_async_session: sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]): + async with get_async_session.begin() as session: + statement = sqlalchemy.text("SELECT 1") + results = await session.execute(statement) + print(results.unique().scalar_one_or_none()) + return {"status": "ok"} + + app.include_router(router) # app.include_router(api_handlers.user_router, prefix="/api/v1/users", tags=["users"]) # app.include_router(api_handlers.movie_router, prefix="/api/v1/movies", tags=["movies"]) @app.on_event("startup") - async def startup_event(): + async def startup_event(): # noqa: ANN202 self.logger.info("Starting server") @app.on_event("shutdown") - async def shutdown_event(): + async def shutdown_event(): # noqa: ANN202 self.logger.info("Shutting down server") return app diff --git a/src/fastapi_app/lib/app/split_settings/postgres.py b/src/fastapi_app/lib/app/split_settings/postgres.py index 62452f6..6aba752 100644 --- a/src/fastapi_app/lib/app/split_settings/postgres.py +++ b/src/fastapi_app/lib/app/split_settings/postgres.py @@ -4,7 +4,39 @@ import pydantic_settings import lib.app.split_settings.utils as app_split_settings_utils -class PostgresSettings(pydantic_settings.BaseSettings): +class DBSettings(pydantic_settings.BaseSettings): + """Parent DB Settings Class.""" + + # Connection settings + protocol: str + name: str + host: str + port: int + user: str + password: pydantic.SecretStr + + # Enginge settings + pool_size: int = 10 + pool_pre_ping: bool = True + echo: bool = False + + # Session settings + auto_commit: bool = False + auto_flush: bool = False + expire_on_commit: bool = False + + @property + def dsn(self) -> str: + return f"{self.protocol}://{self.user}:{self.password}@{self.host}:{self.port}" + + @property + def dsn_as_safe_url(self) -> str: + return f"{self.protocol}://{self.user}:***@{self.host}:{self.port}" + + +class PostgresSettings(DBSettings): + """Postgres settings.""" + model_config = pydantic_settings.SettingsConfigDict( env_file=app_split_settings_utils.ENV_PATH, env_prefix="POSTGRES_", @@ -12,6 +44,7 @@ class PostgresSettings(pydantic_settings.BaseSettings): extra="ignore", ) + protocol: str = "postgresql+asyncpg" name: str = "database_name" host: str = "localhost" port: int = 5432 diff --git a/src/fastapi_app/lib/clients/__init__.py b/src/fastapi_app/lib/clients/__init__.py new file mode 100644 index 0000000..2a44c3f --- /dev/null +++ b/src/fastapi_app/lib/clients/__init__.py @@ -0,0 +1,3 @@ +from .postgres import get_async_session + +__all__ = ["get_async_session"] diff --git a/src/fastapi_app/lib/clients/postgres.py b/src/fastapi_app/lib/clients/postgres.py new file mode 100644 index 0000000..147e950 --- /dev/null +++ b/src/fastapi_app/lib/clients/postgres.py @@ -0,0 +1,24 @@ +import sqlalchemy.ext.asyncio as sa_asyncio + +import lib.app.split_settings as app_split_settings + + +async def get_async_session( + settings: app_split_settings.DBSettings, +) -> sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]: + engine = sa_asyncio.create_async_engine( + url=settings.dsn, + pool_size=settings.pool_size, + pool_pre_ping=settings.pool_pre_ping, + echo=settings.echo, + future=True, + ) + + async_session = sa_asyncio.async_sessionmaker( + bind=engine, + autocommit=settings.auto_commit, + autoflush=settings.auto_flush, + expire_on_commit=settings.expire_on_commit, + ) + + return async_session # noqa: RET504 diff --git a/src/fastapi_app/lib/db/base.py b/src/fastapi_app/lib/db/base.py deleted file mode 100644 index c4434ed..0000000 --- a/src/fastapi_app/lib/db/base.py +++ /dev/null @@ -1,3 +0,0 @@ -# from libs.api.models.movies import * -# from libs.api.models.notification_templates import * -# from libs.api.models.users import * diff --git a/src/fastapi_app/lib/db/postgres.py b/src/fastapi_app/lib/db/postgres.py deleted file mode 100644 index ecefe41..0000000 --- a/src/fastapi_app/lib/db/postgres.py +++ /dev/null @@ -1,38 +0,0 @@ -import typing - -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.orm import DeclarativeBase - -import lib.app.settings as app_settings - -settings = app_settings.settings - -# Создаём базовый класс для будущих моделей - - -class Base(DeclarativeBase): - pass - - -# Создаём движок -# Настройки подключения к БД передаём из переменных окружения, которые заранее загружены в файл настроек -class AsyncDB: - def __init__(self): - self.database_dsn = ( - f"postgresql+asyncpg://{settings.db.user}:{settings.db.password}" - f"@{settings.db.host}:{settings.db.port}/{settings.db.name}" - ) - self.engine = create_async_engine(self.database_dsn, echo=settings.project.debug, future=True) - self.async_session = async_sessionmaker(self.engine, class_=AsyncSession, expire_on_commit=False) - - -db = AsyncDB() - - -async def get_session() -> typing.AsyncGenerator[AsyncSession, typing.Any]: - async with db.async_session() as session: - try: - yield session - except Exception: - await session.rollback() - raise diff --git a/src/fastapi_app/lib/models/__init__.py b/src/fastapi_app/lib/models/__init__.py new file mode 100644 index 0000000..130e2e2 --- /dev/null +++ b/src/fastapi_app/lib/models/__init__.py @@ -0,0 +1,3 @@ +from .base_sqlalchemy import Base + +__all__ = ["Base"] diff --git a/src/fastapi_app/lib/models/base_sqlalchemy.py b/src/fastapi_app/lib/models/base_sqlalchemy.py new file mode 100644 index 0000000..e3af184 --- /dev/null +++ b/src/fastapi_app/lib/models/base_sqlalchemy.py @@ -0,0 +1,3 @@ +import sqlalchemy.ext.declarative + +Base = sqlalchemy.ext.declarative.declarative_base() diff --git a/src/fastapi_app/lib/db/__init__.py b/src/fastapi_app/lib/utils/__init__.py similarity index 100% rename from src/fastapi_app/lib/db/__init__.py rename to src/fastapi_app/lib/utils/__init__.py diff --git a/src/fastapi_app/poetry.lock b/src/fastapi_app/poetry.lock index ac09217..fa5b4b1 100644 --- a/src/fastapi_app/poetry.lock +++ b/src/fastapi_app/poetry.lock @@ -559,6 +559,75 @@ files = [ [package.dependencies] setuptools = "*" +[[package]] +name = "orjson" +version = "3.9.7" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.7" +files = [ + {file = "orjson-3.9.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6df858e37c321cefbf27fe7ece30a950bcc3a75618a804a0dcef7ed9dd9c92d"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5198633137780d78b86bb54dafaaa9baea698b4f059456cd4554ab7009619221"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e736815b30f7e3c9044ec06a98ee59e217a833227e10eb157f44071faddd7c5"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a19e4074bc98793458b4b3ba35a9a1d132179345e60e152a1bb48c538ab863c4"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80acafe396ab689a326ab0d80f8cc61dec0dd2c5dca5b4b3825e7b1e0132c101"}, + {file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:355efdbbf0cecc3bd9b12589b8f8e9f03c813a115efa53f8dc2a523bfdb01334"}, + {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3aab72d2cef7f1dd6104c89b0b4d6b416b0db5ca87cc2fac5f79c5601f549cc2"}, + {file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36b1df2e4095368ee388190687cb1b8557c67bc38400a942a1a77713580b50ae"}, + {file = "orjson-3.9.7-cp310-none-win32.whl", hash = "sha256:e94b7b31aa0d65f5b7c72dd8f8227dbd3e30354b99e7a9af096d967a77f2a580"}, + {file = "orjson-3.9.7-cp310-none-win_amd64.whl", hash = "sha256:82720ab0cf5bb436bbd97a319ac529aee06077ff7e61cab57cee04a596c4f9b4"}, + {file = "orjson-3.9.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1f8b47650f90e298b78ecf4df003f66f54acdba6a0f763cc4df1eab048fe3738"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f738fee63eb263530efd4d2e9c76316c1f47b3bbf38c1bf45ae9625feed0395e"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38e34c3a21ed41a7dbd5349e24c3725be5416641fdeedf8f56fcbab6d981c900"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21a3344163be3b2c7e22cef14fa5abe957a892b2ea0525ee86ad8186921b6cf0"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23be6b22aab83f440b62a6f5975bcabeecb672bc627face6a83bc7aeb495dc7e"}, + {file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5205ec0dfab1887dd383597012199f5175035e782cdb013c542187d280ca443"}, + {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8769806ea0b45d7bf75cad253fba9ac6700b7050ebb19337ff6b4e9060f963fa"}, + {file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9e01239abea2f52a429fe9d95c96df95f078f0172489d691b4a848ace54a476"}, + {file = "orjson-3.9.7-cp311-none-win32.whl", hash = "sha256:8bdb6c911dae5fbf110fe4f5cba578437526334df381b3554b6ab7f626e5eeca"}, + {file = "orjson-3.9.7-cp311-none-win_amd64.whl", hash = "sha256:9d62c583b5110e6a5cf5169ab616aa4ec71f2c0c30f833306f9e378cf51b6c86"}, + {file = "orjson-3.9.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1c3cee5c23979deb8d1b82dc4cc49be59cccc0547999dbe9adb434bb7af11cf7"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a347d7b43cb609e780ff8d7b3107d4bcb5b6fd09c2702aa7bdf52f15ed09fa09"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:154fd67216c2ca38a2edb4089584504fbb6c0694b518b9020ad35ecc97252bb9"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea3e63e61b4b0beeb08508458bdff2daca7a321468d3c4b320a758a2f554d31"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb0b0b2476f357eb2975ff040ef23978137aa674cd86204cfd15d2d17318588"}, + {file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b9a20a03576c6b7022926f614ac5a6b0914486825eac89196adf3267c6489d"}, + {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:915e22c93e7b7b636240c5a79da5f6e4e84988d699656c8e27f2ac4c95b8dcc0"}, + {file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f26fb3e8e3e2ee405c947ff44a3e384e8fa1843bc35830fe6f3d9a95a1147b6e"}, + {file = "orjson-3.9.7-cp312-none-win_amd64.whl", hash = "sha256:d8692948cada6ee21f33db5e23460f71c8010d6dfcfe293c9b96737600a7df78"}, + {file = "orjson-3.9.7-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7bab596678d29ad969a524823c4e828929a90c09e91cc438e0ad79b37ce41166"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63ef3d371ea0b7239ace284cab9cd00d9c92b73119a7c274b437adb09bda35e6"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f8fcf696bbbc584c0c7ed4adb92fd2ad7d153a50258842787bc1524e50d7081"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90fe73a1f0321265126cbba13677dcceb367d926c7a65807bd80916af4c17047"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45a47f41b6c3beeb31ac5cf0ff7524987cfcce0a10c43156eb3ee8d92d92bf22"}, + {file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a2937f528c84e64be20cb80e70cea76a6dfb74b628a04dab130679d4454395c"}, + {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b4fb306c96e04c5863d52ba8d65137917a3d999059c11e659eba7b75a69167bd"}, + {file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:410aa9d34ad1089898f3db461b7b744d0efcf9252a9415bbdf23540d4f67589f"}, + {file = "orjson-3.9.7-cp37-none-win32.whl", hash = "sha256:26ffb398de58247ff7bde895fe30817a036f967b0ad0e1cf2b54bda5f8dcfdd9"}, + {file = "orjson-3.9.7-cp37-none-win_amd64.whl", hash = "sha256:bcb9a60ed2101af2af450318cd89c6b8313e9f8df4e8fb12b657b2e97227cf08"}, + {file = "orjson-3.9.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5da9032dac184b2ae2da4bce423edff7db34bfd936ebd7d4207ea45840f03905"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7951af8f2998045c656ba8062e8edf5e83fd82b912534ab1de1345de08a41d2b"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8e59650292aa3a8ea78073fc84184538783966528e442a1b9ed653aa282edcf"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9274ba499e7dfb8a651ee876d80386b481336d3868cba29af839370514e4dce0"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca1706e8b8b565e934c142db6a9592e6401dc430e4b067a97781a997070c5378"}, + {file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cc275cf6dcb1a248e1876cdefd3f9b5f01063854acdfd687ec360cd3c9712a"}, + {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11c10f31f2c2056585f89d8229a56013bc2fe5de51e095ebc71868d070a8dd81"}, + {file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cf334ce1d2fadd1bf3e5e9bf15e58e0c42b26eb6590875ce65bd877d917a58aa"}, + {file = "orjson-3.9.7-cp38-none-win32.whl", hash = "sha256:76a0fc023910d8a8ab64daed8d31d608446d2d77c6474b616b34537aa7b79c7f"}, + {file = "orjson-3.9.7-cp38-none-win_amd64.whl", hash = "sha256:7a34a199d89d82d1897fd4a47820eb50947eec9cda5fd73f4578ff692a912f89"}, + {file = "orjson-3.9.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e7e7f44e091b93eb39db88bb0cb765db09b7a7f64aea2f35e7d86cbf47046c65"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d647b2a9c45a23a84c3e70e19d120011cba5f56131d185c1b78685457320bb"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eb850a87e900a9c484150c414e21af53a6125a13f6e378cf4cc11ae86c8f9c5"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4b0042d8388ac85b8330b65406c84c3229420a05068445c13ca28cc222f1f7"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd3e7aae977c723cc1dbb82f97babdb5e5fbce109630fbabb2ea5053523c89d3"}, + {file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c616b796358a70b1f675a24628e4823b67d9e376df2703e893da58247458956"}, + {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3ba725cf5cf87d2d2d988d39c6a2a8b6fc983d78ff71bc728b0be54c869c884"}, + {file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4891d4c934f88b6c29b56395dfc7014ebf7e10b9e22ffd9877784e16c6b2064f"}, + {file = "orjson-3.9.7-cp39-none-win32.whl", hash = "sha256:14d3fb6cd1040a4a4a530b28e8085131ed94ebc90d72793c59a713de34b60838"}, + {file = "orjson-3.9.7-cp39-none-win_amd64.whl", hash = "sha256:9ef82157bbcecd75d6296d5d8b2d792242afcd064eb1ac573f8847b52e58f677"}, + {file = "orjson-3.9.7.tar.gz", hash = "sha256:85e39198f78e2f7e054d296395f6c96f5e02892337746ef5b6a1bf3ed5910142"}, +] + [[package]] name = "packaging" version = "23.1" @@ -1288,4 +1357,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "9510f3e6de8529a041dc81466c5e601fbd93e3fcfe5fa0d0d70e6f74bfc8003f" +content-hash = "f9ae9c843527beb7b8c58cae8cfbf5a6d4a2ef89d7b0a83f5fe30d9f8956fdc8" diff --git a/src/fastapi_app/pyproject.toml b/src/fastapi_app/pyproject.toml index 0d3267b..6183362 100644 --- a/src/fastapi_app/pyproject.toml +++ b/src/fastapi_app/pyproject.toml @@ -23,6 +23,8 @@ version = "0.1.0" alembic = "^1.12.0" asyncpg = "^0.28.0" fastapi = "0.103.1" +greenlet = "^2.0.2" +orjson = "^3.9.7" psycopg2 = "^2.9.7" pydantic = {extras = ["email"], version = "^2.3.0"} pydantic-settings = "^2.0.3"