152 lines
5.9 KiB
Python
152 lines
5.9 KiB
Python
import os
|
||
import sys
|
||
from pathlib import Path
|
||
from typing import Optional, Dict, Any
|
||
from dotenv import load_dotenv, find_dotenv
|
||
import logging
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
class EnvironmentLoader:
|
||
"""Класс для загрузки переменных окружения из .env файлов"""
|
||
|
||
# Порядок загрузки файлов .env (от более специфичного к общему)
|
||
ENV_FILES_ORDER = [
|
||
'.env.local', # Локальные переопределения (не в git)
|
||
f'.env.{os.getenv("ENV", "development")}', # Окружение: .env.test, .env.production
|
||
'.env', # Основной файл
|
||
]
|
||
|
||
@classmethod
|
||
def load_environment(cls, env_file: Optional[str] = None):
|
||
"""
|
||
Загрузка переменных окружения.
|
||
|
||
Args:
|
||
env_file: Конкретный файл для загрузки (если None, используется порядок из ENV_FILES_ORDER)
|
||
"""
|
||
if env_file:
|
||
# Загрузка конкретного файла
|
||
env_path = Path(env_file)
|
||
if env_path.exists():
|
||
logger.info(f"Loading environment from specified file: {env_path}")
|
||
load_dotenv(dotenv_path=env_path, override=True)
|
||
else:
|
||
logger.warning(f"Specified env file not found: {env_path}")
|
||
return
|
||
|
||
# Автоматическая загрузка в определенном порядке
|
||
env_loaded = False
|
||
|
||
for env_filename in cls.ENV_FILES_ORDER:
|
||
env_path = find_dotenv(env_filename, usecwd=True)
|
||
if env_path:
|
||
logger.info(f"Loading environment from: {env_path}")
|
||
load_dotenv(dotenv_path=env_path, override=True)
|
||
env_loaded = True
|
||
|
||
if not env_loaded:
|
||
logger.warning("No .env files found, using system environment variables")
|
||
|
||
@classmethod
|
||
def get_env_variable(cls, key: str, default: Any = None, required: bool = False) -> Any:
|
||
"""
|
||
Получение переменной окружения с проверкой.
|
||
|
||
Args:
|
||
key: Ключ переменной окружения
|
||
default: Значение по умолчанию, если переменная не найдена
|
||
required: Обязательна ли переменная (вызывает исключение, если не найдена)
|
||
|
||
Returns:
|
||
Значение переменной окружения
|
||
|
||
Raises:
|
||
ValueError: Если переменная required=True и не найдена
|
||
"""
|
||
value = os.getenv(key)
|
||
|
||
if value is None:
|
||
if required:
|
||
raise ValueError(f"Required environment variable '{key}' is not set")
|
||
return default
|
||
|
||
# Автоматическое преобразование типов
|
||
if value.lower() in ('true', 'false'):
|
||
return value.lower() == 'true'
|
||
elif value.isdigit():
|
||
return int(value)
|
||
elif cls._is_float(value):
|
||
return float(value)
|
||
elif value.startswith('[') and value.endswith(']'):
|
||
# Список значений, разделенных запятыми
|
||
return [item.strip() for item in value[1:-1].split(',') if item.strip()]
|
||
|
||
return value
|
||
|
||
@staticmethod
|
||
def _is_float(value: str) -> bool:
|
||
"""Проверка, можно ли преобразовать строку в float"""
|
||
try:
|
||
float(value)
|
||
return True
|
||
except ValueError:
|
||
return False
|
||
|
||
@classmethod
|
||
def validate_environment(cls):
|
||
"""Валидация обязательных переменных окружения"""
|
||
required_vars = [
|
||
# 'API_BASE_URL',
|
||
# 'UI_BASE_URL',
|
||
]
|
||
|
||
missing_vars = []
|
||
for var in required_vars:
|
||
if not os.getenv(var):
|
||
missing_vars.append(var)
|
||
|
||
if missing_vars:
|
||
raise EnvironmentError(
|
||
f"Missing required environment variables: {', '.join(missing_vars)}\n"
|
||
f"Please set them in .env file or system environment."
|
||
)
|
||
|
||
@classmethod
|
||
def print_environment_info(cls):
|
||
"""Вывод информации о текущем окружении (для отладки)"""
|
||
env_info = {
|
||
'ENV': os.getenv('ENV', 'development'),
|
||
'API_BASE_URL': os.getenv('API_BASE_URL'),
|
||
'UI_BASE_URL': os.getenv('UI_BASE_URL'),
|
||
'DEBUG': os.getenv('DEBUG', 'False'),
|
||
'LOG_LEVEL': os.getenv('LOG_LEVEL', 'INFO'),
|
||
}
|
||
|
||
logger.info("Current environment configuration:")
|
||
for key, value in env_info.items():
|
||
logger.info(f" {key}: {value}")
|
||
|
||
@classmethod
|
||
def get_all_env_variables(cls, prefix: str = '') -> Dict[str, Any]:
|
||
"""
|
||
Получение всех переменных окружения с опциональным префиксом.
|
||
|
||
Args:
|
||
prefix: Фильтр по префиксу (например, 'API_' для всех API настроек)
|
||
|
||
Returns:
|
||
Словарь переменных окружения
|
||
"""
|
||
env_vars = {}
|
||
|
||
for key, _ in os.environ.items():
|
||
if len(prefix) == 0 and not key.startswith(prefix):
|
||
continue
|
||
|
||
env_vars[key] = cls.get_env_variable(key)
|
||
|
||
return env_vars
|
||
|
||
# Инициализация при импорте модуля
|
||
EnvironmentLoader.load_environment()
|