/
urfu_itis_tasks
/
debug_101-Patsyuk
Обзор
Документация
Войти
/
urfu_itis_tasks
/
debug_101-Patsyuk
Код
Запросы
1
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
scripts/check_strict.py
403 строки
15 KB
urfu_itis_tasks
Initial commit
27 окт 2025, 23:59
27 окт 2025, 23:59
c1603f3
Код
Авторство
О чём код?
#!/usr/bin/env python3 """ Строгий чекер для проверки решений - Проверяет исправление кода - Проверяет REPORT.md - Проверяет длину коммит-сообщения - Читает ошибки из CSV базы """ import sys import os import re import ast import subprocess import pandas as pd class StrictChecker: """Проверяет что ошибки исправлены в коде""" def __init__(self, filename): self.filename = filename self.content = self._read_file() self.original_code = self._extract_section('ИСПРАВЬТЕ КОД НИЖЕ') self.task_id = self._extract_task_id() self.expected_errors = self._get_errors_from_csv() self.errors = [] self.warnings = [] def _read_file(self): """Читает файл""" try: with open(self.filename, 'r', encoding='utf-8') as f: return f.read() except FileNotFoundError: raise Exception(f"Файл {self.filename} не найден") def _extract_section(self, section_name): """Извлекает секцию из файла""" pattern = f'# {section_name}.*?# =+\s*\n(.*?)(?:# КОНЕЦ|$)' match = re.search(pattern, self.content, re.DOTALL) return match.group(1).strip() if match else None def _extract_task_id(self): """Извлекает номер задания из файла""" match = re.search(r'Задание #(\d+)', self.content) return int(match.group(1)) if match else None def _get_errors_from_csv(self): """Читает описание ошибок из CSV""" csv_path = os.path.join(os.path.dirname(__file__), '..', 'scripts', '100_vibe_coding_tasks.csv') # Попытка найти CSV в разных местах possible_paths = [ os.path.join(os.path.dirname(__file__), '100_vibe_coding_tasks.csv'), os.path.join(os.path.dirname(__file__), '..', 'scripts', '100_vibe_coding_tasks.csv'), os.path.join(os.getcwd(), '100_vibe_coding_tasks.csv'), os.path.join(os.getcwd(), 'scripts', '100_vibe_coding_tasks.csv'), ] for path in possible_paths: if os.path.exists(path): try: df = pd.read_csv(path) if self.task_id and self.task_id in df['id'].values: task = df[df['id'] == self.task_id].iloc[0] errors_str = str(task.get('errors', '')) return errors_str.split(';') if errors_str else [] except Exception as e: print(f"⚠️ Ошибка чтения CSV: {e}") return [] return [] def check_has_code_section(self): """Проверяет наличие секции с кодом""" if not self.original_code: self.errors.append("❌ Секция 'ИСПРАВЬТЕ КОД НИЖЕ' не найдена") return False if len(self.original_code.strip()) < 10: self.errors.append("❌ Секция с кодом пустая") return False return True def check_syntax_valid(self): """Проверяет синтаксис исправленного кода""" if not self.original_code: return False try: ast.parse(self.original_code) self.warnings.append("✅ Синтаксис исправлен") return True except SyntaxError as e: self.errors.append(f"❌ Синтаксическая ошибка: {e.msg} на строке {e.lineno}") return False def check_code_runs(self): """Проверяет что исправленный код выполняется""" if not self.original_code: return False try: namespace = {} exec(self.original_code, namespace) self.warnings.append("✅ Код выполняется без ошибок") return True except Exception as e: self.errors.append(f"❌ Ошибка выполнения: {type(e).__name__}: {str(e)[:50]}") return False def check_errors_description(self): """Проверяет что ошибки из CSV описаны""" if not self.expected_errors: self.warnings.append("ℹ️ Описание ошибок из CSV не найдено") return True # Проверяем что хотя бы одна ошибка упомянута code_lower = self.original_code.lower() mentioned = False for error in self.expected_errors: if error and len(error.strip()) > 0: # Ищем ключевые слова из описания ошибки error_keywords = error.split()[:3] # Первые 3 слова if any(kw.lower() in code_lower for kw in error_keywords if len(kw) > 2): mentioned = True break if mentioned or not self.expected_errors: self.warnings.append("✅ Ошибки соответствуют описанию") return True return True # Не критично def generate_report(self): """Генерирует отчет""" report = [] report.append("\n" + "="*80) report.append(f"ПРОВЕРКА: {self.filename} (Задание #{self.task_id})") report.append("="*80) report.append("\n1️⃣ СТРУКТУРА ФАЙЛА:") if self.check_has_code_section(): report.append(" ✅ Найдена секция 'ИСПРАВЬТЕ КОД НИЖЕ'") else: return "\n".join(report + self.errors) report.append("\n2️⃣ СИНТАКСИС:") if self.check_syntax_valid(): report.append(" ✅ Синтаксис корректен") else: report.append(" ❌ Синтаксические ошибки") report.append("\n3️⃣ ВЫПОЛНЕНИЕ:") if self.check_code_runs(): report.append(" ✅ Код выполняется") else: report.append(" ❌ Ошибки при выполнении") report.append("\n4️⃣ ОШИБКИ ИЗ CSV:") self.check_errors_description() if self.expected_errors: report.append(f" 📋 Ожидаемые ошибки: {'; '.join([e.strip() for e in self.expected_errors if e])}") if self.errors: report.append("\n" + "❌ ОШИБКИ:") for error in self.errors: report.append(f" {error}") if self.warnings: report.append("\n" + "✅ РЕЗУЛЬТАТЫ:") for warning in self.warnings: report.append(f" {warning}") report.append("\n" + "="*80) return "\n".join(report) def check_all(self): """Запускает все проверки""" self.check_has_code_section() self.check_syntax_valid() self.check_code_runs() self.check_errors_description() return len(self.errors) == 0 class ReportChecker: """Проверяет REPORT.md""" def __init__(self): self.report_file = 'REPORT.md' self.min_length = 100 self.errors = [] self.warnings = [] def check_exists(self): """Проверяет существование REPORT.md""" if not os.path.exists(self.report_file): self.errors.append(f"❌ Файл {self.report_file} не найден") return False self.warnings.append(f"✅ Файл {self.report_file} найден") return True def check_length(self): """Проверяет минимальную длину""" try: with open(self.report_file, 'r', encoding='utf-8') as f: content = f.read() length = len(content) if length < self.min_length: self.errors.append(f"❌ Отчет слишком короткий ({length} символов, требуется {self.min_length})") return False self.warnings.append(f"✅ Отчет содержит {length} символов") return True except Exception as e: self.errors.append(f"❌ Ошибка чтения {self.report_file}: {e}") return False def generate_report(self): """Генерирует отчет о проверке REPORT.md""" report = [] report.append("\n" + "="*80) report.append("ПРОВЕРКА REPORT.md") report.append("="*80) report.append("\n1️⃣ СУЩЕСТВОВАНИЕ ФАЙЛА:") if self.check_exists(): report.append(" ✅ REPORT.md найден") else: return "\n".join(report + self.errors) report.append("\n2️⃣ МИНИМАЛЬНАЯ ДЛИНА (100 символов):") if self.check_length(): report.append(" ✅ Достаточно символов") else: report.append(" ❌ Слишком короткий отчет") if self.errors: report.append("\n" + "❌ ОШИБКИ:") for error in self.errors: report.append(f" {error}") if self.warnings: report.append("\n" + "✅ РЕЗУЛЬТАТЫ:") for warning in self.warnings: report.append(f" {warning}") report.append("\n" + "="*80) return "\n".join(report) def check_all(self): """Запускает все проверки""" self.check_exists() self.check_length() return len(self.errors) == 0 class CommitMessageChecker: """Проверяет длину коммит-сообщения""" def __init__(self): self.min_length = 20 self.errors = [] self.warnings = [] self.message = self._get_last_commit_message() def _get_last_commit_message(self): """Получает последнее коммит-сообщение""" try: result = subprocess.run( ['git', 'log', '-1', '--pretty=%B'], capture_output=True, text=True, timeout=5 ) if result.returncode == 0: return result.stdout.strip() else: self.errors.append("⚠️ Не удалось получить коммит-сообщение") return None except Exception as e: self.warnings.append(f"ℹ️ Git недоступен: {e}") return None def check_length(self): """Проверяет длину коммит-сообщения""" if not self.message: self.errors.append(f"❌ Коммит-сообщение не найдено") return False length = len(self.message) if length < self.min_length: self.errors.append(f"❌ Коммит-сообщение слишком короткое ({length} символов, требуется {self.min_length})") return False self.warnings.append(f"✅ Коммит-сообщение корректно ({length} символов)") return True def generate_report(self): """Генерирует отчет о проверке коммита""" report = [] report.append("\n" + "="*80) report.append("ПРОВЕРКА КОММИТ-СООБЩЕНИЯ") report.append("="*80) if self.message: report.append(f"\n📝 Сообщение: {self.message[:60]}...") report.append("\n1️⃣ МИНИМАЛЬНАЯ ДЛИНА (20 символов):") if self.check_length(): report.append(" ✅ Сообщение достаточно длинное") else: report.append(" ❌ Сообщение слишком короткое") if self.errors: report.append("\n" + "❌ ОШИБКИ:") for error in self.errors: report.append(f" {error}") if self.warnings: report.append("\n" + "ℹ️ ПРИМЕЧАНИЯ:") for warning in self.warnings: report.append(f" {warning}") report.append("\n" + "="*80) return "\n".join(report) def check_all(self): """Запускает все проверки""" self.check_length() return len(self.errors) == 0 def main(): """Главная функция""" print("\n" + "="*80) print("КОМПЛЕКСНАЯ ПРОВЕРКА РЕШЕНИЙ") print("="*80) # Проверка файлов с кодом files = ['python_easy.py', 'python_medium.py', 'python_hard.py'] code_all_passed = True for filename in files: if os.path.exists(filename): try: checker = StrictChecker(filename) checker.check_all() print(checker.generate_report()) if checker.errors: code_all_passed = False except Exception as e: print(f"\n❌ Ошибка при проверке {filename}: {e}") code_all_passed = False # Проверка REPORT.md report_checker = ReportChecker() report_passed = report_checker.check_all() print(report_checker.generate_report()) # Проверка коммит-сообщения commit_checker = CommitMessageChecker() commit_passed = commit_checker.check_all() print(commit_checker.generate_report()) # Итоговый результат print("\n" + "="*80) print("ИТОГОВЫЙ РЕЗУЛЬТАТ:") print("="*80) if code_all_passed and report_passed and commit_passed: print("✅ ВСЕ ПРОВЕРКИ ПРОЙДЕНЫ!") print(" - Код исправлен правильно") print(" - REPORT.md заполнен (100+ символов)") print(" - Коммит-сообщение информативно (20+ символов)") sys.exit(0) else: print("❌ ТРЕБУЮТСЯ ИСПРАВЛЕНИЯ:") if not code_all_passed: print(" - Исправьте ошибки в коде") if not report_passed: print(" - Заполните REPORT.md (минимум 100 символов)") if not commit_passed: print(" - Улучшите коммит-сообщение (минимум 20 символов)") sys.exit(1) if __name__ == "__main__": main()