#!/usr/bin/env python3 import sys from pathlib import Path def parse_env_file(file_path: Path) -> set[str]: if not file_path.exists(): return set() variables = set() with open(file_path) as f: for line in f: line = line.strip() if line and not line.startswith('#') and '=' in line: variables.add(line.split('=', 1)[0].strip()) return variables def get_pydantic_settings_fields() -> tuple[set[str], set[str]]: sys.path.insert(0, str(Path(__file__).parent.parent.parent)) from pydantic import BaseModel from src.config import Settings all_fields, required_fields = set(), set() def extract_fields(model: type[BaseModel], prefix: str = '') -> None: for field_name, field_info in model.model_fields.items(): env_var_name = f'{prefix}{field_name}'.upper() field_type = field_info.annotation if hasattr(field_type, '__origin__'): field_type = field_type.__args__[0] if field_type.__args__ else field_type try: if isinstance(field_type, type) and issubclass(field_type, BaseModel): extract_fields(field_type, prefix=f'{env_var_name}__') else: all_fields.add(env_var_name) if field_info.is_required(): required_fields.add(env_var_name) except TypeError: all_fields.add(env_var_name) if field_info.is_required(): required_fields.add(env_var_name) extract_fields(Settings) return all_fields, required_fields def main() -> int: project_root = Path(__file__).parent.parent.parent env_file = project_root / '.env' env_example_file = project_root / '.env.example' if not env_example_file.exists(): print('❌ Файл .env.example не найден') return 1 env_vars = parse_env_file(env_file) env_example_vars = parse_env_file(env_example_file) all_pydantic_fields, required_pydantic_fields = get_pydantic_settings_fields() print('🔍 Проверка соответствия .env и .env.example\n') has_errors = False missing_in_env = env_example_vars - env_vars if missing_in_env: has_errors = True print('❌ Переменные из .env.example отсутствуют в .env:') for var in sorted(missing_in_env): print(f' - {var}') print() extra_in_env = env_vars - env_example_vars if extra_in_env: has_errors = True print('⚠️ Переменные в .env, которых нет в .env.example:') for var in sorted(extra_in_env): print(f' - {var}') print() missing_in_pydantic = env_example_vars - all_pydantic_fields if missing_in_pydantic: has_errors = True print('❌ Переменные из .env.example не определены в Pydantic Settings (src/config.py):') for var in sorted(missing_in_pydantic): print(f' - {var}') print() missing_in_example = required_pydantic_fields - env_example_vars if missing_in_example: has_errors = True print('❌ Обязательные поля Pydantic Settings отсутствуют в .env.example:') for var in sorted(missing_in_example): print(f' - {var}') print() if not has_errors: print('✅ Все проверки пройдены успешно!') print(f' - Переменных в .env.example: {len(env_example_vars)}') print(f' - Переменных в .env: {len(env_vars)}') print( f' - Полей в Pydantic Settings (всего/обязательных): {len(all_pydantic_fields)}/{len(required_pydantic_fields)}' ) return 0 print('❌ Обнаружены несоответствия') return 1 if __name__ == '__main__': sys.exit(main())