style: isort + black

This commit is contained in:
2026-02-02 00:13:33 +03:00
parent 5f66c86d99
commit 561c9074dd
86 changed files with 8459 additions and 5793 deletions

View File

@@ -4,6 +4,7 @@
Сканирует папку scripts/ и применяет все новые миграции, которые еще не были применены.
"""
import argparse
import asyncio
import importlib.util
@@ -15,9 +16,9 @@ from typing import List, Tuple
# Исключаем служебные скрипты из миграций
EXCLUDED_SCRIPTS = {
'apply_migrations.py',
'test_s3_connection.py',
'voice_cleanup.py',
"apply_migrations.py",
"test_s3_connection.py",
"voice_cleanup.py",
}
DEFAULT_DB_PATH = "database/tg-bot-database.db"
@@ -26,7 +27,7 @@ DEFAULT_DB_PATH = "database/tg-bot-database.db"
def get_migration_scripts(scripts_dir: Path) -> List[Tuple[str, Path]]:
"""
Получает список скриптов миграций из папки scripts.
Возвращает список кортежей (имя_файла, путь_к_файлу), отсортированный по имени файла.
"""
scripts = []
@@ -39,24 +40,25 @@ def get_migration_scripts(scripts_dir: Path) -> List[Tuple[str, Path]]:
async def is_migration_script(script_path: Path) -> bool:
"""
Проверяет, является ли скрипт миграцией.
Миграция должна иметь функцию main() с параметром db_path.
"""
try:
spec = importlib.util.spec_from_file_location("migration_script", script_path)
if spec is None or spec.loader is None:
return False
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Проверяем наличие функции main
if hasattr(module, 'main'):
if hasattr(module, "main"):
import inspect
sig = inspect.signature(module.main)
# Проверяем, что функция принимает db_path
params = list(sig.parameters.keys())
return 'db_path' in params
return "db_path" in params
return False
except Exception:
# Если не удалось проверить, считаем что это не миграция
@@ -66,12 +68,12 @@ async def is_migration_script(script_path: Path) -> bool:
async def apply_migration(script_path: Path, db_path: str) -> bool:
"""
Применяет миграцию, запуская скрипт.
Returns:
True если миграция применена успешно, False в противном случае.
"""
script_name = script_path.name
try:
# Запускаем скрипт как отдельный процесс
result = subprocess.run(
@@ -79,9 +81,9 @@ async def apply_migration(script_path: Path, db_path: str) -> bool:
cwd=script_path.parent.parent,
capture_output=True,
text=True,
timeout=300 # 5 минут максимум на миграцию
timeout=300, # 5 минут максимум на миграцию
)
if result.returncode == 0:
if result.stdout:
print(f" {result.stdout.strip()}")
@@ -93,7 +95,7 @@ async def apply_migration(script_path: Path, db_path: str) -> bool:
if result.stderr:
print(f" STDERR: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print(f" ❌ Превышен лимит времени (5 минут)")
return False
@@ -105,7 +107,7 @@ async def apply_migration(script_path: Path, db_path: str) -> bool:
async def main(db_path: str, dry_run: bool = False) -> None:
"""
Основная функция для применения миграций.
Args:
db_path: Путь к базе данных
dry_run: Если True, только показывает какие миграции будут применены
@@ -113,7 +115,7 @@ async def main(db_path: str, dry_run: bool = False) -> None:
# Импортируем зависимости только когда они действительно нужны
project_root = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(project_root))
# Проверяем наличие необходимых зависимостей
try:
import aiosqlite
@@ -121,53 +123,60 @@ async def main(db_path: str, dry_run: bool = False) -> None:
print("❌ Ошибка: модуль aiosqlite не установлен.")
print("💡 Установите зависимости: pip install -r requirements.txt")
sys.exit(1)
# Импортируем logger
try:
from logs.custom_logger import logger
except ImportError:
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
# Импортируем MigrationRepository напрямую из файла
migration_repo_path = project_root / "database" / "repositories" / "migration_repository.py"
migration_repo_path = (
project_root / "database" / "repositories" / "migration_repository.py"
)
if not migration_repo_path.exists():
print(f"❌ Файл migration_repository.py не найден: {migration_repo_path}")
sys.exit(1)
spec = importlib.util.spec_from_file_location("migration_repository", migration_repo_path)
spec = importlib.util.spec_from_file_location(
"migration_repository", migration_repo_path
)
if spec is None or spec.loader is None:
print("Не удалось загрузить модуль migration_repository")
sys.exit(1)
migration_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(migration_module)
MigrationRepository = migration_module.MigrationRepository
db_path = os.path.abspath(db_path)
if not os.path.exists(db_path):
logger.error(f"База данных не найдена: {db_path}")
print(f"❌ Ошибка: база данных не найдена: {db_path}")
return
scripts_dir = project_root / "scripts"
if not scripts_dir.exists():
logger.error(f"Папка scripts не найдена: {scripts_dir}")
print(f"❌ Ошибка: папка scripts не найдена: {scripts_dir}")
return
# Инициализируем репозиторий миграций напрямую
migration_repo = MigrationRepository(db_path)
await migration_repo.create_table()
# Получаем список примененных миграций
applied_migrations = await migration_repo.get_applied_migrations()
logger.info(f"Примененных миграций: {len(applied_migrations)}")
# Получаем все скрипты миграций
all_scripts = get_migration_scripts(scripts_dir)
# Фильтруем только миграции
migration_scripts = []
for script_name, script_path in all_scripts:
@@ -175,30 +184,31 @@ async def main(db_path: str, dry_run: bool = False) -> None:
migration_scripts.append((script_name, script_path))
else:
logger.debug(f"Скрипт {script_name} не является миграцией, пропускаем")
# Находим новые миграции
new_migrations = [
(name, path) for name, path in migration_scripts
(name, path)
for name, path in migration_scripts
if name not in applied_migrations
]
if not new_migrations:
print("Все миграции уже применены")
logger.info("Новых миграций не найдено")
return
print(f"📋 Найдено новых миграций: {len(new_migrations)}")
for name, _ in new_migrations:
print(f" - {name}")
if dry_run:
print("\n🔍 DRY RUN: миграции не будут применены")
return
# Применяем миграции по порядку
print("\n🚀 Применение миграций...")
failed_migrations = []
for script_name, script_path in new_migrations:
print(f"📝 {script_name}...", end=" ", flush=True)
success = await apply_migration(script_path, db_path)
@@ -213,7 +223,7 @@ async def main(db_path: str, dry_run: bool = False) -> None:
# Прерываем выполнение при ошибке
print(f"\n⚠️ Прерывание: миграция {script_name} завершилась с ошибкой")
break
if failed_migrations:
print(f"\nНе удалось применить {len(failed_migrations)} миграций:")
for name in failed_migrations:
@@ -224,9 +234,7 @@ async def main(db_path: str, dry_run: bool = False) -> None:
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Применение миграций базы данных"
)
parser = argparse.ArgumentParser(description="Применение миграций базы данных")
parser.add_argument(
"--db",
default=os.environ.get("DATABASE_PATH", DEFAULT_DB_PATH),