mirror of
https://github.com/ijaric/voice_assistant.git
synced 2025-07-12 17:53:24 +00:00
feat: postgres async session maker
This commit is contained in:
parent
5ddcfe32ad
commit
a6fac4a95b
|
@ -1,3 +1,4 @@
|
|||
POSTGRES_PROTOCOL=postgresql+asyncpg
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=user
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
3
src/fastapi_app/lib/clients/__init__.py
Normal file
3
src/fastapi_app/lib/clients/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from .postgres import get_async_session
|
||||
|
||||
__all__ = ["get_async_session"]
|
24
src/fastapi_app/lib/clients/postgres.py
Normal file
24
src/fastapi_app/lib/clients/postgres.py
Normal file
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
# from libs.api.models.movies import *
|
||||
# from libs.api.models.notification_templates import *
|
||||
# from libs.api.models.users import *
|
|
@ -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
|
3
src/fastapi_app/lib/models/__init__.py
Normal file
3
src/fastapi_app/lib/models/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from .base_sqlalchemy import Base
|
||||
|
||||
__all__ = ["Base"]
|
3
src/fastapi_app/lib/models/base_sqlalchemy.py
Normal file
3
src/fastapi_app/lib/models/base_sqlalchemy.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
import sqlalchemy.ext.declarative
|
||||
|
||||
Base = sqlalchemy.ext.declarative.declarative_base()
|
71
src/fastapi_app/poetry.lock
generated
71
src/fastapi_app/poetry.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue
Block a user