Calc/.doc/refactoring/debug_api_docs.md

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.