From a95793c3df4b6aaa2dd18ff71b2ceda9896ba333 Mon Sep 17 00:00:00 2001 From: "Nick V. Anokhin" Date: Sat, 18 Jul 2026 16:28:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87=D0=B8=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5=D0=BA=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- net/xeaf/rack/utils/settings/__init__.py | 3 + .../rack/utils/settings/configs/__init__.py | 10 + .../rack/utils/settings/configs/database.py | 42 +++ net/xeaf/rack/utils/settings/configs/debug.py | 16 ++ net/xeaf/rack/utils/settings/configs/drf.py | 46 ++++ net/xeaf/rack/utils/settings/configs/email.py | 36 +++ net/xeaf/rack/utils/settings/configs/files.py | 32 +++ net/xeaf/rack/utils/settings/configs/i18n.py | 42 +++ net/xeaf/rack/utils/settings/configs/keydb.py | 45 +++ .../rack/utils/settings/configs/logging.py | 122 +++++++++ .../rack/utils/settings/configs/middleware.py | 19 ++ .../rack/utils/settings/configs/security.py | 58 ++++ .../rack/utils/settings/configs/templates.py | 24 ++ .../rack/utils/settings/log_debug_filter.py | 25 ++ net/xeaf/rack/utils/settings/rack_config.py | 259 ++++++++++++++++++ 15 files changed, 779 insertions(+) create mode 100644 net/xeaf/rack/utils/settings/configs/__init__.py create mode 100644 net/xeaf/rack/utils/settings/configs/database.py create mode 100644 net/xeaf/rack/utils/settings/configs/debug.py create mode 100644 net/xeaf/rack/utils/settings/configs/drf.py create mode 100644 net/xeaf/rack/utils/settings/configs/email.py create mode 100644 net/xeaf/rack/utils/settings/configs/files.py create mode 100644 net/xeaf/rack/utils/settings/configs/i18n.py create mode 100644 net/xeaf/rack/utils/settings/configs/keydb.py create mode 100644 net/xeaf/rack/utils/settings/configs/logging.py create mode 100644 net/xeaf/rack/utils/settings/configs/middleware.py create mode 100644 net/xeaf/rack/utils/settings/configs/security.py create mode 100644 net/xeaf/rack/utils/settings/configs/templates.py create mode 100644 net/xeaf/rack/utils/settings/log_debug_filter.py create mode 100644 net/xeaf/rack/utils/settings/rack_config.py diff --git a/net/xeaf/rack/utils/settings/__init__.py b/net/xeaf/rack/utils/settings/__init__.py index ae3f86c..f29378c 100644 --- a/net/xeaf/rack/utils/settings/__init__.py +++ b/net/xeaf/rack/utils/settings/__init__.py @@ -7,3 +7,6 @@ """ Пакет классов работы с параметрами конфигурации """ + +from .log_debug_filter import LogDebugFilter +from .rack_config import RackConfig diff --git a/net/xeaf/rack/utils/settings/configs/__init__.py b/net/xeaf/rack/utils/settings/configs/__init__.py new file mode 100644 index 0000000..7fbd93f --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/__init__.py @@ -0,0 +1,10 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Пакет скриптов параметров конфигурации +""" + diff --git a/net/xeaf/rack/utils/settings/configs/database.py b/net/xeaf/rack/utils/settings/configs/database.py new file mode 100644 index 0000000..4d4b5cb --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/database.py @@ -0,0 +1,42 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации базы данных +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Проверка режима запуска тестов +# +if not RackConfig.is_test_mode(): + + # + # Основная БД + # + DATABASES = { + "default": { + "ENGINE": "django.db.backends.postgresql", + "HOST": RackConfig.env_str("DATABASE_HOST"), + "PORT": RackConfig.env_str("DATABASE_PORT"), + "NAME": RackConfig.env_str("DATABASE_NAME"), + "USER": RackConfig.env_str("DATABASE_USERNAME"), + "PASSWORD": RackConfig.env_str("DATABASE_PASSWORD"), + } + } + +else: + + # + # Для запуска тестов + # + DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": RackConfig.env_str("TEST_DATABASE", ":memory:"), + } + } diff --git a/net/xeaf/rack/utils/settings/configs/debug.py b/net/xeaf/rack/utils/settings/configs/debug.py new file mode 100644 index 0000000..3475732 --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/debug.py @@ -0,0 +1,16 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации режима отладки +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Признак режима отладки +# +DEBUG = RackConfig.is_debug_mode() diff --git a/net/xeaf/rack/utils/settings/configs/drf.py b/net/xeaf/rack/utils/settings/configs/drf.py new file mode 100644 index 0000000..0bad510 --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/drf.py @@ -0,0 +1,46 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации Django REST Framework +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Настройка представления результатов вызова API +# +REST_FRAMEWORK_RENDERER = ( + 'djangorestframework_camel_case.render.CamelCaseJSONRenderer', +) + +# +# Только для режима отладки +# +if RackConfig.is_debug_mode(): + REST_FRAMEWORK_RENDERER += ('djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer',) + +# +# Настройки Django Rest Framework +# +REST_FRAMEWORK = { + 'DEFAULT_RENDERER_CLASSES': REST_FRAMEWORK_RENDERER, + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], + 'DEFAULT_PARSER_CLASSES': ( + 'djangorestframework_camel_case.parser.CamelCaseFormParser', + 'djangorestframework_camel_case.parser.CamelCaseMultiPartParser', + 'djangorestframework_camel_case.parser.CamelCaseJSONParser', + ), + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'net.xeaf.rack.utils.auth.ExpiringTokenAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 10, + # 'EXCEPTION_HANDLER': 'tantal.bdrive.api.utils.custom_exception_handler' +} diff --git a/net/xeaf/rack/utils/settings/configs/email.py b/net/xeaf/rack/utils/settings/configs/email.py new file mode 100644 index 0000000..f7de255 --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/email.py @@ -0,0 +1,36 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации отправки электронной почты +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Класс методов отправки электронной почты +# +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + +# +# Информация об отправителе +# +EMAIL_FROM_NAME = RackConfig.env_str('EMAIL_FROM_NAME') +EMAIL_FROM_ADDR = RackConfig.env_str('EMAIL_FROM_ADDR') +EMAIL_SUBJECT_PREFIX = RackConfig.env_str('EMAIL_SUBJECT_PREFIX', '') + +# +# Параметры SMTP сервера +# +EMAIL_HOST = RackConfig.env_str('EMAIL_HOST', 'localhost') +EMAIL_PORT = RackConfig.env_int('EMAIL_PORT', 25) +EMAIL_HOST_USER = RackConfig.env_str('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = RackConfig.env_str('EMAIL_HOST_PASSWORD') +EMAIL_USE_TLS = RackConfig.env_bool('EMAIL_USE_TLS', False) +EMAIL_USE_SSL = RackConfig.env_bool('EMAIL_USE_SSL', False) +EMAIL_TIMEOUT = RackConfig.env_int('EMAIL_TIMEOUT', 20) +EMAIL_SSL_KEYFILE = RackConfig.env_str('EMAIL_SSL_KEYFILE', "") +EMAIL_SSL_CERTFILE = RackConfig.env_str('EMAIL_SSL_CERTFILE', "") diff --git a/net/xeaf/rack/utils/settings/configs/files.py b/net/xeaf/rack/utils/settings/configs/files.py new file mode 100644 index 0000000..3f70a7c --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/files.py @@ -0,0 +1,32 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации файловой системы +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Путь к статическим файлам +# +STATIC_URL = RackConfig.env_str('STATIC_URL', 'static/') + +# +# Путь для сборки статических файлов +# +STATIC_ROOT = RackConfig.env_str_as_dir('STATIC_ROOT') + +# +# Путь к медиафайлам +# +MEDIA_ROOT = RackConfig.env_str_as_dir('MEDIA_ROOT') +THUMBNAILS_ROOT = RackConfig.env_str_as_dir('THUMBNAILS_ROOT') + +# +# Путь к временным файлам +# +FILE_UPLOAD_TEMP_DIR = RackConfig.env_str_as_dir('FILE_UPLOADS_TEMP', '/tmp') diff --git a/net/xeaf/rack/utils/settings/configs/i18n.py b/net/xeaf/rack/utils/settings/configs/i18n.py new file mode 100644 index 0000000..2e12c92 --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/i18n.py @@ -0,0 +1,42 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации интернационализации и локализации +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Идентификаторы поддерживаемых языков +# +UI_LANGUAGE_EN = 'en' +UI_LANGUAGE_RU = 'ru' + +# +# Доступные языки интерфейса пользователя +# +LANGUAGES = ( + (UI_LANGUAGE_EN, 'English'), + (UI_LANGUAGE_RU, 'Russian'), +) + +# +# Язык по умолчанию +# +LANGUAGE_CODE = RackConfig.env_str('LANGUAGE') + +# +# Временная зона +# +TIME_ZONE = RackConfig.env_str('TIME_ZONE') +USE_TZ = True + +# +# Включаем интернационализацию и локализацию +# +USE_I18N = True +USE_L10N = True diff --git a/net/xeaf/rack/utils/settings/configs/keydb.py b/net/xeaf/rack/utils/settings/configs/keydb.py new file mode 100644 index 0000000..d41c30c --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/keydb.py @@ -0,0 +1,45 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации подключения к KeyDb (Redis) +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Проверяем необходимость настройки +# +USE_KEYDB = RackConfig.env_bool('USE_KEYDB', True) +if USE_KEYDB: + + # + # Читаем параметры подключения к KeyDb (Redis) + # + KEYDB_HOST = RackConfig.env_str("KEYDB_HOST", "127.0.0.1") + KEYDB_PORT = RackConfig.env_int("KEYDB_PORT", 6379) + KEYDB_DBINDEX = RackConfig.env_int("KEYDB_DBINDEX", 1) + KEYDB_PASSWORD = RackConfig.env_str('KEYDB_PASSWORD', "") + KEYDB_POOL_SIZE = RackConfig.env_int('KEYDB_POOL_SIZE', 5) + KEYDB_LOCATION = f"redis://:{KEYDB_PASSWORD}@{KEYDB_HOST}:{KEYDB_PORT}/{KEYDB_DBINDEX}" + + # + # Параметры кеширования данных + # + CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.redis.RedisCache", + "LOCATION": KEYDB_LOCATION, + "OPTIONS": { + "CLIENT_CLASS": "django.core.cache.backends.redis.RedisClient", + "CONNECTION_POOL_KWARGS": { + "max_connections": KEYDB_POOL_SIZE, + "retry_on_timeout": True, + } + } + } + } + diff --git a/net/xeaf/rack/utils/settings/configs/logging.py b/net/xeaf/rack/utils/settings/configs/logging.py new file mode 100644 index 0000000..212daba --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/logging.py @@ -0,0 +1,122 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации системы журналирования +""" + +from net.xeaf.rack.utils.settings import LogDebugFilter +from net.xeaf.rack.utils.settings import RackConfig + +# +# Имя журнала +# +LOGGER_NAME = RackConfig.env_str("LOGGER_NAME", "rack") + +# +# Уровень журналирования +# +LOG_LEVEL = RackConfig.env_str("LOG_LEVEL") +if RackConfig.is_debug_mode(): + LOG_LEVEL = "DEBUG" +else: + if LOG_LEVEL == "DEBUG": + LOG_LEVEL = "INFO" + +# +# Файлы журналов +# +LOG_FILE = RackConfig.env_str_as_file("LOG_FILE") +DEBUG_LOG_FILE = RackConfig.env_str_as_file("DEBUG_LOG_FILE") + +# +# Настройка журнала +# +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + + "filters": { + "strict_debug_only": { + "()": LogDebugFilter, + }, + }, + + "formatters": { + "custom_format": { + "format": "{asctime} [{levelname}] {message}", + "datefmt": "%Y-%m-%d %H:%M:%S", + "style": "{", + }, + }, + + "handlers": { + + # + # Основной лог + # + "main_file": { + "level": "INFO" if LOG_LEVEL == "DEBUG" else LOG_LEVEL, + "class": "logging.handlers.RotatingFileHandler", + "filename": LOG_FILE, + "maxBytes": 1024 * 1024 * 10, + "backupCount": 5, + "formatter": "custom_format", + "encoding": "utf-8", + }, + + # + # Отладка + # + "debug_file": { + "level": "DEBUG", + "class": "logging.handlers.RotatingFileHandler", + "filename": DEBUG_LOG_FILE, + "maxBytes": 1024 * 1024 * 10, + "backupCount": 5, + "formatter": "custom_format", + "filters": [] if RackConfig.is_debug_mode() else ["strict_debug_only"], + "encoding": "utf-8", + }, + }, + + # + # Журналы + # + "loggers": { + + # Журнал системы + LOGGER_NAME: { + "handlers": ["main_file", "debug_file"], + "level": "DEBUG", + "propagate": False, + }, + + # Стандартный журнал + "django": { + # "handlers": ["main_file", "debug_file"], + # Отключаем полностью + "'handlers": [], + "level": "ERROR", + "propagate": False, + }, + + # + # Отрезаем вообще всё, кроме реальных падений ядра (500 ошибок вне DRF) + # + "django.request": { + "level": "ERROR", + "propagate": True, + }, + + # + # Глушим системный спам сторонних библиотек + # + "urllib3": {"level": "WARNING"}, + "botocore": {"level": "WARNING"}, + "boto3": {"level": "WARNING"}, + }, +} diff --git a/net/xeaf/rack/utils/settings/configs/middleware.py b/net/xeaf/rack/utils/settings/configs/middleware.py new file mode 100644 index 0000000..d4f5e46 --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/middleware.py @@ -0,0 +1,19 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации среднего слоя приложения +""" + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] diff --git a/net/xeaf/rack/utils/settings/configs/security.py b/net/xeaf/rack/utils/settings/configs/security.py new file mode 100644 index 0000000..9f29fdf --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/security.py @@ -0,0 +1,58 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации безопасности +""" + +from net.xeaf.rack.utils.settings import RackConfig + +# +# Допустимые хосты, параметры CORS и CSRF +# +ALLOWED_HOSTS = RackConfig.env_str_as_list('ALLOWED_HOSTS') +CORS_ALLOWED_ORIGINS = RackConfig.env_str_as_list('CORS_ALLOWED_ORIGINS') +CSRF_TRUSTED_ORIGINS = RackConfig.env_str_as_list('CSRF_TRUSTED_ORIGINS') + +# +# Допустимые заголовки CORS +# +CORS_ALLOW_HEADERS = ( + 'content-disposition', + 'accept-encoding', + 'content-type', + 'accept', + 'origin', + 'authorization', + 'cache-control', + 'x-requested-with', +) + +# +# Ключ +# +SECRET_KEY = RackConfig.env_str('SECRET_KEY') + +# +# Валидаторы паролей +# +AUTH_PASSWORD_VALIDATORS = [ + {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', "OPTIONS": {"min_length": 9, }, }, + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, + {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, +] + +# +# Тайм-аут сессии +# +SESSION_TIMEOUT = RackConfig.env_int('SESSION_TIMEOUT', 3600) + +# +# Модели данных аутентификации +# +AUTH_USER_MODEL = 'net_xeaf_rack.Account' +AUTH_SESSION_MODEL = 'net_xeaf_rack.Session' diff --git a/net/xeaf/rack/utils/settings/configs/templates.py b/net/xeaf/rack/utils/settings/configs/templates.py new file mode 100644 index 0000000..df9d50c --- /dev/null +++ b/net/xeaf/rack/utils/settings/configs/templates.py @@ -0,0 +1,24 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Параметры конфигурации шаблонизатора +""" + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] diff --git a/net/xeaf/rack/utils/settings/log_debug_filter.py b/net/xeaf/rack/utils/settings/log_debug_filter.py new file mode 100644 index 0000000..7c0f3dd --- /dev/null +++ b/net/xeaf/rack/utils/settings/log_debug_filter.py @@ -0,0 +1,25 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса LogDebugFilter +""" + + +class LogDebugFilter: + """ + Фильтр для разделения журнала DEBUG + """ + + # noinspection PyMethodMayBeStatic + def filter(self, record)->bool: + """ + Фильтрация + + :return: True, если уровень журнала DEBUG + """ + + return record.levelname == 'DEBUG' diff --git a/net/xeaf/rack/utils/settings/rack_config.py b/net/xeaf/rack/utils/settings/rack_config.py new file mode 100644 index 0000000..86df9c6 --- /dev/null +++ b/net/xeaf/rack/utils/settings/rack_config.py @@ -0,0 +1,259 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса RackConfig +""" + +import os +import sys +from pathlib import Path + +import environ +from django.core.exceptions import ImproperlyConfigured +from environ import Env +from environ import NoValue + + +class RackConfig: + """ + Содержит базовые параметры для настройки приложения + """ + + __base_dir: str + """ Путь к корневой директории приложения """ + + __debug_mode: bool + """ Признак режима отладки приложения """ + + __is_initialized: bool + """ Признак инициализации конфигурации """ + + __env: Env + """ Хранилище переменных окружения """ + + __env_prefix: str + """ Префикс переменных окружения """ + + __config_files: dict[str, str | None] = {} + """ Словарь файлов параметров конфигурации """ + + @classmethod + def initialize(cls, base_dir: str, env_prefix: str = ""): + """ + Инициализирует конфигурацию приложения + + :param base_dir: Путь к корневой директории + :param env_prefix: Префикс переменных окружения + """ + + cls.__base_dir = base_dir + cls.__env = environ.Env() + cls.__env_prefix = env_prefix + environ.Env.read_env(os.path.join(cls.__base_dir, '.env')) + cls._init_configuration_files() + cls.__is_initialized = True + + # Сразу загружаем признак режима отладки + cls.__debug_mode = cls.env_bool('DEBUG', False) + + @classmethod + def get_base_dir(cls) -> str: + """ + Возвращает путь к корневой директории приложения + + :return: Путь к корневой директории приложения + """ + + cls._check_initialization() + return cls.__base_dir + + @classmethod + def get_debug_mode(cls) -> bool: + """ + Возвращает признак режима отладки приложения + + :return: Признак режима отладки + """ + + cls._check_initialization() + return cls.__debug_mode + + @classmethod + def is_test_mode(cls) -> bool: + """ + Возвращает признак режима тестирования приложения + + :return: Признак режима тестирования приложения + """ + + cls._check_initialization() + return 'test' in sys.argv + + @classmethod + def is_debug_mode(cls) -> bool: + """ + Возвращает признак режима отладки приложения + + :return: Признак режима отладки + """ + + cls._check_initialization() + return cls.__debug_mode + + @classmethod + def env(cls) -> Env: + """ + Возвращает объект для работы с переменными окружения + + :return: Объект для работы с переменными окружения + """ + + cls._check_initialization() + return cls.__env + + @classmethod + def env_str(cls, name: str, default_value: str | NoValue = Env.NOTSET) -> str: + """ + Возвращает строковое значение переменной окружения + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + return cls.env().str(cls.env_name(name), default_value) + + @classmethod + def env_int(cls, name: str, default_value: int | NoValue = Env.NOTSET) -> int: + """ + Возвращает целочисленное значение переменной окружения + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + return cls.env().int(cls.env_name(name), default_value) + + @classmethod + def env_bool(cls, name: str, default_value: bool | NoValue = Env.NOTSET) -> bool: + """ + Возвращает логическое значение переменной окружения + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + return cls.env().bool(cls.env_name(name), default_value) + + @classmethod + def env_str_as_dir(cls, name: str, default_value: str | NoValue = Env.NOTSET) -> str: + """ + Возвращает значение переменной окружения в виде проверенного имени директории + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + dir_path = cls.env_str(name, default_value) + os.makedirs(dir_path, exist_ok=True) + + return dir_path + + @classmethod + def env_str_as_file(cls, name: str, default_value: str | NoValue = Env.NOTSET) -> str: + """ + Возвращает значение переменной окружения в виде проверенного имени фйала + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + file_path = cls.env_str(name, default_value) + dir_path = os.path.dirname(file_path) + os.makedirs(dir_path, exist_ok=True) + + return file_path + + @classmethod + def env_str_as_list(cls, name: str, default_value: str | NoValue = Env.NOTSET) -> list[str]: + """ + Возвращает значение переменной окружения в виде списка строк + + :param name: Название переменной окружения + :param default_value: Значение по умолчанию + + :return: Значение переменной окружения + """ + + values = cls.env_str(name, default_value) + if not values: + return [] + + return [item.strip() for item in values.split(",") if item.strip()] + + @classmethod + def env_name(cls, name: str) -> str: + """ + Возвращает полное имя переменной окружения + + :param name: Название переменной окружения + + :return: Имя переменной окружения + """ + + return f"{cls.__env_prefix}{name}" + + @classmethod + def get_config_files(cls) -> list[str]: + """ + Возвращает список файлов конфигурации + + :return: Список файлов конфигурации + """ + + return [file for file in cls.__config_files.values() if file is not None] + + @classmethod + def set_config_file(cls, name: str, full_path: str | None) -> None: + """ + Устанавливает полный путь к файлу конфигурации + + :param name: Название файла конфигурации + :param full_path: Полный путь к файлу конфигурации + """ + + cls.__config_files[name] = full_path + + @classmethod + def _check_initialization(cls) -> None: + """ + Проверяет завершение инициализации + """ + + if not cls.__is_initialized: + raise ImproperlyConfigured("DRF Rack configuration is not initialized") + + @classmethod + def _init_configuration_files(cls) -> None: + """ + Инициализирует словарь файлов параметров конфигурации + """ + + root = f"{os.path.dirname(__file__)}/configs" + for file in os.listdir(root): + if file.endswith(".py") and file != "__init__.py": + name = Path(file).stem + cls.__config_files[name] = f"{root}/{file}"