#!/usr/bin/env python3 """ Simple Debug API - Calculadora MAV CAS API CLI simple que usa el motor de evaluación existente para generar debug traces sin modificar el código base. Permite debuggear "como si usaras la aplicación" mediante archivos JSON. Principio: texto → texto tal como se muestra en la aplicación. No duplica lógica, solo encapsula llamadas directas. Uso: python simple_debug.py debug_input.json python simple_debug.py debug_input.json --output debug_results.json python simple_debug.py debug_input.json --verbose """ import json import sys import argparse from datetime import datetime from pathlib import Path # Importar motores de evaluación from .main_evaluation import HybridEvaluationEngine def run_debug(input_file: str, output_file: str = None, verbose: bool = False): """ Ejecuta las queries de debug desde un archivo JSON y guarda los resultados. Args: input_file: Archivo JSON con las queries output_file: Archivo de salida (opcional) verbose: Modo verboso """ # Cargar queries del archivo de entrada try: with open(input_file, 'r', encoding='utf-8') as f: data = json.load(f) except FileNotFoundError: print(f"Error: No se encontró el archivo '{input_file}'") sys.exit(1) except json.JSONDecodeError as e: print(f"Error: JSON inválido en '{input_file}': {e}") sys.exit(1) if 'queries' not in data: print("Error: El archivo JSON debe contener una clave 'queries'") sys.exit(1) # Determinar qué motor usar engine_module = data.get('engine_module', 'main_evaluation') if verbose: print(f"Usando motor: {engine_module}") print("Iniciando motor de evaluación...") # Crear motor de evaluación según el módulo especificado if engine_module == 'main_evaluation_puro': from .main_evaluation import PureAlgebraicEngine engine = PureAlgebraicEngine() else: # Motor por defecto engine = HybridEvaluationEngine() results = [] successful = 0 failed = 0 # Ejecutar cada query for query in data['queries']: if verbose: print(f"Ejecutando query {query.get('index', '?')}: {query.get('content', '')[:50]}...") try: if query['type'] == 'input': # Query de tipo input: evaluar expresión como si fuera entrada del usuario result = engine.evaluate_line(query['content']) # Capturar resultado directo sin procesamiento output = { 'index': query['index'], 'input': query['content'], 'output': str(result.result) if hasattr(result, 'result') else str(result), 'result_type': type(result.result).__name__ if hasattr(result, 'result') else type(result).__name__, 'success': not (hasattr(result, 'is_error') and result.is_error), 'error': result.error if hasattr(result, 'is_error') and result.is_error else None } if not (hasattr(result, 'is_error') and result.is_error): successful += 1 else: failed += 1 elif query['type'] == 'exec': # Query de tipo exec: evaluar usando el motor adecuado if engine_module == 'main_evaluation_puro': # Para motor puro, evaluar directamente result = engine.evaluate_line(query['content']) output = { 'index': query['index'], 'input': query['content'], 'output': result.output, 'result_type': result.result_type, 'success': result.success, 'error': result.error_message } if result.success: successful += 1 else: failed += 1 else: # Motor original: ejecutar código Python para inspeccionar el estado exec_result = eval(query['content'], {'engine': engine}) output = { 'index': query['index'], 'input': query['content'], 'output': str(exec_result), 'result_type': type(exec_result).__name__, 'success': True, 'error': None, 'exec_result': exec_result } successful += 1 else: raise ValueError(f"Tipo de query desconocido: {query['type']}") except Exception as e: # Manejar errores en la ejecución output = { 'index': query['index'], 'input': query['content'], 'output': None, 'result_type': None, 'success': False, 'error': str(e) } failed += 1 if verbose: print(f" Error: {str(e)}") results.append(output) # Preparar salida final final_output = { 'execution_info': { 'timestamp': datetime.now().isoformat() + 'Z', 'total_queries': len(data['queries']), 'successful': successful, 'failed': failed, 'input_file': input_file }, 'results': results } # Determinar archivo de salida if output_file is None: base_name = Path(input_file).stem output_file = f"{base_name}_results.json" # Guardar resultados try: # Serialización simple con fallback a string with open(output_file, 'w', encoding='utf-8') as f: json.dump(final_output, f, indent=2, ensure_ascii=False, default=str) if verbose: print(f"\nResultados guardados en: {output_file}") print(f"Queries exitosas: {successful}") print(f"Queries con error: {failed}") except Exception as e: print(f"Error al guardar resultados: {e}") sys.exit(1) return final_output def main(): """Función principal del CLI""" parser = argparse.ArgumentParser( description='Simple Debug API para Calculadora MAV CAS', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Ejemplos de uso: python simple_debug.py debug_input.json python simple_debug.py debug_input.json --output custom_results.json python simple_debug.py debug_input.json --verbose """ ) parser.add_argument('input_file', help='Archivo JSON con las queries de debug') parser.add_argument('--output', '-o', help='Archivo de salida (por defecto: _results.json)') parser.add_argument('--verbose', '-v', action='store_true', help='Modo verboso') args = parser.parse_args() # Verificar que el archivo de entrada existe if not Path(args.input_file).exists(): print(f"Error: El archivo '{args.input_file}' no existe") sys.exit(1) # Ejecutar debug try: results = run_debug(args.input_file, args.output, args.verbose) # Mostrar resumen si no es modo verboso if not args.verbose: info = results['execution_info'] print(f"Debug completado: {info['successful']}/{info['total_queries']} exitosas") if args.output: print(f"Resultados en: {args.output}") else: base_name = Path(args.input_file).stem print(f"Resultados en: {base_name}_results.json") except KeyboardInterrupt: print("\nInterrumpido por el usuario") sys.exit(1) except Exception as e: print(f"Error inesperado: {e}") sys.exit(1) if __name__ == '__main__': main()