Исходный код run_tests

# run_tests.py
#!/usr/bin/env python3
"""
Скрипт для запуска всех тестов проекта с отладочными выводами.

Этот скрипт предоставляет удобный интерфейс для запуска всех тестов проекта
с подробным логированием, визуальными индикаторами выполнения и измерением
времени выполнения. Поддерживает автоматическое определение наличия
библиотеки tqdm для отображения прогресс-бара.
"""
import subprocess
import sys
import os
from pathlib import Path
import time
from datetime import datetime

[документация] def get_project_root(): """Возвращает корневую директорию проекта. Определяет и возвращает путь к корневой директории проекта на основе расположения текущего файла скрипта. :return: Объект Path, представляющий корневую директорию проекта :rtype: pathlib.Path """ return Path(__file__).parent
[документация] def run_command(command, cwd=None): """Выполняет команду и возвращает результат. Запускает указанную команду в подпроцессе с отображением времени выполнения, визуальных индикаторов и обработкой ошибок. Поддерживает отображение прогресс-бара через библиотеку tqdm, если она доступна. :param command: Список аргументов командной строки для выполнения :type command: list[str] :param cwd: Рабочая директория для выполнения команды (по умолчанию None) :type cwd: str or pathlib.Path, optional :return: True если команда выполнена успешно (код возврата 0), False в случае ошибки :rtype: bool """ print(f"🕐 [{datetime.now().strftime('%H:%M:%S')}] Выполняю: {' '.join(command)}") start_time = time.time() try: # Проверяем наличие tqdm для прогресс-бара try: from tqdm import tqdm has_tqdm = True except ImportError: has_tqdm = False print("ℹ️ tqdm не найден. Установите его для прогресс-бара: pip install tqdm") # Запускаем процесс process = subprocess.Popen( command, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8", errors="replace", bufsize=1, universal_newlines=True ) # Читаем вывод построчно с отображением прогресса stdout_lines = [] stderr_lines = [] if has_tqdm: from tqdm import tqdm # Создаем прогресс-бар pbar = tqdm(desc="Запуск тестов", unit="сек", leave=True) last_update = time.time() while True: if process.poll() is not None: # Процесс завершен break # Обновляем прогресс-бар current_time = time.time() if current_time - last_update >= 1: # Обновляем каждую секунду pbar.update(int(current_time - last_update)) last_update = current_time time.sleep(0.1) pbar.close() else: print("⏳ Тесты запущены, ожидаем завершения...") # Просто ждем завершения с периодическим сообщением wait_time = 0 while process.poll() is None: time.sleep(1) wait_time += 1 if wait_time % 10 == 0: # Сообщение каждые 10 секунд print(f"⏳ Тесты работают уже {wait_time} секунд...") # Получаем финальный результат stdout, stderr = process.communicate() end_time = time.time() duration = end_time - start_time print(f"🕐 [{datetime.now().strftime('%H:%M:%S')}] Завершено за {duration:.2f} секунд") if process.returncode == 0: print("✅ Успешно") else: print("❌ Ошибка:") if stdout: print("STDOUT:", stdout) if stderr: print("STDERR:", stderr) return process.returncode == 0 except Exception as e: end_time = time.time() duration = end_time - start_time print(f"🕐 [{datetime.now().strftime('%H:%M:%S')}] Завершено за {duration:.2f} секунд") print(f"❌ Ошибка выполнения: {e}") return False
[документация] def check_pytest(): """Проверяет наличие pytest и выводит информацию о нем. Выполняет проверку доступности pytest в текущем окружении, отображает версию установленного пакета и обрабатывает возможные ошибки проверки. :return: True если pytest доступен и работает корректно, False в случае ошибки :rtype: bool """ print("🔍 Проверяю наличие pytest...") try: result = subprocess.run( [sys.executable, "-m", "pytest", "--version"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: print(f"✅ pytest найден: {result.stdout.strip()}") return True else: print("❌ Ошибка при проверке pytest") return False except subprocess.TimeoutExpired: print("❌ Таймаут при проверке pytest") return False except Exception as e: print(f"❌ Ошибка при проверке pytest: {e}") return False
[документация] def main(): """Основная точка входа в скрипт. Выполняет полный цикл запуска тестов: проверяет окружение, определяет доступные тесты, запускает их выполнение и отображает результаты. Включает подробное логирование всех этапов выполнения. :return: True если все тесты пройдены успешно, False в случае ошибок :rtype: bool """ project_root = get_project_root() print("🚀 Запуск всех тестов проекта") print("=" * 60) print(f"📁 Рабочая директория: {project_root}") print(f"🕐 Начало: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # Проверяем наличие pytest if not check_pytest(): print("❌ pytest не найден. Установите его: pip install pytest") return False # Проверяем наличие директории с тестами test_dir = project_root / "test_suite" if not test_dir.exists(): print(f"❌ Директория с тестами не найдена: {test_dir}") return False print(f"📋 Найдено тестов: {len(list(test_dir.glob('test_*.py')))} файлов") # Запускаем все тесты print("\n📋 Запуск всех тестов...") test_command = [ sys.executable, "-m", "pytest", "test_suite/", "-v", # подробный вывод "--tb=short" # краткий traceback ] print(f"🔧 Команда: {' '.join(test_command)}") print("-" * 60) success = run_command(test_command, cwd=project_root) end_time = datetime.now() print("=" * 60) if success: print(f"🎉 Все тесты успешно пройдены! Завершено: {end_time.strftime('%Y-%m-%d %H:%M:%S')}") return True else: print(f"💥 Некоторые тесты провалены! Завершено: {end_time.strftime('%Y-%m-%d %H:%M:%S')}") return False
if __name__ == "__main__": try: success = main() sys.exit(0 if success else 1) except KeyboardInterrupt: print("\n⚠️ Прервано пользователем") sys.exit(1) except Exception as e: print(f"\n💥 Критическая ошибка: {e}") sys.exit(1)