From 5dd8e98a3787b2b282910d46a81216081d3011c8 Mon Sep 17 00:00:00 2001 From: ksieuk Date: Fri, 22 Sep 2023 20:31:46 +0300 Subject: [PATCH] [#10] add split settings --- src/fastapi_app/bin/__main__.py | 2 +- src/fastapi_app/lib/app/app.py | 7 +- src/fastapi_app/lib/app/settings.py | 43 ++++------ .../lib/app/split_settings/__init__.py | 11 +++ .../lib/app/split_settings/logger.py | 79 +++++++++++++++++++ .../lib/app/split_settings/postgres.py | 20 +++++ .../lib/app/split_settings/project.py | 31 ++++++++ .../lib/app/split_settings/utils.py | 4 + 8 files changed, 165 insertions(+), 32 deletions(-) create mode 100644 src/fastapi_app/lib/app/split_settings/__init__.py create mode 100644 src/fastapi_app/lib/app/split_settings/logger.py create mode 100644 src/fastapi_app/lib/app/split_settings/postgres.py create mode 100644 src/fastapi_app/lib/app/split_settings/project.py create mode 100644 src/fastapi_app/lib/app/split_settings/utils.py diff --git a/src/fastapi_app/bin/__main__.py b/src/fastapi_app/bin/__main__.py index 5343917..4463373 100644 --- a/src/fastapi_app/bin/__main__.py +++ b/src/fastapi_app/bin/__main__.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) app_instance = app_module.Application() app = app_instance.create_app() -settings = app_settings.get_settings() +settings = app_settings.settings if __name__ == "__main__": diff --git a/src/fastapi_app/lib/app/app.py b/src/fastapi_app/lib/app/app.py index af2c2b6..6e24e89 100644 --- a/src/fastapi_app/lib/app/app.py +++ b/src/fastapi_app/lib/app/app.py @@ -1,18 +1,15 @@ import logging -import logging.config as logging_config import fastapi -from .logger import LOGGING -from .settings import get_settings +import lib.app.settings as app_settings -logging_config.dictConfig(LOGGING) logger = logging.getLogger(__name__) class Application: def __init__(self) -> None: - self.settings = get_settings() + self.settings = app_settings self.logger = logging.getLogger(__name__) self.producer = None diff --git a/src/fastapi_app/lib/app/settings.py b/src/fastapi_app/lib/app/settings.py index 46d1cbd..22149c4 100644 --- a/src/fastapi_app/lib/app/settings.py +++ b/src/fastapi_app/lib/app/settings.py @@ -1,35 +1,26 @@ -import functools +import logging.config as logging_config import pydantic import pydantic_settings - -class DbSettings(pydantic_settings.BaseSettings): - host: str = pydantic.Field("127.0.0.1", validation_alias="db_host") - port: int = pydantic.Field(5432, validation_alias="db_port") - user: str = pydantic.Field(..., validation_alias="db_user") - password: str = pydantic.Field(..., validation_alias="db_password") - name: str = pydantic.Field("db_name", validation_alias="db_name") - - -class ApiSettings(pydantic_settings.BaseSettings): - host: str = pydantic.Field("0.0.0.0", validation_alias="server_host") - port: int = pydantic.Field(8000, validation_alias="server_port") +import lib.app.split_settings as app_split_settings class Settings(pydantic_settings.BaseSettings): - debug: str = pydantic.Field("false", validation_alias="debug") - db: DbSettings = pydantic.Field(default_factory=lambda: DbSettings()) - api: ApiSettings = pydantic.Field(default_factory=lambda: ApiSettings()) - - jwt_secret_key: str = pydantic.Field(..., validation_alias="jwt_secret_key") - - @pydantic.field_validator("debug") - @classmethod - def validate_debug(cls, v: str) -> bool: - return v.lower() == "true" + api: app_split_settings.ApiSettings = pydantic.Field(default_factory=lambda: app_split_settings.ApiSettings()) + db: app_split_settings.PostgresSettings = pydantic.Field( + default_factory=lambda: app_split_settings.PostgresSettings() + ) + logger: app_split_settings.LoggingSettings = pydantic.Field( + default_factory=lambda: app_split_settings.LoggingSettings() + ) + project: app_split_settings.ProjectSettings = pydantic.Field( + default_factory=lambda: app_split_settings.ProjectSettings() + ) -@functools.lru_cache -def get_settings() -> Settings: - return Settings() +settings = Settings() # todo Вынести в инициализацию + +logging_config.dictConfig( # todo Вынести в инициализацию + app_split_settings.get_logging_config(**settings.logger.model_dump()) +) diff --git a/src/fastapi_app/lib/app/split_settings/__init__.py b/src/fastapi_app/lib/app/split_settings/__init__.py new file mode 100644 index 0000000..91f518b --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/__init__.py @@ -0,0 +1,11 @@ +from .logger import * +from .postgres import * +from .project import * + +__all__ = [ + "LoggingSettings", + "get_logging_config", + "PostgresSettings", + "ApiSettings", + "ProjectSettings", +] diff --git a/src/fastapi_app/lib/app/split_settings/logger.py b/src/fastapi_app/lib/app/split_settings/logger.py new file mode 100644 index 0000000..360487a --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/logger.py @@ -0,0 +1,79 @@ +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class LoggingSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, env_file_encoding="utf-8", extra="ignore" + ) + + log_format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + log_default_handlers: list[str] = [ + "console", + ] + + log_level_handlers: str = "INFO" + log_level_loggers: str = "INFO" + log_level_root: str = "INFO" + + +def get_logging_config( + log_format: str, + log_default_handlers: list[str], + log_level_handlers: str, + log_level_loggers: str, + log_level_root: str, +): + return { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": {"format": log_format}, + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "fmt": "%(levelprefix)s %(message)s", + "use_colors": None, + }, + "access": { + "()": "uvicorn.logging.AccessFormatter", + "fmt": "%(levelprefix)s %(client_addr)s - '%(request_line)s' %(status_code)s", + }, + }, + "handlers": { + "console": { + "level": log_level_handlers, + "class": "logging.StreamHandler", + "formatter": "verbose", + }, + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + "access": { + "formatter": "access", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "loggers": { + "": { + "handlers": log_default_handlers, + "level": log_level_loggers, + }, + "uvicorn.error": { + "level": log_level_loggers, + }, + "uvicorn.access": { + "handlers": ["access"], + "level": log_level_loggers, + "propagate": False, + }, + }, + "root": { + "level": log_level_root, + "formatter": "verbose", + "handlers": log_default_handlers, + }, + } diff --git a/src/fastapi_app/lib/app/split_settings/postgres.py b/src/fastapi_app/lib/app/split_settings/postgres.py new file mode 100644 index 0000000..390992b --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/postgres.py @@ -0,0 +1,20 @@ +import pydantic +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class PostgresSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="DB_", + env_file_encoding="utf-8", + extra="ignore", + ) + + host: str = "localhost" + port: int = 5432 + user: str = "app" + password: pydantic.SecretStr = pydantic.Field( + default=..., validation_alias=pydantic.AliasChoices("password", "db_password") + ) diff --git a/src/fastapi_app/lib/app/split_settings/project.py b/src/fastapi_app/lib/app/split_settings/project.py new file mode 100644 index 0000000..7a9a55a --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/project.py @@ -0,0 +1,31 @@ +import pydantic +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class ApiSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="SERVER_", + env_file_encoding="utf-8", + extra="ignore", + ) + + host: str = "0.0.0.0" + port: int = 8000 + + +class ProjectSettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_file_encoding="utf-8", + extra="ignore", + ) + + debug: str = "false" + jwt_secret_key: pydantic.SecretStr = pydantic.Field(default=..., validation_alias="jwt_secret_key") + + @pydantic.field_validator("debug") + def validate_debug(cls, v: str) -> bool: + return v.lower() == "true" diff --git a/src/fastapi_app/lib/app/split_settings/utils.py b/src/fastapi_app/lib/app/split_settings/utils.py new file mode 100644 index 0000000..459631e --- /dev/null +++ b/src/fastapi_app/lib/app/split_settings/utils.py @@ -0,0 +1,4 @@ +import pathlib + +BASE_PATH = pathlib.Path(__file__).parent.parent.parent.parent.resolve() +ENV_PATH = BASE_PATH / ".env"