Download utils/code_validator.py from sourize/manimate: direct link, hf CLI and curl.
- Browser
- Download file 4.48 kB
-
https://huggingface.co/spaces/sourize/manimate/resolve/main/utils/code_validator.py
- Command line
-
hf download hf://spaces/sourize/manimate/utils/code_validator.py
-
curl -L -o code_validator.py https://huggingface.co/spaces/sourize/manimate/resolve/main/utils/code_validator.py
4.48 kB
| """ | |
| Enhanced Code validation utilities for Manim code generation | |
| """ | |
| import re | |
| import ast | |
| import logging | |
| from typing import Tuple, Optional, Dict, Any, List | |
| logger = logging.getLogger(__name__) | |
| class CodeValidator: | |
| """Validates and fixes Manim code generation issues.""" | |
| def fix_common_issues(code: str) -> str: | |
| """Fix common issues in generated Manim code.""" | |
| # Remove markdown formatting | |
| code = re.sub(r'```python\n?', '', code) | |
| code = re.sub(r'```\n?', '', code) | |
| code = code.replace('```', '') | |
| code = code.replace('`', '') | |
| # Fix string literals in Text objects | |
| code = re.sub(r'Text\(([^"\'()\[\]]*?)\)', r'Text("\1")', code) | |
| code = re.sub(r'Text\(([^"\']*?), font_size', r'Text("\1", font_size', code) | |
| # Fix unterminated string literals | |
| lines = code.split('\n') | |
| fixed_lines = [] | |
| for line in lines: | |
| if 'Text(' in line and line.count('"') % 2 != 0: | |
| # Add closing quote before comma or parenthesis | |
| line = re.sub(r'([^"]*?)(,|\))', r'\1"\2', line) | |
| fixed_lines.append(line) | |
| code = '\n'.join(fixed_lines) | |
| # Ensure proper imports | |
| if not re.search(r'from manim import \*', code): | |
| code = 'from manim import *\n\n' + code | |
| return code.strip() | |
| def validate_python_syntax(code: str) -> Tuple[bool, Optional[str]]: | |
| """Validate Python syntax of the generated code.""" | |
| try: | |
| ast.parse(code) | |
| return True, None | |
| except SyntaxError as e: | |
| return False, str(e) | |
| def has_scene_class(code: str) -> bool: | |
| """Check if the code has a proper Scene class.""" | |
| try: | |
| tree = ast.parse(code) | |
| for node in ast.walk(tree): | |
| if isinstance(node, ast.ClassDef): | |
| # Check if it inherits from Scene | |
| for base in node.bases: | |
| if isinstance(base, ast.Name) and base.id == 'Scene': | |
| return True | |
| elif isinstance(base, ast.Attribute) and base.attr == 'Scene': | |
| return True | |
| return False | |
| except SyntaxError: | |
| return False | |
| def has_construct_method(code: str) -> bool: | |
| """Check if the Scene class has a construct method.""" | |
| try: | |
| tree = ast.parse(code) | |
| for node in ast.walk(tree): | |
| if isinstance(node, ast.ClassDef): | |
| for item in node.body: | |
| if isinstance(item, ast.FunctionDef) and item.name == 'construct': | |
| return True | |
| return False | |
| except SyntaxError: | |
| return False | |
| def has_animations(code: str) -> bool: | |
| """Check if the code has at least one animation.""" | |
| required_patterns = [ | |
| r'self\.play\(', | |
| r'self\.wait\(' | |
| ] | |
| for pattern in required_patterns: | |
| if not re.search(pattern, code): | |
| return False | |
| return True | |
| def validate_manim_code(code: str) -> Tuple[bool, Optional[str]]: | |
| """Validate that the code meets Manim requirements.""" | |
| # Check basic structure | |
| if not CodeValidator.has_scene_class(code): | |
| return False, "Code must contain a class that inherits from Scene" | |
| if not CodeValidator.has_construct_method(code): | |
| return False, "Scene class must have a construct method" | |
| if not CodeValidator.has_animations(code): | |
| return False, "Code must include at least one animation (self.play) and wait" | |
| # Check for problematic patterns | |
| problematic_patterns = [ | |
| r'for\s+\*', | |
| r'\*\s*=', | |
| r'^\s*\*', # Lines starting with * | |
| r'get\*center', | |
| r'import\s+\*', # No wildcard imports except manim | |
| r'from\s+[^\s]+\s+import\s+\*' # No wildcard imports except manim | |
| ] | |
| for pattern in problematic_patterns: | |
| if re.search(pattern, code, re.MULTILINE): | |
| return False, f"Code contains problematic pattern: {pattern}" | |
| return True, None |