Files
EricRorich-ComfyUI-face-shaper/validate_node_structure.py
copilot-swe-agent[bot]andEricRorich 33682fdf0a Update node identifier and increase eye/iris size limits
- Changed NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS keys from "RORICH-AI" to "Rorich"
- Increased max value from 2.0 to 3.0 for eye_left_size_x, eye_left_size_y, eye_right_size_x, eye_right_size_y
- Increased max value from 2.0 to 3.0 for iris_left_size and iris_right_size
- Updated validation script to expect "Rorich" key
- All defaults, mins, and steps remain unchanged

Co-authored-by: EricRorich <86147326+EricRorich@users.noreply.github.com>
2026-01-13 14:45:03 +00:00

314 lines
9.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Simple validation script to verify the node loads and renders without errors.
This script validates code structure without importing the actual node
(which would require numpy, torch, and PIL dependencies).
"""
import sys
import ast
import re
def validate_syntax():
"""Validate Python syntax."""
print("=" * 70)
print("1. Validating Python syntax")
print("=" * 70)
try:
with open('face_shaper.py', 'r') as f:
source = f.read()
# Parse the source code
ast.parse(source)
print("✓ Python syntax is valid")
print()
return True
except SyntaxError as e:
print(f"✗ FAILED: Syntax error at line {e.lineno}: {e.msg}")
print()
return False
def validate_imports():
"""Validate required imports are present."""
print("=" * 70)
print("2. Validating imports")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
content = f.read()
required_imports = [
'from typing import',
'import numpy',
'import torch',
'from PIL import Image',
]
for imp in required_imports:
if imp not in content:
print(f"✗ FAILED: Missing import: {imp}")
return False
print("✓ All required imports present")
print()
return True
def validate_class_structure():
"""Validate ComfyUIFaceShaper class structure."""
print("=" * 70)
print("3. Validating class structure")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
content = f.read()
# Check class definition
if 'class ComfyUIFaceShaper:' not in content:
print("✗ FAILED: ComfyUIFaceShaper class not found")
return False
print("✓ ComfyUIFaceShaper class defined")
# Check required attributes
required_attrs = ['CATEGORY', 'RETURN_TYPES', 'FUNCTION']
for attr in required_attrs:
if f'{attr} = ' not in content:
print(f"✗ FAILED: Missing class attribute: {attr}")
return False
print("✓ All required class attributes present")
# Check required methods
required_methods = ['INPUT_TYPES', 'draw_face']
for method in required_methods:
if f'def {method}' not in content:
print(f"✗ FAILED: Missing method: {method}")
return False
print("✓ All required methods present")
# Verify CATEGORY value
if 'CATEGORY = "face"' not in content:
print("✗ FAILED: CATEGORY should be 'face'")
return False
print("✓ CATEGORY is 'face'")
# Verify RETURN_TYPES value
if 'RETURN_TYPES = ("IMAGE", "LIST")' not in content:
print("✗ FAILED: RETURN_TYPES should be ('IMAGE', 'LIST')")
return False
print("✓ RETURN_TYPES is ('IMAGE', 'LIST')")
print()
return True
def validate_node_mappings():
"""Validate NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS."""
print("=" * 70)
print("4. Validating node mappings")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
content = f.read()
# Check NODE_CLASS_MAPPINGS
if 'NODE_CLASS_MAPPINGS' not in content:
print("✗ FAILED: NODE_CLASS_MAPPINGS not found")
return False
if '"Rorich": ComfyUIFaceShaper' not in content:
print("✗ FAILED: NODE_CLASS_MAPPINGS should map 'Rorich' to ComfyUIFaceShaper")
return False
print("✓ NODE_CLASS_MAPPINGS configured correctly")
# Check NODE_DISPLAY_NAME_MAPPINGS
if 'NODE_DISPLAY_NAME_MAPPINGS' not in content:
print("✗ FAILED: NODE_DISPLAY_NAME_MAPPINGS not found")
return False
if '"Rorich": "Face Shaper"' not in content:
print("✗ FAILED: NODE_DISPLAY_NAME_MAPPINGS should map to 'Face Shaper'")
return False
print("✓ NODE_DISPLAY_NAME_MAPPINGS configured correctly")
print()
return True
def validate_parameter_count():
"""Validate the total parameter count is reasonable."""
print("=" * 70)
print("5. Validating parameter count")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
source = f.read()
tree = ast.parse(source)
# Find draw_face method
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == 'draw_face':
params = [arg.arg for arg in node.args.args if arg.arg != 'self' and arg.arg != 'settings_list']
print(f"✓ Total parameters in draw_face: {len(params)}")
# Parameter count: removed 2 chin parameters (chin_size_x, chin_size_y)
# and added 2 eye rotation parameters (eye_left_rotation, eye_right_rotation)
# Net change: 0 parameters, so expected count remains ~48
if len(params) < 46 or len(params) > 50:
print(f" ⚠ WARNING: Unexpected parameter count (expected ~48)")
else:
print(f" ✓ Parameter count looks reasonable")
print()
return True
print("✗ FAILED: Could not find draw_face method")
return False
def validate_no_chin_references():
"""Final check: no chin-related code should remain."""
print("=" * 70)
print("6. Final check: No chin references")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
content = f.read()
# Remove comments to avoid false positives
content_no_comments = re.sub(r'#.*', '', content)
content_no_comments = re.sub(r'""".*?"""', '', content_no_comments, flags=re.DOTALL)
content_no_comments = re.sub(r"'''.*?'''", '', content_no_comments, flags=re.DOTALL)
# Check for chin references
chin_patterns = [
'"chin"',
"'chin'",
'chin_pos',
'chin_size',
]
found = []
for pattern in chin_patterns:
if pattern in content_no_comments:
found.append(pattern)
if found:
print(f"✗ FAILED: Found chin references: {found}")
return False
print("✓ No chin references found in code")
print()
return True
def validate_no_ear_references():
"""Check: no ear-related code should remain."""
print("=" * 70)
print("7. Check: No ear references")
print("=" * 70)
with open('face_shaper.py', 'r') as f:
content = f.read()
# Remove comments to avoid false positives
content_no_comments = re.sub(r'#.*', '', content)
content_no_comments = re.sub(r'""".*?"""', '', content_no_comments, flags=re.DOTALL)
content_no_comments = re.sub(r"'''.*?'''", '', content_no_comments, flags=re.DOTALL)
# Check for ear references
ear_patterns = [
'"ear_left"',
'"ear_right"',
"'ear_left'",
"'ear_right'",
'ear_left_pos',
'ear_right_pos',
'ear_left_size',
'ear_right_size',
'debug_ears',
]
found = []
for pattern in ear_patterns:
if pattern in content_no_comments:
found.append(pattern)
if found:
print(f"✗ FAILED: Found ear references: {found}")
return False
print("✓ No ear references found in code")
print()
return True
def main():
"""Run all validation checks."""
print("\n" + "=" * 70)
print("BASIC VALIDATION: Node Structure and Functionality")
print("=" * 70 + "\n")
tests = [
("Python syntax", validate_syntax),
("Required imports", validate_imports),
("Class structure", validate_class_structure),
("Node mappings", validate_node_mappings),
("Parameter count", validate_parameter_count),
("No chin references", validate_no_chin_references),
("No ear references", validate_no_ear_references),
]
results = []
for name, test_func in tests:
try:
success = test_func()
results.append((name, success))
except Exception as e:
print(f"✗ EXCEPTION in {name}: {e}\n")
results.append((name, False))
# Summary
print("=" * 70)
print("VALIDATION SUMMARY")
print("=" * 70 + "\n")
passed = sum(1 for _, success in results if success)
total = len(results)
for name, success in results:
status = "✓ PASS" if success else "✗ FAIL"
print(f"{status}: {name}")
print(f"\nTotal: {passed}/{total} tests passed")
if passed == total:
print("\n" + "=" * 70)
print("✓✓✓ ALL VALIDATION TESTS PASSED ✓✓✓")
print("=" * 70)
print("\nThe node is ready to use!")
print("• No syntax errors")
print("• All required methods and attributes present")
print("• No chin-related code remains")
print("• No ear-related code remains")
print("• Node name and category unchanged")
return 0
else:
print("\n" + "=" * 70)
print("✗✗✗ SOME VALIDATION TESTS FAILED ✗✗✗")
print("=" * 70)
return 1
if __name__ == "__main__":
sys.exit(main())