mirror of
https://github.com/ijaric/voice_assistant.git
synced 2025-05-24 14:33:26 +00:00
Merge pull request #32 from ijaric/fix/#6_fix_template
Исправление мелких багов в "Шаблоне" #6
This commit is contained in:
commit
a6700b4e17
|
@ -1,14 +1,15 @@
|
|||
POSTGRES_PROTOCOL=postgresql+asyncpg
|
||||
POSTGRES_DRIVER=postgresql+asyncpg
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=user
|
||||
POSTGRES_PASSWORD=Qwe123
|
||||
POSTGRES_NAME=api_db
|
||||
POSTGRES_DB_NAME=api_db
|
||||
|
||||
NGINX_PORT=80
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
|
||||
JWT_SECRET_KEY=v9LctjUWwol4XbvczPiLFMDtZ8aal7mm
|
||||
JWT_ALGORITHM=HS256
|
||||
|
||||
APP_RELOAD=True
|
||||
|
|
|
@ -1 +1 @@
|
|||
Generic single-database configuration with an async dbapi.
|
||||
Generic single-database configuration with an async dbapi.
|
||||
|
|
|
@ -17,7 +17,7 @@ config = context.config
|
|||
if config.config_file_name is not None:
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
config.set_main_option("sqlalchemy.url", app_settings.settings.postgres.dsn)
|
||||
config.set_main_option("sqlalchemy.url", app_settings.Settings().postgres.dsn)
|
||||
|
||||
target_metadata = models.Base.metadata
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .health import *
|
||||
|
||||
__all__ = [
|
||||
"health_router",
|
||||
"basic_router",
|
||||
]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .liveness_probe import router as health_router
|
||||
from .liveness_probe import basic_router
|
||||
|
||||
__all__ = [
|
||||
"health_router",
|
||||
"basic_router",
|
||||
]
|
||||
|
|
|
@ -2,10 +2,10 @@ import fastapi
|
|||
|
||||
import lib.api.v1.schemas as api_shemas
|
||||
|
||||
router = fastapi.APIRouter()
|
||||
basic_router = fastapi.APIRouter()
|
||||
|
||||
|
||||
@router.get(
|
||||
@basic_router.get(
|
||||
"/",
|
||||
response_model=api_shemas.HealthResponseModel,
|
||||
summary="Статус работоспособности",
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import uuid
|
||||
|
||||
import sqlalchemy
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
|
||||
class BaseMixin:
|
||||
@declared_attr
|
||||
def id(cls):
|
||||
return sqlalchemy.Column(
|
||||
UUID(as_uuid=True),
|
||||
primary_key=True,
|
||||
default=uuid.uuid4,
|
||||
unique=True,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
@declared_attr
|
||||
def created_at(cls):
|
||||
return sqlalchemy.Column(sqlalchemy.DateTime, server_default=sqlalchemy.sql.func.now())
|
||||
|
||||
@declared_attr
|
||||
def updated_at(cls):
|
||||
return sqlalchemy.Column(sqlalchemy.DateTime, server_default=sqlalchemy.sql.func.now())
|
|
@ -1,6 +1,5 @@
|
|||
from .base import *
|
||||
from .base import HealthResponseModel
|
||||
|
||||
__all__ = [
|
||||
"HealthResponseModel",
|
||||
"TokenResponseModel",
|
||||
]
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
import uuid
|
||||
|
||||
import pydantic
|
||||
|
||||
|
||||
class TokenResponseModel(pydantic.BaseModel):
|
||||
sub: uuid.UUID
|
||||
exp: int | None = None
|
||||
|
||||
|
||||
class HealthResponseModel(pydantic.BaseModel):
|
||||
status: str = pydantic.Field(default=..., examples=["healthy"], description="Схема доступности сервиса")
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import fastapi
|
||||
from jose import JWTError, jwt
|
||||
from pydantic import ValidationError
|
||||
|
||||
import lib.app.settings as app_settings
|
||||
from lib.api.v1 import schemas as app_schemas
|
||||
|
||||
app = fastapi.FastAPI()
|
||||
settings = app_settings.settings
|
||||
|
||||
security = fastapi.security.HTTPBearer()
|
||||
|
||||
|
||||
def get_token_data(
|
||||
authorization: fastapi.security.HTTPAuthorizationCredentials = fastapi.Security(security),
|
||||
) -> app_schemas.entity.Token:
|
||||
token = authorization.credentials
|
||||
try:
|
||||
secret_key = settings.project.jwt_secret_key
|
||||
payload = jwt.decode(token, secret_key, algorithms=["HS256"])
|
||||
return app_schemas.entity.Token(**payload)
|
||||
except (JWTError, ValidationError):
|
||||
raise fastapi.HTTPException(
|
||||
status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
)
|
|
@ -4,8 +4,8 @@ from .settings import Settings
|
|||
|
||||
__all__ = [
|
||||
"Application",
|
||||
"Settings",
|
||||
"ApplicationError",
|
||||
"DisposeError",
|
||||
"Settings",
|
||||
"StartServerError",
|
||||
]
|
||||
|
|
|
@ -10,6 +10,7 @@ import lib.api.v1.handlers as api_v1_handlers
|
|||
import lib.app.errors as app_errors
|
||||
import lib.app.settings as app_settings
|
||||
import lib.app.split_settings as app_split_settings
|
||||
import lib.clients as clients
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -43,6 +44,15 @@ class Application:
|
|||
# Global clients
|
||||
|
||||
logger.info("Initializing global clients")
|
||||
postgres_client = clients.AsyncPostgresClient(settings=settings)
|
||||
http_client = clients.get_async_http_session()
|
||||
|
||||
disposable_resources.append(
|
||||
DisposableResource(
|
||||
name="postgres_client",
|
||||
dispose_callback=postgres_client.dispose_callback(),
|
||||
)
|
||||
)
|
||||
|
||||
# Clients
|
||||
|
||||
|
@ -63,10 +73,10 @@ class Application:
|
|||
# Handlers
|
||||
|
||||
logger.info("Initializing handlers")
|
||||
# liveness_probe_handler = health_handlers.LivenessProbeHandler()
|
||||
liveness_probe_handler = api_v1_handlers.basic_router
|
||||
|
||||
|
||||
logger.info("Creating application")
|
||||
# aio_app = aiohttp_web.Application()
|
||||
|
||||
fastapi_app = fastapi.FastAPI(
|
||||
title=settings.app.title,
|
||||
|
@ -77,7 +87,7 @@ class Application:
|
|||
)
|
||||
|
||||
# Routes
|
||||
fastapi_app.include_router(api_v1_handlers.health_router, prefix="/api/v1/health", tags=["health"])
|
||||
fastapi_app.include_router(liveness_probe_handler, prefix="/api/v1/health", tags=["health"])
|
||||
|
||||
application = Application(
|
||||
settings=settings,
|
||||
|
|
|
@ -4,19 +4,28 @@ import pydantic_settings
|
|||
import lib.app.split_settings.utils as app_split_settings_utils
|
||||
|
||||
|
||||
class DBSettings(pydantic_settings.BaseSettings):
|
||||
"""Parent DB Settings Class."""
|
||||
class PostgresSettings(pydantic_settings.BaseSettings):
|
||||
"""Postgres settings."""
|
||||
|
||||
model_config = pydantic_settings.SettingsConfigDict(
|
||||
env_file=app_split_settings_utils.ENV_PATH,
|
||||
env_prefix="POSTGRES_",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
# Connection settings
|
||||
protocol: str
|
||||
name: str
|
||||
host: str
|
||||
port: int
|
||||
user: str
|
||||
password: pydantic.SecretStr
|
||||
driver: str = "postgresql+asyncpg"
|
||||
db_name: str = "database_name"
|
||||
host: str = "localhost"
|
||||
port: int = 5432
|
||||
user: str = "app"
|
||||
password: pydantic.SecretStr = pydantic.Field(
|
||||
default=..., validation_alias=pydantic.AliasChoices("password", "postgres_password")
|
||||
)
|
||||
|
||||
# Enginge settings
|
||||
pool_size: int = 10
|
||||
# Engine settings
|
||||
pool_size: int = 50
|
||||
pool_pre_ping: bool = True
|
||||
echo: bool = False
|
||||
|
||||
|
@ -27,29 +36,9 @@ class DBSettings(pydantic_settings.BaseSettings):
|
|||
|
||||
@property
|
||||
def dsn(self) -> str:
|
||||
password = self.password.get_secret_value() if isinstance(self.password, pydantic.SecretStr) else self.password
|
||||
return f"{self.protocol}://{self.user}:{password}@{self.host}:{self.port}"
|
||||
password = self.password.get_secret_value()
|
||||
return f"{self.driver}://{self.user}:{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_",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
protocol: str = "postgresql+asyncpg"
|
||||
name: str = "database_name"
|
||||
host: str = "localhost"
|
||||
port: int = 5432
|
||||
user: str = "app"
|
||||
password: pydantic.SecretStr = pydantic.Field(
|
||||
default=..., validation_alias=pydantic.AliasChoices("password", "postgres_password")
|
||||
)
|
||||
return f"{self.driver}://{self.user}:***@{self.host}:{self.port}"
|
||||
|
|
|
@ -5,6 +5,8 @@ import lib.app.split_settings.utils as app_split_settings_utils
|
|||
|
||||
|
||||
class ProjectSettings(pydantic_settings.BaseSettings):
|
||||
"""Project settings."""
|
||||
|
||||
model_config = pydantic_settings.SettingsConfigDict(
|
||||
env_file=app_split_settings_utils.ENV_PATH,
|
||||
env_file_encoding="utf-8",
|
||||
|
@ -12,7 +14,8 @@ class ProjectSettings(pydantic_settings.BaseSettings):
|
|||
)
|
||||
|
||||
debug: str = "false"
|
||||
jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key")
|
||||
jwt_secret_key: str = pydantic.Field(default=..., validation_alias="jwt_secret_key")
|
||||
jwt_algorithm: str = "HS256"
|
||||
|
||||
@pydantic.field_validator("debug")
|
||||
def validate_debug(cls, v: str) -> bool:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .postgres import get_async_session
|
||||
from .httpx import get_async_http_session
|
||||
from .postgres import AsyncPostgresClient
|
||||
|
||||
__all__ = ["get_async_session"]
|
||||
__all__ = ["AsyncPostgresClient", "get_async_http_session"]
|
||||
|
|
16
src/fastapi_app/lib/clients/httpx.py
Normal file
16
src/fastapi_app/lib/clients/httpx.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import contextlib
|
||||
import typing
|
||||
|
||||
import httpx
|
||||
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def get_async_http_session(
|
||||
settings: dict[str, typing.Any] | None = None
|
||||
) -> typing.AsyncGenerator[httpx.AsyncClient, None]:
|
||||
"""Async http client."""
|
||||
if settings is None:
|
||||
settings = {}
|
||||
client = httpx.AsyncClient(**settings) # Insert your own settings here
|
||||
async with client as ac:
|
||||
yield ac
|
|
@ -1,24 +1,30 @@
|
|||
import sqlalchemy.ext.asyncio as sa_asyncio
|
||||
|
||||
import lib.app.split_settings as app_split_settings
|
||||
import lib.app.settings as app_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,
|
||||
)
|
||||
class AsyncPostgresClient:
|
||||
"""Async Postgres Client that return sessionmaker."""
|
||||
|
||||
async_session = sa_asyncio.async_sessionmaker(
|
||||
bind=engine,
|
||||
autocommit=settings.auto_commit,
|
||||
autoflush=settings.auto_flush,
|
||||
expire_on_commit=settings.expire_on_commit,
|
||||
)
|
||||
def __init__(self, settings: app_settings.Settings) -> None:
|
||||
self.settings = settings.postgres
|
||||
self.async_enging = sa_asyncio.create_async_engine(
|
||||
url=self.settings.dsn,
|
||||
pool_size=self.settings.pool_size,
|
||||
pool_pre_ping=self.settings.pool_pre_ping,
|
||||
echo=self.settings.echo,
|
||||
future=True,
|
||||
)
|
||||
|
||||
return async_session # noqa: RET504
|
||||
def get_async_session(self) -> sa_asyncio.async_sessionmaker[sa_asyncio.AsyncSession]:
|
||||
async_session = sa_asyncio.async_sessionmaker(
|
||||
bind=self.async_enging,
|
||||
autocommit=self.settings.auto_commit,
|
||||
autoflush=self.settings.auto_flush,
|
||||
expire_on_commit=self.settings.expire_on_commit,
|
||||
)
|
||||
|
||||
return async_session # noqa: RET504
|
||||
|
||||
async def dispose_callback(self) -> None:
|
||||
await self.async_enging.dispose()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .base_sqlalchemy import Base
|
||||
from .base_sqlalchemy import Base, IdCreatedUpdatedBaseMixin
|
||||
from .token import Token
|
||||
|
||||
__all__ = ["Base"]
|
||||
__all__ = ["Base", "IdCreatedUpdatedBaseMixin", "Token"]
|
||||
|
|
|
@ -1,5 +1,36 @@
|
|||
import uuid
|
||||
|
||||
import sqlalchemy
|
||||
import sqlalchemy.dialects.postgresql
|
||||
import sqlalchemy.ext.declarative
|
||||
import sqlalchemy.orm
|
||||
|
||||
|
||||
class Base(sqlalchemy.orm.DeclarativeBase):
|
||||
"""Base class for all models."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class IdCreatedUpdatedBaseMixin(Base):
|
||||
@sqlalchemy.ext.declarative.declared_attr
|
||||
def uuid(cls):
|
||||
return sqlalchemy.Column(
|
||||
sqlalchemy.dialects.postgresql.UUID(as_uuid=True),
|
||||
primary_key=True,
|
||||
default=uuid.uuid4,
|
||||
unique=True,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
@sqlalchemy.ext.declarative.declared_attr
|
||||
def created_at(cls):
|
||||
return sqlalchemy.Column(sqlalchemy.DateTime, server_default=sqlalchemy.sql.func.now())
|
||||
|
||||
@sqlalchemy.ext.declarative.declared_attr
|
||||
def updated_at(cls):
|
||||
return sqlalchemy.Column(sqlalchemy.DateTime, server_default=sqlalchemy.sql.func.now())
|
||||
|
||||
@sqlalchemy.ext.declarative.declared_attr.directive
|
||||
def __tablename__(cls) -> str:
|
||||
return cls.__name__.lower()
|
||||
|
|
9
src/fastapi_app/lib/models/token.py
Normal file
9
src/fastapi_app/lib/models/token.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import uuid
|
||||
|
||||
import pydantic
|
||||
|
||||
|
||||
# TODO: TBU
|
||||
class Token(pydantic.BaseModel):
|
||||
sub: uuid.UUID
|
||||
exp: int | None = None
|
25
src/fastapi_app/lib/utils/token.py
Normal file
25
src/fastapi_app/lib/utils/token.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
import fastapi
|
||||
import fastapi.security
|
||||
import jose
|
||||
import jose.jwt
|
||||
import pydantic
|
||||
|
||||
import lib.app.settings as app_settings
|
||||
import lib.models as models
|
||||
|
||||
|
||||
def get_token_data(
|
||||
authorization: fastapi.security.HTTPAuthorizationCredentials = fastapi.Security(fastapi.security.HTTPBearer()),
|
||||
) -> models.Token:
|
||||
settings = app_settings.Settings()
|
||||
|
||||
token = authorization.credentials
|
||||
try:
|
||||
secret_key = settings.project.jwt_secret_key
|
||||
payload = jose.jwt.decode(token, secret_key, algorithms=[settings.project.jwt_algorithm])
|
||||
return models.Token(**payload)
|
||||
except (jose.JWTError, pydantic.ValidationError) as error:
|
||||
raise fastapi.HTTPException(
|
||||
status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
) from error
|
57
src/fastapi_app/poetry.lock
generated
57
src/fastapi_app/poetry.lock
generated
|
@ -162,6 +162,17 @@ d = ["aiohttp (>=3.7.4)"]
|
|||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2023.7.22"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
|
||||
{file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
|
@ -361,6 +372,50 @@ files = [
|
|||
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "0.18.0"
|
||||
description = "A minimal low-level HTTP client."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "httpcore-0.18.0-py3-none-any.whl", hash = "sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced"},
|
||||
{file = "httpcore-0.18.0.tar.gz", hash = "sha256:13b5e5cd1dca1a6636a6aaea212b19f4f85cd88c366a2b82304181b769aab3c9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=3.0,<5.0"
|
||||
certifi = "*"
|
||||
h11 = ">=0.13,<0.15"
|
||||
sniffio = "==1.*"
|
||||
|
||||
[package.extras]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.25.0"
|
||||
description = "The next generation HTTP client."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "httpx-0.25.0-py3-none-any.whl", hash = "sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100"},
|
||||
{file = "httpx-0.25.0.tar.gz", hash = "sha256:47ecda285389cb32bb2691cc6e069e3ab0205956f681c5b2ad2325719751d875"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = "*"
|
||||
httpcore = ">=0.18.0,<0.19.0"
|
||||
idna = "*"
|
||||
sniffio = "*"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli", "brotlicffi"]
|
||||
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
|
@ -1357,4 +1412,4 @@ files = [
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "f9ae9c843527beb7b8c58cae8cfbf5a6d4a2ef89d7b0a83f5fe30d9f8956fdc8"
|
||||
content-hash = "a1f51871ee88f7c8503f57105be988ea4ece9f41671d11a4464c382057acf3e7"
|
||||
|
|
|
@ -24,6 +24,7 @@ alembic = "^1.12.0"
|
|||
asyncpg = "^0.28.0"
|
||||
fastapi = "0.103.1"
|
||||
greenlet = "^2.0.2"
|
||||
httpx = "^0.25.0"
|
||||
orjson = "^3.9.7"
|
||||
psycopg2 = "^2.9.7"
|
||||
pydantic = {extras = ["email"], version = "^2.3.0"}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
.venv
|
||||
.env
|
|
@ -1,11 +0,0 @@
|
|||
LOG_LEVEL_HANDLERS=INFO
|
||||
LOG_LEVEL_LOGGERS=INFO
|
||||
LOG_LEVEL_ROOT=INFO
|
||||
API_PORT=8000
|
||||
|
||||
NGINX_PORT=80
|
||||
|
||||
PROJET_NAME="FastAPI Template"
|
||||
PROJECT_DESCRIPTION="FastAPI Template Project using DDD"
|
||||
PROJECT_VERSION=0.0.1
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"*.py": [
|
||||
".venv/bin/python -m black --check",
|
||||
".venv/bin/python -m isort --check",
|
||||
".venv/bin/python -m sort_all",
|
||||
".venv/bin/python -m pyupgrade --py311-plus --keep-runtime-typing",
|
||||
".venv/bin/python -m pylint",
|
||||
"../../node_modules/.bin/pyright"
|
||||
],
|
||||
"*.toml": [".venv/bin/toml-sort --check"]
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
FROM python:3.11
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
WORKDIR /opt/app
|
||||
|
||||
ENV PYTHONPATH '/opt/app'
|
||||
|
||||
COPY pyproject.toml ./
|
||||
COPY poetry.lock ./
|
||||
RUN apt-get update \
|
||||
&& pip install poetry \
|
||||
&& poetry config virtualenvs.create false \
|
||||
&& poetry install --no-dev
|
||||
|
||||
COPY backend .
|
||||
|
||||
# CMD ["python", "-m", "bin"]
|
|
@ -1,3 +0,0 @@
|
|||
include ../../common_makefile.mk
|
||||
|
||||
PROJECT_FOLDERS = backend tests
|
|
@ -1,3 +0,0 @@
|
|||
# Example monorepo package
|
||||
|
||||
...
|
|
@ -1,36 +0,0 @@
|
|||
import logging
|
||||
|
||||
import faker
|
||||
|
||||
import backend.user.handlers as user_handlers
|
||||
import backend.user.repositories as user_repositories
|
||||
import backend.user.services as user_services
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class App:
|
||||
def __init__(self):
|
||||
self._faker_client = faker.Faker()
|
||||
self._user_faker_client2 = user_repositories.UserFakerClient2(self._faker_client)
|
||||
self._user_service = user_services.UserService(self._user_faker_client2)
|
||||
|
||||
self._handler1 = user_handlers.UserHandler1(self._user_service)
|
||||
self._handler2 = user_handlers.UserHandler2(self._user_service)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
def run(self):
|
||||
logger.info(self._handler1.get_one())
|
||||
logger.info(self._handler2.get_one())
|
||||
|
||||
def close(self):
|
||||
logger.info("Closing app...")
|
||||
del self._faker_client
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = App()
|
||||
try:
|
||||
app.run()
|
||||
finally:
|
||||
app.close()
|
|
@ -1,20 +0,0 @@
|
|||
import backend.user.services as user_services
|
||||
import backend.utils.http as http_utils
|
||||
|
||||
|
||||
class UserHandler1:
|
||||
def __init__(self, user_service: user_services.UserService):
|
||||
self._user_service = user_service
|
||||
|
||||
def get_one(self) -> http_utils.Response:
|
||||
user = self._user_service.get_one(entity_id=1)
|
||||
return http_utils.get_response_from_dataclass(user)
|
||||
|
||||
|
||||
class UserHandler2:
|
||||
def __init__(self, user_service: user_services.UserService):
|
||||
self._user_service = user_service
|
||||
|
||||
def get_one(self) -> http_utils.Response:
|
||||
user = self._user_service.get_one(entity_id=2)
|
||||
return http_utils.get_response_from_dataclass(user)
|
|
@ -1,12 +0,0 @@
|
|||
import dataclasses
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class User:
|
||||
id: int # pylint: disable=C0103
|
||||
name: str
|
||||
|
||||
|
||||
__all__ = [
|
||||
"User",
|
||||
]
|
|
@ -1,23 +0,0 @@
|
|||
import faker
|
||||
|
||||
|
||||
class UserFakerClient:
|
||||
def __init__(self, faker_client: faker.Faker):
|
||||
self._faker_client = faker_client
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self._faker_client.name()
|
||||
|
||||
def get_email(self) -> str:
|
||||
return self._faker_client.email()
|
||||
|
||||
|
||||
class UserFakerClient2:
|
||||
def __init__(self, faker_client: faker.Faker):
|
||||
self._faker_client = faker_client
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self._faker_client.full_name()
|
||||
|
||||
def get_email(self) -> str:
|
||||
return self._faker_client.email()
|
|
@ -1,16 +0,0 @@
|
|||
import typing
|
||||
|
||||
import backend.user.models as models
|
||||
|
||||
|
||||
class UserClientProtocol(typing.Protocol):
|
||||
def get_name(self) -> str:
|
||||
...
|
||||
|
||||
|
||||
class UserService:
|
||||
def __init__(self, user_client: UserClientProtocol):
|
||||
self._user_client = user_client
|
||||
|
||||
def get_one(self, entity_id: int) -> models.User:
|
||||
return models.User(id=entity_id, name=self._user_client.get_name())
|
|
@ -1,20 +0,0 @@
|
|||
import dataclasses
|
||||
import json
|
||||
import typing
|
||||
|
||||
|
||||
class Handler(typing.Protocol):
|
||||
def __call__(self) -> "Response":
|
||||
...
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Response:
|
||||
code: int
|
||||
body: str
|
||||
|
||||
|
||||
def get_response_from_dataclass(body: object) -> Response:
|
||||
assert dataclasses.is_dataclass(body), "body must be a dataclass"
|
||||
|
||||
return Response(code=200, body=json.dumps(dataclasses.asdict(body)))
|
|
@ -1,29 +0,0 @@
|
|||
version: "3"
|
||||
|
||||
services:
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
ports:
|
||||
- "${API_PORT}:${API_PORT}"
|
||||
expose:
|
||||
- ${API_PORT}
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
nginx:
|
||||
image: nginx:1.25.1
|
||||
restart: always
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/templates:/etc/nginx/templates
|
||||
ports:
|
||||
- "${NGINX_PORT}:${NGINX_PORT}"
|
||||
depends_on:
|
||||
- api
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
|
@ -1,38 +0,0 @@
|
|||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
server_tokens off;
|
||||
|
||||
sendfile on;
|
||||
tcp_nodelay on;
|
||||
tcp_nopush on;
|
||||
client_max_body_size 200m;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 3;
|
||||
gzip_min_length 1000;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
application/json
|
||||
application/x-javascript
|
||||
text/xml
|
||||
text/javascript;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
include conf.d/api.conf;
|
||||
include conf.d/rabbitmq.conf;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
server {
|
||||
listen ${NGINX_PORT} default_server;
|
||||
listen [::]:${NGINX_PORT} default_server;
|
||||
server_name _;
|
||||
|
||||
location /api {
|
||||
proxy_pass http://api:${API_PORT}/api;
|
||||
proxy_set_header X-Request-Id $request_id;
|
||||
}
|
||||
|
||||
}
|
482
src/fastapi_example/poetry.lock
generated
482
src/fastapi_example/poetry.lock
generated
|
@ -1,482 +0,0 @@
|
|||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.15.6"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"},
|
||||
{file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
lazy-object-proxy = ">=1.4.0"
|
||||
wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "23.9.1"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"},
|
||||
{file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"},
|
||||
{file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"},
|
||||
{file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"},
|
||||
{file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"},
|
||||
{file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"},
|
||||
{file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"},
|
||||
{file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"},
|
||||
{file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"},
|
||||
{file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"},
|
||||
{file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"},
|
||||
{file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"},
|
||||
{file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"},
|
||||
{file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"},
|
||||
{file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"},
|
||||
{file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"},
|
||||
{file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"},
|
||||
{file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"},
|
||||
{file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"},
|
||||
{file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"},
|
||||
{file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"},
|
||||
{file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
packaging = ">=22.0"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.7.4)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dill"
|
||||
version = "0.3.7"
|
||||
description = "serialize all of Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
|
||||
{file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
graph = ["objgraph (>=1.7.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "faker"
|
||||
version = "19.6.1"
|
||||
description = "Faker is a Python package that generates fake data for you."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Faker-19.6.1-py3-none-any.whl", hash = "sha256:64c8513c53c3a809075ee527b323a0ba61517814123f3137e4912f5d43350139"},
|
||||
{file = "Faker-19.6.1.tar.gz", hash = "sha256:5d6b7880b3bea708075ddf91938424453f07053a59f8fa0453c1870df6ff3292"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
python-dateutil = ">=2.4"
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.12.0"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
optional = false
|
||||
python-versions = ">=3.8.0"
|
||||
files = [
|
||||
{file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
|
||||
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama (>=0.4.3)"]
|
||||
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
|
||||
plugins = ["setuptools"]
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-object-proxy"
|
||||
version = "1.9.0"
|
||||
description = "A fast and thorough lazy object proxy."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"},
|
||||
{file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.11.2"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
|
||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.10.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
|
||||
{file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.3.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
|
||||
{file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.17.5"
|
||||
description = "python code static checker"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"},
|
||||
{file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
astroid = ">=2.15.6,<=2.17.0-dev0"
|
||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||
dill = {version = ">=0.3.6", markers = "python_version >= \"3.11\""}
|
||||
isort = ">=4.2.5,<6"
|
||||
mccabe = ">=0.6,<0.8"
|
||||
platformdirs = ">=2.2.0"
|
||||
tomlkit = ">=0.10.1"
|
||||
|
||||
[package.extras]
|
||||
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||
testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"},
|
||||
{file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
files = [
|
||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
name = "pyupgrade"
|
||||
version = "3.11.1"
|
||||
description = "A tool to automatically upgrade syntax for newer versions."
|
||||
optional = false
|
||||
python-versions = ">=3.8.1"
|
||||
files = [
|
||||
{file = "pyupgrade-3.11.1-py2.py3-none-any.whl", hash = "sha256:6e9dd362394b3068123e06ca268de5845d41e2bb29f387b38323cc1009fb3100"},
|
||||
{file = "pyupgrade-3.11.1.tar.gz", hash = "sha256:3e6c7689d2f3ae418c6a60ee981477fe9130eccaed3e33dac6c21274cf7d45f4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tokenize-rt = ">=5.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sort-all"
|
||||
version = "1.2.0"
|
||||
description = "Automatically Sort __all__ records alphabetically"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "sort_all-1.2.0-py3-none-any.whl", hash = "sha256:ccc0fc7191a486ff826cb4d21c2b67d93f9d9cb5eb72e8d572d017d50d4eca88"},
|
||||
{file = "sort_all-1.2.0.tar.gz", hash = "sha256:1eb6a91cc61f36bd48d697f687377c6eb67b4ef98e2850fc65130502bae945d8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tokenize-rt = ">=3.0.1"
|
||||
|
||||
[[package]]
|
||||
name = "tokenize-rt"
|
||||
version = "5.2.0"
|
||||
description = "A wrapper around the stdlib `tokenize` which roundtrips."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tokenize_rt-5.2.0-py2.py3-none-any.whl", hash = "sha256:b79d41a65cfec71285433511b50271b05da3584a1da144a0752e9c621a285289"},
|
||||
{file = "tokenize_rt-5.2.0.tar.gz", hash = "sha256:9fe80f8a5c1edad2d3ede0f37481cc0cc1538a2f442c9c2f9e4feacd2792d054"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml-sort"
|
||||
version = "0.23.1"
|
||||
description = "Toml sorting library"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
files = [
|
||||
{file = "toml_sort-0.23.1-py3-none-any.whl", hash = "sha256:69ae60de9c4d67478533697eb4119092e2b30ddffe5ca09bbad3912905c935a0"},
|
||||
{file = "toml_sort-0.23.1.tar.gz", hash = "sha256:833728c48b0f8d509aecd9ae8347768ca3a9332977b32c9fd2002932f0eb9c90"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tomlkit = ">=0.11.2"
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.12.1"
|
||||
description = "Style preserving TOML library"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
|
||||
{file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrapt"
|
||||
version = "1.15.0"
|
||||
description = "Module for decorators, wrappers and monkey patching."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
files = [
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"},
|
||||
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"},
|
||||
{file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"},
|
||||
{file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"},
|
||||
{file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"},
|
||||
{file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"},
|
||||
{file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"},
|
||||
{file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"},
|
||||
{file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"},
|
||||
{file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"},
|
||||
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "e25f13be31f469d85a4a042b9d4c52f6828b417fcb114065ccf94b789353e743"
|
|
@ -1,3 +0,0 @@
|
|||
[virtualenvs]
|
||||
create = true
|
||||
in-project = true
|
|
@ -1,74 +0,0 @@
|
|||
[build-system]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
||||
[tool.black]
|
||||
known_first_party = ["backend", "tests"]
|
||||
line-length = 120
|
||||
target-version = ["py311"]
|
||||
|
||||
[tool.isort]
|
||||
line_length = 120
|
||||
profile = "black"
|
||||
|
||||
[tool.poetry]
|
||||
authors = ["name <name@email.com>"]
|
||||
description = "FastAPI Template Project using DDD"
|
||||
name = "FastAPI Template"
|
||||
version = "0.0.1"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
black = "^23.9.1"
|
||||
faker = "^19.6.1"
|
||||
isort = "^5.12.0"
|
||||
pylint = "^2.17.5"
|
||||
pytest = "^7.4.2"
|
||||
python = "^3.11"
|
||||
pyupgrade = "^3.11.0"
|
||||
sort-all = "^1.2.0"
|
||||
toml-sort = "^0.23.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[tool.pylint]
|
||||
disable = [
|
||||
"broad-except",
|
||||
"consider-using-from-import",
|
||||
"consider-using-sys-exit",
|
||||
"duplicate-code",
|
||||
"missing-docstring",
|
||||
"protected-access",
|
||||
"too-few-public-methods"
|
||||
]
|
||||
ignore-paths = ["^.*venv/.*$"]
|
||||
max-line-length = 120
|
||||
recursive = true
|
||||
|
||||
[tool.pylint.basic]
|
||||
argument-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||
class-attribute-rgx = "^_{0,2}[a-zA-Z][a-zA-Z0-9_]*$"
|
||||
variable-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||
|
||||
[tool.pylint.typecheck]
|
||||
signature-mutators = "click.decorators.option"
|
||||
|
||||
[tool.pyright]
|
||||
exclude = ["**/__pycache__"]
|
||||
include = ["backend", "tests"]
|
||||
pythonPlatform = "All"
|
||||
pythonVersion = "3.11"
|
||||
reportConstantRedefinition = "none"
|
||||
reportMissingTypeStubs = "warning"
|
||||
reportPrivateUsage = "information"
|
||||
reportPropertyTypeMismatch = "warning"
|
||||
reportUninitializedInstanceVariable = "warning"
|
||||
reportUnknownMemberType = "none"
|
||||
reportUnnecessaryTypeIgnoreComment = "warning"
|
||||
typeCheckingMode = "strict"
|
||||
useLibraryCodeForTypes = true
|
||||
venv = ".venv"
|
||||
venvPath = '.'
|
||||
|
||||
[tool.tomlsort]
|
||||
all = true
|
||||
in_place = true
|
|
@ -1,2 +0,0 @@
|
|||
.venv/
|
||||
tests/
|
13
src/python-service/.gitignore
vendored
13
src/python-service/.gitignore
vendored
|
@ -1,13 +0,0 @@
|
|||
# Python dependencies
|
||||
.venv/
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
|
||||
# Coverage reports
|
||||
/.coverage
|
||||
htmlcov/
|
||||
|
||||
# Environment variables
|
||||
.env
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"*.py": [
|
||||
".venv/bin/python -m black --check",
|
||||
".venv/bin/python -m isort --check",
|
||||
".venv/bin/python -m sort_all",
|
||||
".venv/bin/python -m pyupgrade --py311-plus",
|
||||
".venv/bin/python -m pylint",
|
||||
"../node_modules/.bin/pyright"
|
||||
],
|
||||
"*.toml": [".venv/bin/toml-sort --check"]
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
# Python dependencies
|
||||
.venv/
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
|
||||
# Coverage reports
|
||||
/.coverage
|
||||
|
||||
# Environment variables
|
||||
.env
|
|
@ -1,19 +0,0 @@
|
|||
FROM ghcr.io/yp-middle-python-24/python-dev:3.10-jammy-0.0.1 AS builder
|
||||
|
||||
RUN mkdir --parents /opt/app
|
||||
COPY pyproject.toml /opt/app/pyproject.toml
|
||||
COPY poetry.lock /opt/app/poetry.lock
|
||||
COPY poetry.toml /opt/app/poetry.toml
|
||||
|
||||
WORKDIR /opt/app
|
||||
RUN poetry install --no-dev
|
||||
|
||||
FROM ghcr.io/yp-middle-python-24/python:3.10-jammy-0.0.1 AS runtime
|
||||
|
||||
RUN mkdir --parents /opt/app
|
||||
COPY --from=builder /opt/app/.venv /opt/app/.venv
|
||||
COPY bin /opt/app/bin
|
||||
COPY lib /opt/app/lib
|
||||
|
||||
WORKDIR /opt/app
|
||||
CMD [".venv/bin/python", "-m", "bin.main"]
|
|
@ -1,3 +0,0 @@
|
|||
include ../../common_makefile.mk
|
||||
|
||||
PROJECT_FOLDERS = bin lib tests
|
|
@ -1,28 +0,0 @@
|
|||
# Python Service Example Backend
|
||||
|
||||
Python Service Example Backend
|
||||
|
||||
## Development
|
||||
|
||||
### Global dependencies
|
||||
|
||||
- poetry
|
||||
|
||||
### Makefile commands
|
||||
|
||||
- `make init` - Initialize service
|
||||
- `make lint` - Lint service
|
||||
- `make lint-fix` - Auto-fix service
|
||||
- `make test` - Test service
|
||||
- `make clean` - Clean up service
|
||||
- `make dev-server-start` - Start dev server
|
||||
- `make test-coverage-run` - Collect test coverage data
|
||||
- `make test-coverage-report` - Show coverage report in console
|
||||
- `make test-coverage-html` - Prepare and show coverage report in browser
|
||||
- `make ci-image-build` - Build production container
|
||||
- `make ci-image-push` - Push production container to yccr
|
||||
|
||||
### Environment variables
|
||||
|
||||
- `APP_ENV` - Application environment (development, production, etc.)
|
||||
- `APP_VERSION` - Application version
|
|
@ -1,37 +0,0 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
import lib.app as app
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def run() -> None:
|
||||
settings = app.Settings()
|
||||
application = app.Application.from_settings(settings)
|
||||
|
||||
try:
|
||||
await application.start()
|
||||
finally:
|
||||
await application.dispose()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
try:
|
||||
asyncio.run(run())
|
||||
exit(os.EX_OK)
|
||||
except SystemExit:
|
||||
exit(os.EX_OK)
|
||||
except app.ApplicationError:
|
||||
exit(os.EX_SOFTWARE)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Exited with keyboard interruption")
|
||||
exit(os.EX_OK)
|
||||
except BaseException:
|
||||
logger.exception("Unexpected error occurred")
|
||||
exit(os.EX_SOFTWARE)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,5 +0,0 @@
|
|||
from .liveness_probe import LivenessProbeHandler
|
||||
|
||||
__all__ = [
|
||||
"LivenessProbeHandler",
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
import json
|
||||
|
||||
import aiohttp.web as aiohttp_web
|
||||
import lib.utils.aiohttp as aiohttp_utils
|
||||
|
||||
|
||||
class LivenessProbeHandler(aiohttp_utils.HandlerProtocol):
|
||||
async def process(self, request: aiohttp_web.Request) -> aiohttp_web.Response:
|
||||
return aiohttp_web.Response(
|
||||
status=200,
|
||||
body=json.dumps(obj={"status": "healthy"}),
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"LivenessProbeHandler",
|
||||
]
|
|
@ -1,11 +0,0 @@
|
|||
from .app import Application
|
||||
from .errors import ApplicationError, DisposeError, StartServerError
|
||||
from .settings import Settings
|
||||
|
||||
__all__ = [
|
||||
"Application",
|
||||
"ApplicationError",
|
||||
"DisposeError",
|
||||
"Settings",
|
||||
"StartServerError",
|
||||
]
|
|
@ -1,134 +0,0 @@
|
|||
import asyncio
|
||||
import dataclasses
|
||||
import logging
|
||||
import typing
|
||||
|
||||
import aiohttp.web as aiohttp_web
|
||||
import lib.api.rest.v1.health as health_handlers
|
||||
import lib.app.errors as app_errors
|
||||
import lib.app.settings as app_settings
|
||||
import typing_extensions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class DisposableResource:
|
||||
name: str
|
||||
dispose_callback: typing.Awaitable[typing.Any]
|
||||
|
||||
|
||||
class Application:
|
||||
def __init__(
|
||||
self,
|
||||
settings: app_settings.Settings,
|
||||
aio_app: aiohttp_web.Application,
|
||||
disposable_resources: typing.Sequence[DisposableResource],
|
||||
) -> None:
|
||||
self._settings = settings
|
||||
self._aio_app = aio_app
|
||||
self._disposable_resources = disposable_resources
|
||||
|
||||
@classmethod
|
||||
def from_settings(cls, settings: app_settings.Settings) -> typing_extensions.Self:
|
||||
# Logging
|
||||
|
||||
logging.basicConfig(
|
||||
level=settings.LOGS_MIN_LEVEL,
|
||||
format=settings.LOGS_FORMAT,
|
||||
)
|
||||
|
||||
logger.info("Initializing application")
|
||||
disposable_resources = []
|
||||
|
||||
# Global clients
|
||||
|
||||
logger.info("Initializing global clients")
|
||||
|
||||
# Clients
|
||||
|
||||
logger.info("Initializing clients")
|
||||
|
||||
# Repositories
|
||||
|
||||
logger.info("Initializing repositories")
|
||||
|
||||
# Caches
|
||||
|
||||
logger.info("Initializing caches")
|
||||
|
||||
# Services
|
||||
|
||||
logger.info("Initializing services")
|
||||
|
||||
# Handlers
|
||||
|
||||
logger.info("Initializing handlers")
|
||||
liveness_probe_handler = health_handlers.LivenessProbeHandler()
|
||||
|
||||
logger.info("Creating application")
|
||||
aio_app = aiohttp_web.Application()
|
||||
|
||||
# Routes
|
||||
aio_app.add_routes(
|
||||
[
|
||||
aiohttp_web.get(
|
||||
"/api/v1/health/liveness",
|
||||
liveness_probe_handler.process,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
application = Application(
|
||||
settings=settings,
|
||||
aio_app=aio_app,
|
||||
disposable_resources=disposable_resources,
|
||||
)
|
||||
|
||||
logger.info("Initializing application finished")
|
||||
|
||||
return application
|
||||
|
||||
async def start(self) -> None:
|
||||
logger.info("Discord server is starting")
|
||||
|
||||
try:
|
||||
await aiohttp_web._run_app(
|
||||
app=self._aio_app,
|
||||
host=self._settings.SERVER_HOST,
|
||||
port=self._settings.SERVER_PORT,
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
logger.info("HTTP server has been interrupted")
|
||||
except BaseException as unexpected_error:
|
||||
logger.exception("HTTP server failed to start")
|
||||
raise app_errors.StartServerError(
|
||||
"HTTP server failed to start"
|
||||
) from unexpected_error
|
||||
|
||||
async def dispose(self) -> None:
|
||||
logger.info("Application is shutting down...")
|
||||
dispose_errors = []
|
||||
|
||||
for resource in self._disposable_resources:
|
||||
logger.info("Disposing %s...", resource.name)
|
||||
try:
|
||||
await resource.dispose_callback
|
||||
except Exception as unexpected_error:
|
||||
dispose_errors.append(unexpected_error)
|
||||
logger.exception("Failed to dispose %s", resource.name)
|
||||
else:
|
||||
logger.info("%s has been disposed", resource.name)
|
||||
|
||||
if len(dispose_errors) != 0:
|
||||
logger.error("Application has shut down with errors")
|
||||
raise app_errors.DisposeError(
|
||||
"Application has shut down with errors, see logs above"
|
||||
)
|
||||
|
||||
logger.info("Application has successfully shut down")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Application",
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
import typing
|
||||
|
||||
|
||||
class ApplicationError(Exception):
|
||||
def __init__(self, message: str, *args: typing.Any) -> None:
|
||||
super().__init__(*args)
|
||||
self.message = message
|
||||
|
||||
|
||||
class DisposeError(ApplicationError):
|
||||
pass
|
||||
|
||||
|
||||
class StartServerError(ApplicationError):
|
||||
pass
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ApplicationError",
|
||||
"DisposeError",
|
||||
"StartServerError",
|
||||
]
|
|
@ -1,32 +0,0 @@
|
|||
import typing
|
||||
|
||||
import pydantic
|
||||
|
||||
LogLevel = typing.Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]
|
||||
|
||||
|
||||
class Settings(pydantic.BaseSettings):
|
||||
# App
|
||||
|
||||
APP_ENV: str = "development"
|
||||
APP_NAME: str = "discord-chatbot-backend"
|
||||
APP_VERSION: str = "0.0.1"
|
||||
|
||||
# Logging
|
||||
|
||||
LOGS_MIN_LEVEL: LogLevel = "DEBUG"
|
||||
LOGS_FORMAT: str = "%(asctime)s | %(name)s | %(levelname)s | %(message)s"
|
||||
|
||||
# Server
|
||||
|
||||
SERVER_HOST: str = "localhost"
|
||||
SERVER_PORT: int = 8080
|
||||
|
||||
@property
|
||||
def is_development(self) -> bool:
|
||||
return self.APP_ENV == "development"
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Settings",
|
||||
]
|
|
@ -1,5 +0,0 @@
|
|||
from .types import HandlerProtocol
|
||||
|
||||
__all__ = [
|
||||
"HandlerProtocol",
|
||||
]
|
|
@ -1,5 +0,0 @@
|
|||
from .handler import HandlerProtocol
|
||||
|
||||
__all__ = [
|
||||
"HandlerProtocol",
|
||||
]
|
|
@ -1,13 +0,0 @@
|
|||
import typing
|
||||
|
||||
import aiohttp.web as aiohttp_web
|
||||
|
||||
|
||||
class HandlerProtocol(typing.Protocol):
|
||||
async def process(self, request: aiohttp_web.Request) -> aiohttp_web.Response:
|
||||
...
|
||||
|
||||
|
||||
__all__ = [
|
||||
"HandlerProtocol",
|
||||
]
|
1186
src/python-service/poetry.lock
generated
1186
src/python-service/poetry.lock
generated
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +0,0 @@
|
|||
[virtualenvs]
|
||||
create = true
|
||||
in-project = true
|
|
@ -1,121 +0,0 @@
|
|||
[build-system]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
target-version = ["py311"]
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"def __repr__",
|
||||
"raise NotImplementedError",
|
||||
"if __name__ == .__main__.:",
|
||||
"class .*Protocol\\):",
|
||||
"@(abc\\.)?abstractmethod",
|
||||
"if typing.TYPE_CHECKING:",
|
||||
]
|
||||
|
||||
[tool.coverage.run]
|
||||
include = ["bin/*", "lib/*"]
|
||||
|
||||
[tool.isort]
|
||||
known_first_party = ["bin", "lib", "tests"]
|
||||
line_length = 120
|
||||
profile = "black"
|
||||
py_version = 311
|
||||
|
||||
[tool.poetry]
|
||||
authors = ["ovsds <ovsds@yandex-team.ru>"]
|
||||
description = "Python Service Example Backend"
|
||||
name = "python-service-example-backend"
|
||||
version = "0.0.1"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
aiohttp = "3.8.4"
|
||||
pydantic = {extras = ["dotenv"], version = "1.10.2"}
|
||||
python = "~3.11"
|
||||
typing-extensions = "4.5.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
black = "22.6.0"
|
||||
coverage = "6.5.0"
|
||||
isort = "5.10.1"
|
||||
pylint = "2.14.5"
|
||||
pylint-pydantic = "0.1.4"
|
||||
pylint-pytest = "1.1.2"
|
||||
pytest = "7.1.2"
|
||||
pytest-asyncio = "0.19.0"
|
||||
pytest-mock = "3.8.2"
|
||||
pyupgrade = "3.1.0"
|
||||
sort-all = "1.2.0"
|
||||
toml-sort = "0.20.0"
|
||||
|
||||
[tool.pylint]
|
||||
disable = [
|
||||
"broad-except",
|
||||
"consider-using-from-import",
|
||||
"consider-using-sys-exit",
|
||||
"duplicate-code",
|
||||
"fixme",
|
||||
"missing-docstring",
|
||||
"no-member",
|
||||
"protected-access",
|
||||
"too-few-public-methods",
|
||||
"too-many-instance-attributes",
|
||||
"too-many-locals",
|
||||
"too-many-statements",
|
||||
"unnecessary-ellipsis",
|
||||
]
|
||||
extension-pkg-allow-list = [
|
||||
"pydantic", # https://github.com/samuelcolvin/pydantic/issues/1961
|
||||
]
|
||||
ignore-paths = [
|
||||
"^.*venv/.*$",
|
||||
]
|
||||
load-plugins = [
|
||||
"pylint_pydantic",
|
||||
"pylint_pytest",
|
||||
]
|
||||
max-args = 10
|
||||
max-line-length = 120
|
||||
recursive = true
|
||||
|
||||
[tool.pylint.basic]
|
||||
argument-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||
attr-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||
class-attribute-rgx = "^_{0,2}[a-zA-Z][a-zA-Z0-9_]*$"
|
||||
variable-rgx = "^_{0,2}[a-z][a-z0-9_]*$"
|
||||
|
||||
[tool.pyright]
|
||||
exclude = [
|
||||
"**/__pycache__",
|
||||
]
|
||||
include = [
|
||||
"bin",
|
||||
"lib",
|
||||
"tests",
|
||||
]
|
||||
pythonPlatform = "All"
|
||||
pythonVersion = "3.11"
|
||||
reportConstantRedefinition = "none"
|
||||
reportMissingTypeStubs = "warning"
|
||||
reportPrivateUsage = "information"
|
||||
reportPropertyTypeMismatch = "warning"
|
||||
reportUninitializedInstanceVariable = "warning"
|
||||
reportUnknownMemberType = "none"
|
||||
reportUnnecessaryTypeIgnoreComment = "warning"
|
||||
reportUntypedFunctionDecorator = "warning"
|
||||
typeCheckingMode = "strict"
|
||||
useLibraryCodeForTypes = true
|
||||
venv = ".venv"
|
||||
venvPath = '.'
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
pythonpath = "."
|
||||
|
||||
[tool.tomlsort]
|
||||
all = true
|
||||
ignore_case = true
|
||||
in_place = true
|
Loading…
Reference in New Issue
Block a user