Calc/simple_debug.py

208 lines
7.0 KiB
Python

#!/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 el motor de evaluación existente
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)
# Crear motor de evaluación
if verbose:
print("Iniciando motor de evaluación...")
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: 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: <input>_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()