10 KiB
Simple Debug API - Calculadora MAV CAS
Descripción
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.
Uso
# Ejecutar debug
python simple_debug.py debug_input.json
# Con archivo de salida específico
python simple_debug.py debug_input.json --output debug_results.json
# Modo verboso
python simple_debug.py debug_input.json --verbose
Formato de Entrada
Estructura Simple
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "input", "content": "16#FF + 10"},
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
{"index": 3, "type": "input", "content": "x = 5"},
{"index": 4, "type": "exec", "content": "len(engine.symbol_table)"}
]
}
Tipos de Query
Input Query
Evalúa expresiones como si las escribieras en la calculadora:
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"}
{"index": 1, "type": "input", "content": "mask = 255.255.0.0"}
{"index": 2, "type": "input", "content": "solve(x**2 + 1, x)"}
Exec Query
Ejecuta código Python para inspeccionar el estado interno:
{"index": 3, "type": "exec", "content": "engine.symbol_table"}
{"index": 4, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
{"index": 5, "type": "exec", "content": "list(engine.base_context.keys())[:10]"}
Formato de Salida
Estructura de Respuesta
{
"execution_info": {
"timestamp": "2025-01-01T10:30:15Z",
"total_queries": 5,
"successful": 4,
"failed": 1
},
"results": [
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2",
"result_type": "FourBytes",
"success": true
},
{
"index": 1,
"input": "16#FF + 10",
"output": "16#109",
"result_type": "IntBase",
"success": true
},
{
"index": 2,
"input": "engine.symbol_table",
"output": "{'x': Symbol('x'), 'mask': FourBytes('255.255.0.0')}",
"result_type": "dict",
"success": true
}
]
}
Resultado Individual
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2",
"result_type": "FourBytes",
"success": true,
"error": null,
"display_class": "[FourBytes]"
}
Resultado con Error
{
"index": 3,
"input": "IP4Mask(255.240.0.3)",
"output": null,
"result_type": null,
"success": false,
"error": "ValueError: Máscara inválida: 255.240.0.3"
}
Resultado de Exec
{
"index": 4,
"input": "len(engine.symbol_table)",
"output": "3",
"result_type": "int",
"success": true,
"exec_result": 3
}
Casos de Uso Comunes
1. Debug de Tokenización
{
"queries": [
{"index": 0, "type": "input", "content": "192.168.1.1 + 16#FF"},
{"index": 1, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
]
}
2. Debug de Contexto
{
"queries": [
{"index": 0, "type": "input", "content": "x = 5"},
{"index": 1, "type": "input", "content": "y = x + 10"},
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
{"index": 3, "type": "exec", "content": "len(engine.equations)"}
]
}
3. Debug de Tipos
{
"queries": [
{"index": 0, "type": "input", "content": "ip = 10.1.1.x"},
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['ip'])"},
{"index": 2, "type": "exec", "content": "engine.symbol_table['ip'].has_symbols"},
{"index": 3, "type": "input", "content": "ip.substitute(x=5)"}
]
}
4. Debug de Errores
{
"queries": [
{"index": 0, "type": "input", "content": "bad_mask = 255.240.0.3"},
{"index": 1, "type": "input", "content": "IP4Mask(bad_mask)"},
{"index": 2, "type": "exec", "content": "engine.last_result"}
]
}
5. Testing de Regresión
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "exec", "content": "str(type(engine.last_result))"},
{"index": 2, "type": "exec", "content": "engine.last_result.original"},
{"index": 3, "type": "input", "content": "16#FF + 10"},
{"index": 4, "type": "exec", "content": "engine.last_result.base"}
]
}
Funciones Útiles para Exec
Estado del Motor
# Contexto y variables
"engine.symbol_table" # Variables actuales
"list(engine.base_context.keys())" # Funciones disponibles
"len(engine.equations)" # Ecuaciones en el sistema
"engine.last_result" # Último resultado
# Configuración del motor
"engine.symbolic_mode" # ¿Modo simbólico?
"engine.debug" # ¿Debug habilitado?
Información de Tipos
# Tipos registrados
"engine.get_available_types()" # Info completa de tipos
"list(engine.registered_types_info['registered_classes'].keys())" # Tipos disponibles
"engine.registered_types_info['class_count']" # Cantidad de tipos
# Análisis de objetos
"type(engine.last_result)" # Tipo del último resultado
"engine.last_result.__class__.__name__" # Nombre de la clase
"hasattr(engine.last_result, 'has_symbols')" # ¿Tiene símbolos?
Tokenización y Parsing
# Tokenización
"engine.parser.get_tokenization_info()" # Info de tokenización
"engine.parser.process_expression('test')" # Procesar expresión
"len(engine.parser.tokenizer.tokenization_rules)" # Cantidad de reglas
# Análisis de expresiones
"engine._classify_line('x = 5')" # Clasificar línea
"engine._extract_variable_names('x + y')" # Extraer variables
Testing de Funciones Específicas
# Testing de FourBytes
"engine.last_result._numeric_value" # Valor numérico interno
"engine.last_result.has_symbols" # ¿Tiene símbolos?
"engine.last_result.original" # String original
# Testing de IntBase
"engine.last_result.base" # Base numérica
"engine.last_result.value_str" # String del valor
"engine.last_result._symbols" # Símbolos detectados
Implementación Simple
Estructura Mínima
simple_debug.py # CLI principal (~100 líneas)
debug_templates/ # Templates de ejemplo
├── basic_test.json
├── tokenization_test.json
└── regression_test.json
CLI Principal (Pseudocódigo)
# simple_debug.py
import json
from main_evaluation import HybridEvaluationEngine
def run_debug(input_file, output_file=None):
# Cargar queries
with open(input_file) as f:
data = json.load(f)
# Crear motor
engine = HybridEvaluationEngine()
results = []
# Ejecutar cada query
for query in data['queries']:
if query['type'] == 'input':
result = engine.evaluate_line(query['content'])
output = {
'index': query['index'],
'input': query['content'],
'output': str(result.result),
'result_type': type(result.result).__name__,
'success': not result.is_error,
'error': result.error if result.is_error else None
}
elif query['type'] == 'exec':
try:
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,
'exec_result': exec_result
}
except Exception as e:
output = {
'index': query['index'],
'input': query['content'],
'success': False,
'error': str(e)
}
results.append(output)
# Guardar resultados
final_output = {
'execution_info': {...},
'results': results
}
with open(output_file, 'w') as f:
json.dump(final_output, f, indent=2)
Templates de Ejemplo
basic_test.json
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 2, "type": "input", "content": "16#FF"},
{"index": 3, "type": "exec", "content": "engine.last_result.base"}
]
}
tokenization_test.json
{
"queries": [
{"index": 0, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
{"index": 1, "type": "input", "content": "192.168.1.1 + 16#FF"},
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()['rules'][:3]"}
]
}
regression_test.json
{
"queries": [
{"index": 0, "type": "input", "content": "mask=255.240.0.0"},
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['mask']).__name__"},
{"index": 2, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 3, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 4, "type": "input", "content": "IP4Mask(255.255.0.0)"},
{"index": 5, "type": "exec", "content": "engine.last_result.get_prefix_int()"}
]
}
Ventajas de este Diseño
✅ Simplicidad: ~100 líneas de código total
✅ Sin modificaciones: Usa el motor existente tal como está
✅ Flexibilidad: Cualquier función del engine es accesible via exec
✅ Debugging real: Exactamente como usar la aplicación
✅ Fácil testing: JSON simple para casos de prueba
✅ Serialización automática: Python maneja la conversión a string
Esta aproximación te permite debuggear efectivamente sin crear una infraestructura compleja, usando el poder del motor existente.