diff --git a/api_v1/routers.py b/api_v1/routers.py index c017092..8a48d13 100644 --- a/api_v1/routers.py +++ b/api_v1/routers.py @@ -7,6 +7,33 @@ def register_routers(app: FastAPI) -> None: """ Функция по регистрации роутеров + + ## Args: + app (FastAPI): ASGI приложение. + + ## Returns: + None + + ## Example + ```python + from fastapi import FastAPI + + from config import settings + from api_v1.api_xml.views import router as xml + from api_v1.users.views import router as users + + + def register_routers(app: FastAPI) -> None: + app.include_router( + router=xml, + prefix=settings.API_PREFIX, + ) + # Новый роутер + app.include_router( + router=users, + prefix=settings.API_PREFIX, + ) + ``` """ app.include_router( router=users, diff --git a/app_includes/logs_errors.py b/app_includes/logs_errors.py index c52b2fd..816762a 100644 --- a/app_includes/logs_errors.py +++ b/app_includes/logs_errors.py @@ -12,7 +12,54 @@ def register_errors(app: FastAPI) -> None: """ Крючек для логирования различных исключений + + ## Args: + app (FastAPI): ASGI приложение. + + ## Returns: + None + + ## Example + ```python + from fastapi import FastAPI, Request + from fastapi.responses import JSONResponse + from fastapi.exceptions import HTTPException + from http import HTTPStatus + + from config.setup_logs.logging import logger + from api_v1.api_xml.exeptions import APIFileNotFoundError + + + def register_errors(app: FastAPI) -> None: + @app.exception_handler(HTTPException) + async def http_error_handler( + request: Request, + exc: HTTPException, + ): + logger.opt(exception=True).warning(exc) + response = dict( + status=False, + error_code=exc.status_code, + message=exc.detail, + ) + return JSONResponse(response) + + # Добавление нового крюка + @app.exception_handler(APIFileNotFoundError) + async def file_not_found_error_handler( + request: Request, + exc: APIFileNotFoundError, + ): + logger.opt(exception=True).warning(exc) + response = dict( + status=False, + error_code=exc.status_code, + message=exc.detail, + ) + return JSONResponse(response) + ``` """ + @app.exception_handler(ValidationError) async def validation_error_handler( request: Request, diff --git a/app_includes/middlewares.py b/app_includes/middlewares.py index 785d442..2b4e59d 100644 --- a/app_includes/middlewares.py +++ b/app_includes/middlewares.py @@ -7,6 +7,39 @@ def register_middlewares(app: FastAPI) -> None: """ Регистрация middleware + + ## Args: + app (FastAPI): ASGI приложение. + + ## Returns: + None + + ## Example + ```python + from fastapi.middleware.cors import CORSMiddleware + from fastapi import FastAPI + + from config import settings + from middlewares import SomeMiddleware + + + def register_middlewares(app: FastAPI) -> None: + app.add_middleware( + CORSMiddleware, + allow_origins=[y + settings.CURRENT_ORIGIN, + ], + allow_credentials=True, + allow_methods=['*'], + allow_headers=['*'], + ) + + # Новая регистрация + app.add_middleware( + SomeMiddleware, + *args, + ) + ``` """ app.add_middleware( CORSMiddleware, diff --git a/config/database/db_helper.py b/config/database/db_helper.py index a158bb5..c503701 100644 --- a/config/database/db_helper.py +++ b/config/database/db_helper.py @@ -16,12 +16,49 @@ class DataBaseHelper: """ - Вспомогательный класс для работы с Базой Данных + Вспомогательный класс для работы с Базой Данных. + + Помогает инициализировать соединение с Базой Данных, а так же + работу с сессиями. + + ## Инициализация: + :string:`db_url` - Адресс базы данных. + :string:`poolclass` - Пул типа :class:`sqlalchemy.pool.Pool` + + ## Методы: + :function:`DataBaseHelper.session_geter` - Получение генератора текущей сессии. + :function:`DataBaseHelper.get_scoped_session` - Получение текущей сессии. + :function:`DataBaseHelper.dispose` - Закрытые соединения. + + ## Примеры: + ```python + from fastapi import FastAPI + from contextlib import asynccontextmanager + from config import db_connection, BaseModel + + + @asynccontextmanager + async def lifespan(app: FastAPI): + # Инициализация соединения для создания таблиц. + async with db_connection.engine.begin() as conn: + await conn.run_sync(BaseModel.metadata.create_all) + yield + await db_connection.dispose() + + app = FastApi(lifespan=lifespan) + ``` """ def __init__(self, db_url: str = DATA_BASE_URL, poolclass: Pool | None = None, ) -> None: + """ + Args: + db_url (str, optional): Адресс Базы Данных. Defaults to DATA_BASE_URL. + + poolclass (Pool | None, optional): Пул типа :class:`sqlalchemy.pool.Pool`. + Defaults to None. + """ self._db_url = db_url setup = dict( url=self._db_url, @@ -42,9 +79,15 @@ def __init__(self, ) async def dispose(self) -> None: + """ + Закрытие соединения + """ await self.engine.dispose() def get_scoped_session(self) -> AsyncSession: + """ + Получение сессии + """ session = async_scoped_session( session_factory=self.session, scopefunc=current_task, @@ -52,6 +95,17 @@ def get_scoped_session(self) -> AsyncSession: return session async def session_geter(self) -> AsyncGenerator[AsyncSession, Any]: + """ + Получение генератора сессии + + Returns: + AsyncGenerator[AsyncSession, Any]: Возвращает + генератор с сессиями + + Yields: + Iterator[AsyncGenerator[AsyncSession, Any]]: Генератор подает + сессии + """ session = self.get_scoped_session() yield session await session.remove() diff --git a/config/models/base.py b/config/models/base.py index 179313c..3a61970 100644 --- a/config/models/base.py +++ b/config/models/base.py @@ -6,7 +6,48 @@ class Base(DeclarativeBase): - """Базовая модель + """ + Базовая модель для инициализации других моделей. + + Данная базовая модель является абстактной, и определяет + базовое поведение других таблиц. + + ## Определение поведения таблиц: + + - Имя любой таблицы приводится к :method:`lower()` и + добаляется `s` к окончанию. + + - Для каждой таблицы создается автогенерируемое поле `id` или `uid`, + которое автоинкремирует счетчик интидификатора сущностей. + + ## Примеры: + ```python + from sqlalchemy.orm import Mapped, mapped_column + from sqlalchemy import String + from sqlalchemy.types import LargeBinary + from datetime import date + + from config.models import Base + + + class User(Base): + name: Mapped[str] = mapped_column(String(length=100)) + surname: Mapped[str] = mapped_column(String(length=200)) + password: Mapped[str] = mapped_column(LargeBinary) + active: Mapped[bool] = mapped_column(default=True) + is_admin: Mapped[bool] = mapped_column(default=False) + create_date: Mapped[datetime] = mapped_column( + insert_default=func.now(), + server_default=func.now(), + ) + login_date: Mapped[datetime | None] = mapped_column( + default=None, + server_default=None, + nullable=True, + ) + ``` + По итогу к классу :class:`User` будет добавленно поле `id` или `uid`, + а так же в Базу данных таблица будет с названием `users`. """ __abstract__ = True diff --git a/config/setup_logs/logging.py b/config/setup_logs/logging.py index ef8eb7d..777f585 100644 --- a/config/setup_logs/logging.py +++ b/config/setup_logs/logging.py @@ -1,3 +1,7 @@ +r""" +Основной файл настройки логирования проектов +""" + import sys from loguru import logger