style: ruff format и правки линтера на каркасе шаблона
Без смены поведения: форматирование, сортировка импортов, удаление неиспользуемых импортов, __all__ в src/db, datetime.UTC, HTTPStatus.NOT_FOUND вместо 404, аннотация lvl в logger, noqa F401 на проверке доступности raisa_fastapi_protected_api, mypy: miniopy_async не подтягивается (follow_imports=skip). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
bf63d3a9dc
commit
72415ab891
@ -1,12 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
from sqlalchemy import engine_from_config
|
from sqlalchemy import engine_from_config, pool
|
||||||
from sqlalchemy import pool
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncEngine
|
from sqlalchemy.ext.asyncio import AsyncEngine
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
from src.core.config import settings
|
from src.core.config import settings
|
||||||
from src.models import Base # noqa: F401 — модели регистрируются в src/models/__init__.py
|
from src.models import Base # noqa: F401 — модели регистрируются в src/models/__init__.py
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
config = context.config
|
config = context.config
|
||||||
@ -28,9 +29,10 @@ target_metadata = Base.metadata
|
|||||||
# my_important_option = config.get_main_option("my_important_option")
|
# my_important_option = config.get_main_option("my_important_option")
|
||||||
# ... etc.
|
# ... etc.
|
||||||
|
|
||||||
|
|
||||||
def include_name(name, type_, parent_names):
|
def include_name(name, type_, parent_names):
|
||||||
if type_ == 'schema':
|
if type_ == "schema":
|
||||||
return name == 'dkb'
|
return name == "dkb"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -41,12 +43,13 @@ def do_run_migrations(connection) -> None:
|
|||||||
compare_type=True,
|
compare_type=True,
|
||||||
version_table_schema="dkb",
|
version_table_schema="dkb",
|
||||||
include_schemas=True,
|
include_schemas=True,
|
||||||
include_name=include_name
|
include_name=include_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
with context.begin_transaction():
|
with context.begin_transaction():
|
||||||
context.run_migrations()
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
"""Run migrations in 'offline' mode.
|
"""Run migrations in 'offline' mode.
|
||||||
|
|
||||||
@ -67,7 +70,7 @@ def run_migrations_offline() -> None:
|
|||||||
dialect_opts={"paramstyle": "named"},
|
dialect_opts={"paramstyle": "named"},
|
||||||
version_table_schema="dkb",
|
version_table_schema="dkb",
|
||||||
include_schemas=True,
|
include_schemas=True,
|
||||||
include_name=include_name
|
include_name=include_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
with context.begin_transaction():
|
with context.begin_transaction():
|
||||||
@ -83,10 +86,7 @@ async def run_migrations_online() -> None:
|
|||||||
"""
|
"""
|
||||||
connectable = AsyncEngine(
|
connectable = AsyncEngine(
|
||||||
engine_from_config(
|
engine_from_config(
|
||||||
config.get_section(config.config_ini_section),
|
config.get_section(config.config_ini_section), prefix="sqlalchemy.", poolclass=pool.NullPool, future=True
|
||||||
prefix="sqlalchemy.",
|
|
||||||
poolclass=pool.NullPool,
|
|
||||||
future=True
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -36,5 +36,11 @@ extra_checks = true
|
|||||||
|
|
||||||
# Сторонние пакеты без типов (или недоступные вне банка)
|
# Сторонние пакеты без типов (или недоступные вне банка)
|
||||||
[[tool.mypy.overrides]]
|
[[tool.mypy.overrides]]
|
||||||
module = ["smbclient.*", "nkeys.*", "miniopy_async.*", "nats.*", "raisa_fastapi_protected_api", "raisa_fastapi_protected_api.*", "pydbml.*"]
|
module = ["smbclient.*", "nkeys.*", "nats.*", "raisa_fastapi_protected_api", "raisa_fastapi_protected_api.*", "pydbml.*"]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
# miniopy_async: пакет типизирован с ошибкой (Minio не виден mypy при реэкспорте) — типы не подтягиваем, Minio = Any
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = ["miniopy_async", "miniopy_async.*"]
|
||||||
|
follow_imports = "skip"
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from src import app, get_settings
|
from src import app, get_settings
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -9,4 +10,3 @@ if __name__ == "__main__":
|
|||||||
port=settings.server.PORT,
|
port=settings.server.PORT,
|
||||||
lifespan="on",
|
lifespan="on",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,6 @@ from .app import app
|
|||||||
from .core.config import get_settings
|
from .core.config import get_settings
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'app',
|
"app",
|
||||||
'get_settings',
|
"get_settings",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -5,10 +5,12 @@ middleware (gzip, proxy headers, CORS, РАИСА при DEBUG=False), healthche
|
|||||||
Что добавляет Срез 0: роутеры в src/api/router.py, outbox-паблишер и consumer recognition.result
|
Что добавляет Срез 0: роутеры в src/api/router.py, outbox-паблишер и consumer recognition.result
|
||||||
(docs/context/03-architecture.md), зависимость require(permission).
|
(docs/context/03-architecture.md), зависимость require(permission).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
|
from http import HTTPStatus
|
||||||
|
|
||||||
import nkeys
|
import nkeys
|
||||||
import smbclient
|
import smbclient
|
||||||
@ -30,7 +32,7 @@ from src.core.exception_handlers import register_exception_handlers
|
|||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
||||||
VERSION = settings.VERSION
|
VERSION = settings.VERSION
|
||||||
UP_TIME = datetime.now(timezone.utc)
|
UP_TIME = datetime.now(UTC)
|
||||||
|
|
||||||
|
|
||||||
# --- NATS: аутентификация по nkeys/JWT ---------------------------------------------------------
|
# --- NATS: аутентификация по nkeys/JWT ---------------------------------------------------------
|
||||||
@ -51,7 +53,7 @@ def sig_cb(nonce):
|
|||||||
protected_middleware_available = False
|
protected_middleware_available = False
|
||||||
if not settings.DEBUG:
|
if not settings.DEBUG:
|
||||||
try:
|
try:
|
||||||
from raisa_fastapi_protected_api import ( # pyright: ignore[reportMissingImports]
|
from raisa_fastapi_protected_api import ( # noqa: F401 # pyright: ignore[reportMissingImports]
|
||||||
AuthorizationMiddleware,
|
AuthorizationMiddleware,
|
||||||
OpenEndpoint,
|
OpenEndpoint,
|
||||||
ProtectedOAuthSettings,
|
ProtectedOAuthSettings,
|
||||||
@ -177,7 +179,7 @@ class SPAStaticFiles(StaticFiles):
|
|||||||
try:
|
try:
|
||||||
return await super().get_response(path, scope)
|
return await super().get_response(path, scope)
|
||||||
except (HTTPException, StarletteHTTPException) as ex:
|
except (HTTPException, StarletteHTTPException) as ex:
|
||||||
if ex.status_code == 404:
|
if ex.status_code == HTTPStatus.NOT_FOUND:
|
||||||
if "images" in path:
|
if "images" in path:
|
||||||
return await super().get_response(sep_static(path, "images"), scope)
|
return await super().get_response(sep_static(path, "images"), scope)
|
||||||
if "static" in path:
|
if "static" in path:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CouldntCreateError(Exception):
|
class CouldntCreateError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
"""Клиенты инфраструктуры. Каркас: оставлен S3Storage; outbox-паблишер (PollWorker) реализуется в Срезе 0
|
"""Клиенты инфраструктуры. Каркас: оставлен S3Storage; outbox-паблишер (PollWorker) реализуется в Срезе 0
|
||||||
по docs/context/03-architecture.md (референс — reference-old-arm/api/src/core/clients.py).
|
по docs/context/03-architecture.md (референс — reference-old-arm/api/src/core/clients.py).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from miniopy_async import Minio
|
from miniopy_async import Minio
|
||||||
@ -10,11 +11,11 @@ class S3Storage:
|
|||||||
def __init__(self, client: Minio, bucket_name: str):
|
def __init__(self, client: Minio, bucket_name: str):
|
||||||
self.client = client
|
self.client = client
|
||||||
self.bucket = bucket_name
|
self.bucket = bucket_name
|
||||||
|
|
||||||
async def put_object(self, obj_name, file_data):
|
async def put_object(self, obj_name, file_data):
|
||||||
try:
|
try:
|
||||||
stream = BytesIO(file_data)
|
stream = BytesIO(file_data)
|
||||||
await self.client.put_object(self.bucket, obj_name, stream, length=len(file_data))
|
await self.client.put_object(self.bucket, obj_name, stream, length=len(file_data))
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -23,5 +24,5 @@ class S3Storage:
|
|||||||
response = await self.client.get_object(self.bucket, obj_name)
|
response = await self.client.get_object(self.bucket, obj_name)
|
||||||
# file_bytes = await response.content.read()
|
# file_bytes = await response.content.read()
|
||||||
return response
|
return response
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|||||||
@ -1,42 +1,48 @@
|
|||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
class DBSettings(BaseSettings):
|
class DBSettings(BaseSettings):
|
||||||
DATABASE_URL: str
|
DATABASE_URL: str
|
||||||
|
|
||||||
|
|
||||||
class MinioSettings(BaseSettings):
|
class MinioSettings(BaseSettings):
|
||||||
MINIO_URL: str
|
MINIO_URL: str
|
||||||
MINIO_ADMIN_LOGIN: str
|
MINIO_ADMIN_LOGIN: str
|
||||||
MINIO_ADMIN_PASSWORD: str
|
MINIO_ADMIN_PASSWORD: str
|
||||||
MINIO_BUCKET: str
|
MINIO_BUCKET: str
|
||||||
|
|
||||||
|
|
||||||
class NATSSettings(BaseSettings):
|
class NATSSettings(BaseSettings):
|
||||||
NATS_URL: str
|
NATS_URL: str
|
||||||
NATS_SEED: str
|
NATS_SEED: str
|
||||||
NATS_JWT: str
|
NATS_JWT: str
|
||||||
|
|
||||||
|
|
||||||
class SMBSettings(BaseSettings):
|
class SMBSettings(BaseSettings):
|
||||||
SMB_HOST: str
|
SMB_HOST: str
|
||||||
SMB_PATH: str
|
SMB_PATH: str
|
||||||
SMB_LOGIN: str
|
SMB_LOGIN: str
|
||||||
SMB_PASSWORD: str
|
SMB_PASSWORD: str
|
||||||
|
|
||||||
|
|
||||||
class OpenBAOSettings(BaseSettings):
|
class OpenBAOSettings(BaseSettings):
|
||||||
DATABASE: DBSettings
|
DATABASE: DBSettings
|
||||||
MINIO: MinioSettings
|
MINIO: MinioSettings
|
||||||
NATS: NATSSettings
|
NATS: NATSSettings
|
||||||
SMB: SMBSettings
|
SMB: SMBSettings
|
||||||
|
|
||||||
|
|
||||||
class ServerSettings(BaseSettings):
|
class ServerSettings(BaseSettings):
|
||||||
HOST: str = "0.0.0.0"
|
HOST: str = "0.0.0.0"
|
||||||
PORT: int = 8000
|
PORT: int = 8000
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
OPENBAO: OpenBAOSettings
|
OPENBAO: OpenBAOSettings
|
||||||
DEBUG: bool = False
|
DEBUG: bool = False
|
||||||
server: ServerSettings = ServerSettings()
|
server: ServerSettings = ServerSettings()
|
||||||
ROOT_PATH: str = '/'
|
ROOT_PATH: str = "/"
|
||||||
VERSION: str = '1.0.0'
|
VERSION: str = "1.0.0"
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
extra = "ignore"
|
extra = "ignore"
|
||||||
@ -44,7 +50,9 @@ class Settings(BaseSettings):
|
|||||||
env_nested_delimiter = "__"
|
env_nested_delimiter = "__"
|
||||||
nested_model_default_partial_update = False
|
nested_model_default_partial_update = False
|
||||||
|
|
||||||
|
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
return Settings()
|
return Settings()
|
||||||
|
|
||||||
settings = get_settings()
|
|
||||||
|
settings = get_settings()
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import sys
|
|||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
# Периодические пробы мониторинга/оркестратора и служебные doc-эндпоинты.
|
# Периодические пробы мониторинга/оркестратора и служебные doc-эндпоинты.
|
||||||
NOISE_PATHS: tuple[str, ...] = (
|
NOISE_PATHS: tuple[str, ...] = (
|
||||||
"/healthcheck",
|
"/healthcheck",
|
||||||
@ -22,8 +21,20 @@ _NOISE_MARKERS: tuple[str, ...] = ("/static/", "/static-swagger/")
|
|||||||
|
|
||||||
# Расширения статических ассетов (картинки, стили, скрипты, шрифты).
|
# Расширения статических ассетов (картинки, стили, скрипты, шрифты).
|
||||||
_STATIC_SUFFIXES: tuple[str, ...] = (
|
_STATIC_SUFFIXES: tuple[str, ...] = (
|
||||||
".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp",
|
".png",
|
||||||
".css", ".js", ".map", ".woff", ".woff2", ".ttf", ".eot",
|
".jpg",
|
||||||
|
".jpeg",
|
||||||
|
".gif",
|
||||||
|
".svg",
|
||||||
|
".ico",
|
||||||
|
".webp",
|
||||||
|
".css",
|
||||||
|
".js",
|
||||||
|
".map",
|
||||||
|
".woff",
|
||||||
|
".woff2",
|
||||||
|
".ttf",
|
||||||
|
".eot",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -74,7 +85,7 @@ def setup_logger(
|
|||||||
class InterceptHandler(logging.Handler):
|
class InterceptHandler(logging.Handler):
|
||||||
def emit(self, record: logging.LogRecord) -> None:
|
def emit(self, record: logging.LogRecord) -> None:
|
||||||
try:
|
try:
|
||||||
lvl = logger.level(record.levelname).name
|
lvl: str | int = logger.level(record.levelname).name
|
||||||
except ValueError:
|
except ValueError:
|
||||||
lvl = record.levelno
|
lvl = record.levelno
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
маппинг JSON из S3 в document/osv_entry/financial_statement_*) реализуется в Срезе 0–2 по
|
маппинг JSON из S3 в document/osv_entry/financial_statement_*) реализуется в Срезе 0–2 по
|
||||||
docs/context/03-architecture.md. Для референса — reference-old-arm/api/src/core/nats_callback.py.
|
docs/context/03-architecture.md. Для референса — reference-old-arm/api/src/core/nats_callback.py.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from nats.aio.client import Client as NATS
|
from nats.aio.client import Client as NATS
|
||||||
|
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
from .db import get_async_session
|
from .db import get_async_session
|
||||||
|
|
||||||
|
__all__ = ["get_async_session"]
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
from contextlib import asynccontextmanager
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine, AsyncSession
|
|
||||||
from fastapi import Depends
|
|
||||||
# from fastapi_users.db import SQLAlchemyUserDatabase, SQLAlchemyBaseUserTableUUID
|
# from fastapi_users.db import SQLAlchemyUserDatabase, SQLAlchemyBaseUserTableUUID
|
||||||
from src.core.config import settings
|
from src.core.config import settings
|
||||||
|
|
||||||
engine = create_async_engine(settings.OPENBAO.DATABASE.DATABASE_URL, connect_args={"server_settings": {"search_path": 'dkb'}})
|
engine = create_async_engine(
|
||||||
|
settings.OPENBAO.DATABASE.DATABASE_URL, connect_args={"server_settings": {"search_path": "dkb"}}
|
||||||
|
)
|
||||||
async_session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
@ -13,4 +13,3 @@ async_session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_
|
|||||||
async def get_async_session():
|
async def get_async_session():
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
"""ORM-модели. Источник истины — docs/model/data-model-v5.13.dbml; заполняется в Срезе 0."""
|
"""ORM-модели. Источник истины — docs/model/data-model-v5.13.dbml; заполняется в Срезе 0."""
|
||||||
|
|
||||||
from .base import Base, UUIDPrimaryMixin
|
from .base import Base, UUIDPrimaryMixin
|
||||||
|
|
||||||
__all__ = ["Base", "UUIDPrimaryMixin"]
|
__all__ = ["Base", "UUIDPrimaryMixin"]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user