"""Validation utilities for generated code.""" import ast import os from pathlib import Path from typing import List, Optional def validate_python_syntax(file_path: Path) -> tuple[bool, Optional[str]]: """Check if a Python file has valid syntax.""" try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() ast.parse(content) return True, None except SyntaxError as e: return False, f"Syntax error at line {e.lineno}: {e.msg}" except Exception as e: return False, str(e) def validate_required_files_exist(repo_dir: Path, required_files: List[str]) -> List[str]: """Check that required files exist in the repository.""" missing = [] for file in required_files: if not (repo_dir / file).exists(): missing.append(file) return missing def validate_imports(file_path: Path) -> List[str]: """Check for likely missing imports (basic heuristic).""" try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() tree = ast.parse(content) defined_names = set() used_names = set() for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): defined_names.add(node.name) elif isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load): used_names.add(node.id) elif isinstance(node, ast.Attribute): # Capture attribute access like os.path if isinstance(node.value, ast.Name): used_names.add(f"{node.value.id}.{node.attr}") undefined = used_names - defined_names - set(__builtins__.keys()) # Filter out likely imports from standard library and common packages common_imports = { "os", "sys", "json", "logging", "typing", "Path", "Optional", "List", "Dict", "Any", "Union", "Callable", "subprocess", "requests", "fastapi", "gradio", "uvicorn", } possibly_undefined = [n for n in undefined if n not in common_imports] return possibly_undefined except Exception: return [] def validate_file_not_empty(file_path: Path) -> bool: """Check that a file has non-empty content.""" return file_path.exists() and file_path.stat().st_size > 10 def validate_has_main_block(file_path: Path) -> bool: """Check if Python file has a main execution block.""" try: with open(file_path, "r", encoding="utf-8") as f: content = f.read() tree = ast.parse(content) for node in ast.walk(tree): if isinstance(node, ast.If): if ( isinstance(node.test, ast.Compare) and any(isinstance(op, ast.Eq) for op in node.test.ops) and any( isinstance(comp, ast.Name) and comp.id == "__name__" for comp in node.test.comparators ) ): return True return False except Exception: return False