From 1bf1e47c0458aebd9d085d3d03bb2c2e66e36e14 Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 5 Jun 2025 18:27:56 +0200 Subject: [PATCH] Mejorado para que la API de Debug sea solo un wrap y no necesite actualizacion --- LLM_DEBUG_API_GUIDE.md | 462 ++++++++++++++++++++++++++++++++++++++ basic_test_results.json | 274 +--------------------- debug_templates/README.md | 53 ++--- error_debug_results.json | 20 +- simple_debug.py | 264 +--------------------- 5 files changed, 503 insertions(+), 570 deletions(-) create mode 100644 LLM_DEBUG_API_GUIDE.md diff --git a/LLM_DEBUG_API_GUIDE.md b/LLM_DEBUG_API_GUIDE.md new file mode 100644 index 0000000..083a39f --- /dev/null +++ b/LLM_DEBUG_API_GUIDE.md @@ -0,0 +1,462 @@ +# Simple Debug API - Guía para LLM + +## Propósito + +Esta API permite debuggear la **Calculadora MAV CAS** sin modificar código fuente ni crear scripts adicionales. + +**Principio**: **texto → texto** tal como se muestra en la aplicación. +**NO duplica lógica**, solo encapsula llamadas directas al motor existente. + +Como LLM, puedes usar esta herramienta para: + +- **Diagnosticar problemas** en el motor de evaluación +- **Verificar comportamiento** de tipos personalizados (FourBytes, IntBase, IP4Mask, etc.) +- **Inspeccionar el estado interno** del motor (variables, contexto, tipos registrados) +- **Testing de regresión** para verificar que cambios no rompan funcionalidad existente + +## Flujo de Trabajo Recomendado + +### 1. Crear archivo JSON con queries +### 2. Ejecutar: `python simple_debug.py archivo.json` +### 3. Analizar resultados en el archivo `*_results.json` + +--- + +## Tipos de Query + +### Query tipo `input` +Evalúa expresiones como si el usuario las escribiera en la calculadora. +**Resultado**: texto tal como se muestra en la aplicación. + +```json +{"index": 0, "type": "input", "content": "10.1.1.1 + 1"} +``` + +### Query tipo `exec` +Ejecuta código Python para inspeccionar el estado interno del motor. +**Resultado**: valor directo de la evaluación Python. + +```json +{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"} +``` + +--- + +## Plantilla Base + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "EXPRESION_A_EVALUAR"}, + {"index": 1, "type": "exec", "content": "CODIGO_PYTHON_INSPECCION"} + ] +} +``` + +--- + +## Casos de Uso Comunes + +### Debugging de Tipos Personalizados + +**Problema**: Verificar si FourBytes maneja correctamente operaciones IP. + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "192.168.1.1 + 1"}, + {"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"}, + {"index": 2, "type": "exec", "content": "engine.last_result.original"}, + {"index": 3, "type": "exec", "content": "engine.last_result._numeric_value"}, + {"index": 4, "type": "input", "content": "10.0.0.0/8 + 256"}, + {"index": 5, "type": "exec", "content": "engine.last_result.has_symbols"} + ] +} +``` + +### Debugging de Tokenización + +**Problema**: La expresión `192.168.1.x + 16#FF` no se tokeniza correctamente. + +```json +{ + "queries": [ + {"index": 0, "type": "exec", "content": "engine.parser.process_expression('192.168.1.x + 16#FF')"}, + {"index": 1, "type": "input", "content": "192.168.1.x + 16#FF"}, + {"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()"}, + {"index": 3, "type": "exec", "content": "len(engine.parser.tokenizer.tokenization_rules)"} + ] +} +``` + +### Debugging de Errores + +**Problema**: IP4Mask rechaza máscaras que deberían ser válidas. + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "mask = 255.240.0.0"}, + {"index": 1, "type": "input", "content": "IP4Mask(mask)"}, + {"index": 2, "type": "exec", "content": "engine.last_result"}, + {"index": 3, "type": "input", "content": "IP4Mask(255.240.0.3)"}, + {"index": 4, "type": "exec", "content": "engine.last_result"} + ] +} +``` + +### Debugging de Estado del Motor + +**Problema**: Las variables no se están guardando correctamente. + +```json +{ + "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.symbol_table)"}, + {"index": 4, "type": "exec", "content": "list(engine.symbol_table.keys())"}, + {"index": 5, "type": "input", "content": "solve(z**2 + x, z)"}, + {"index": 6, "type": "exec", "content": "len(engine.equations)"} + ] +} +``` + +--- + +## Interpretación de Resultados + +### Estructura del Resultado + +```json +{ + "execution_info": { + "timestamp": "2025-06-05T18:25:22.256442Z", + "total_queries": 5, + "successful": 4, + "failed": 1 + }, + "results": [...] +} +``` + +### Resultado Individual (Query `input`) + +```json +{ + "index": 0, + "input": "10.1.1.1 + 1", + "output": "10.1.1.2", // Texto tal como se muestra en la app + "result_type": "FourBytes", // Tipo del objeto resultado + "success": true, + "error": null +} +``` + +### Resultado Individual (Query `exec`) + +```json +{ + "index": 1, + "input": "type(engine.last_result).__name__", + "output": "FourBytes", // String del resultado + "result_type": "str", // Tipo del resultado de la evaluación + "success": true, + "error": null, + "exec_result": "FourBytes" // Valor directo (serializado si es necesario) +} +``` + +### Resultado con Error + +```json +{ + "index": 2, + "input": "IP4Mask(255.240.0.3)", + "output": "None", + "result_type": "NoneType", + "success": false, + "error": "❌ Máscara inválida: 255.240.0.3..." +} +``` + +--- + +## Funciones de Inspección Útiles + +### Estado del Motor + +```python +"engine.symbol_table" # Variables actuales +"engine.last_result" # Último resultado +"engine.symbolic_mode" # ¿Modo simbólico activo? +"len(engine.equations)" # Cantidad de ecuaciones en el sistema +"engine.debug" # ¿Debug habilitado? +"list(engine.base_context.keys())[:10]" # Funciones disponibles (muestra 10) +``` + +### Información de Tipos + +```python +"engine.get_available_types()" # Info completa de tipos registrados +"list(engine.registered_types_info['registered_classes'].keys())" # Lista de tipos +"engine.registered_types_info['class_count']" # Cantidad de tipos registrados +"type(engine.last_result).__name__" # Tipo del último resultado +"hasattr(engine.last_result, 'has_symbols')" # ¿El resultado tiene símbolos? +``` + +### Tokenización y Parsing + +```python +"engine.parser.get_tokenization_info()" # Info completa de tokenización +"engine.parser.process_expression('test')" # Procesar expresión específica +"len(engine.parser.tokenizer.tokenization_rules)" # Cantidad de reglas +"engine._classify_line('x = 5')" # Clasificar tipo de línea +"engine._extract_variable_names('x + y')" # Extraer nombres de variables +``` + +### Análisis de Objetos Específicos + +```python +# Para FourBytes +"engine.last_result.original" # String original +"engine.last_result._numeric_value" # Valor numérico interno +"engine.last_result.has_symbols" # ¿Tiene símbolos? + +# Para IntBase +"engine.last_result.base" # Base numérica (10, 16, 8, 2) +"engine.last_result.value_str" # String del valor +"engine.last_result._symbols" # Símbolos detectados + +# Para IP4Mask +"engine.last_result.get_prefix_int()" # Prefijo como entero +"engine.last_result.is_valid()" # ¿Es máscara válida? +``` + +--- + +## Patrones de Debugging + +### 1. Debugging de Regresión + +**Cuándo usar**: Verificar que cambios no rompan funcionalidad existente. + +```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 + 10"}, + {"index": 3, "type": "exec", "content": "engine.last_result.base"}, + {"index": 4, "type": "input", "content": "IP4Mask(255.255.0.0)"}, + {"index": 5, "type": "exec", "content": "engine.last_result.get_prefix_int()"} + ] +} +``` + +### 2. Debugging de Nuevas Funcionalidades + +**Cuándo usar**: Verificar que nueva funcionalidad trabaja correctamente. + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "NUEVA_FUNCIONALIDAD_AQUI"}, + {"index": 1, "type": "exec", "content": "type(engine.last_result)"}, + {"index": 2, "type": "exec", "content": "dir(engine.last_result)"}, + {"index": 3, "type": "exec", "content": "str(engine.last_result)"}, + {"index": 4, "type": "exec", "content": "engine.symbol_table"} + ] +} +``` + +### 3. Debugging de Performance + +**Cuándo usar**: Identificar operaciones lentas o problemáticas. + +```json +{ + "queries": [ + {"index": 0, "type": "exec", "content": "import time; start = time.time()"}, + {"index": 1, "type": "input", "content": "OPERACION_LENTA"}, + {"index": 2, "type": "exec", "content": "time.time() - start"}, + {"index": 3, "type": "exec", "content": "len(engine.symbol_table)"} + ] +} +``` + +### 4. Debugging de Comportamiento + +**Cuándo usar**: Verificar comportamiento específico de tipos o funciones. + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "EXPRESION"}, + {"index": 1, "type": "exec", "content": "str(engine.last_result)"}, + {"index": 2, "type": "exec", "content": "repr(engine.last_result)"}, + {"index": 3, "type": "exec", "content": "type(engine.last_result).__name__"} + ] +} +``` + +--- + +## Comandos de Ejecución + +```bash +# Ejecución básica +python simple_debug.py mi_debug.json + +# Con archivo de salida específico +python simple_debug.py mi_debug.json --output resultados.json + +# Modo verboso (para ver progreso) +python simple_debug.py mi_debug.json --verbose +``` + +--- + +## Templates Existentes para Reutilizar + +### Casos Básicos +**Archivo**: `debug_templates/basic_test.json` +- Operaciones con FourBytes e IntBase +- Variables y SymPy básico + +### Testing de Errores +**Archivo**: `debug_templates/error_debug.json` +- Máscaras inválidas +- IPs fuera de rango +- Expresiones malformadas + +### Información de Contexto +**Archivo**: `debug_templates/context_debug.json` +- Estado completo del motor +- Tipos registrados +- Sistema de ecuaciones + +### Tokenización +**Archivo**: `debug_templates/tokenization_test.json` +- Debug del sistema de parsing +- Reglas de tokenización + +--- + +## Flujo de Resolución de Problemas + +### 1. Identificar el Problema +- ¿Es un error de evaluación? +- ¿Es un problema de tokenización? +- ¿Es un problema de estado del motor? + +### 2. Crear Query de Diagnóstico +- Usar query `input` para reproducir el problema +- Usar query `exec` para inspeccionar el estado + +### 3. Analizar Resultados +- Verificar `success: true/false` +- Examinar `error` si hay fallo +- Comparar `output` (texto de la app) con `exec_result` (valor interno) + +### 4. Iterar +- Crear nuevas queries basadas en hallazgos +- Profundizar en áreas problemáticas +- Verificar soluciones con queries adicionales + +--- + +## Ejemplo Completo de Debugging + +**Problema**: "La operación `192.168.1.x + 1` no funciona correctamente" + +### Paso 1: Crear archivo de debug + +```json +{ + "queries": [ + {"index": 0, "type": "input", "content": "192.168.1.x + 1"}, + {"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"}, + {"index": 2, "type": "exec", "content": "engine.last_result.has_symbols"}, + {"index": 3, "type": "exec", "content": "engine.parser.process_expression('192.168.1.x + 1')"}, + {"index": 4, "type": "input", "content": "ip = 192.168.1.x"}, + {"index": 5, "type": "exec", "content": "type(engine.symbol_table['ip'])"}, + {"index": 6, "type": "input", "content": "ip.substitute(x=5)"} + ] +} +``` + +### Paso 2: Ejecutar +```bash +python simple_debug.py debug_problema.json +``` + +### Paso 3: Analizar resultados +- Verificar si `192.168.1.x + 1` se evalúa correctamente (campo `output`) +- Comprobar el tipo resultante con `exec` +- Verificar si tiene símbolos +- Examinar cómo se tokeniza la expresión +- Probar operaciones relacionadas + +Este flujo te permite identificar exactamente dónde está el problema y verificar la solución. + +--- + +## Consejos para LLMs + +1. **Siempre usa índices secuenciales** en las queries para facilitar la lectura +2. **Combina queries `input` y `exec`** para obtener contexto completo +3. **El campo `output` es texto tal como se muestra en la aplicación** +4. **El campo `exec_result` es el valor directo de la evaluación Python** +5. **Usa los templates existentes** como punto de partida +6. **Examina `success` y `error`** antes de analizar resultados +7. **Crea queries incrementales** que construyan sobre resultados anteriores +8. **NO intentes duplicar lógica de la aplicación** - usa solo llamadas directas + +--- + +## Referencia Rápida + +### Query Básica +```json +{"index": N, "type": "input|exec", "content": "CONTENIDO"} +``` + +### Comandos Esenciales +```bash +python simple_debug.py archivo.json # Ejecutar debug +python simple_debug.py archivo.json --verbose # Con detalles +python simple_debug.py archivo.json -o resultado.json # Salida específica +``` + +### Inspección Básica del Motor +```python +"engine.last_result" # Último resultado +"type(engine.last_result)" # Tipo del resultado +"engine.symbol_table" # Variables actuales +"engine.get_available_types()" # Tipos registrados +"engine.parser.get_tokenization_info()" # Info de parsing +``` + +### Análisis de Resultado +```python +"success": true/false # ¿Éxito? +"error": "mensaje" # Error si falla +"output": "resultado" # Texto tal como se muestra en la app +"exec_result": valor # Valor directo (exec queries) +``` + +### Templates Disponibles +- `debug_templates/basic_test.json` - Pruebas básicas +- `debug_templates/error_debug.json` - Testing de errores +- `debug_templates/context_debug.json` - Estado del motor +- `debug_templates/tokenization_test.json` - Debug de parsing + +### Workflow Típico +1. **Identificar problema** → Crear query `input` para reproducir +2. **Inspeccionar estado** → Añadir queries `exec` para diagnosticar +3. **Analizar resultados** → Examinar `success`, `error`, `output` +4. **Iterar** → Crear nuevas queries basadas en hallazgos + +**Principio clave**: texto → texto. La API no interpreta ni procesa, solo encapsula llamadas directas al motor existente. \ No newline at end of file diff --git a/basic_test_results.json b/basic_test_results.json index a4a4ef5..f846a88 100644 --- a/basic_test_results.json +++ b/basic_test_results.json @@ -1,6 +1,6 @@ { "execution_info": { - "timestamp": "2025-06-05T18:10:43.323812Z", + "timestamp": "2025-06-05T18:25:22.256442Z", "total_queries": 8, "successful": 8, "failed": 0, @@ -13,73 +13,7 @@ "output": "10.1.1.2", "result_type": "FourBytes", "success": true, - "error": null, - "output_raw": { - "parts": [ - [ - "custom_type", - "10.1.1.2" - ], - [ - "class_hint", - "[FourBytes]" - ] - ], - "formatted_text": "[custom_type]10.1.1.2[class_hint][FourBytes]", - "tag_info": { - "error": { - "fg": "#ff6b6b", - "font": "bold" - }, - "result": { - "fg": "#abdbe3" - }, - "symbolic": { - "fg": "#82aaff" - }, - "numeric": { - "fg": "#c3e88d" - }, - "equation": { - "fg": "#c792ea" - }, - "info": { - "fg": "#ffcb6b" - }, - "comment": { - "fg": "#546e7a" - }, - "class_hint": { - "fg": "#888888" - }, - "type_hint": { - "fg": "#6a6a6a" - }, - "custom_type": { - "fg": "#f9a825" - }, - "hex": { - "fg": "#f9a825" - }, - "bin": { - "fg": "#4fc3f7" - }, - "ip": { - "fg": "#fff176" - }, - "date": { - "fg": "#ff8a80" - }, - "chr_type": { - "fg": "#80cbc4" - }, - "helper": { - "fg": "#ffd700", - "font": "italic" - } - } - }, - "display_class": "[FourBytes]" + "error": null }, { "index": 1, @@ -96,73 +30,7 @@ "output": "16#FF", "result_type": "IntBase", "success": true, - "error": null, - "output_raw": { - "parts": [ - [ - "custom_type", - "16#FF" - ], - [ - "class_hint", - "[IntBase]" - ] - ], - "formatted_text": "[custom_type]16#FF[class_hint][IntBase]", - "tag_info": { - "error": { - "fg": "#ff6b6b", - "font": "bold" - }, - "result": { - "fg": "#abdbe3" - }, - "symbolic": { - "fg": "#82aaff" - }, - "numeric": { - "fg": "#c3e88d" - }, - "equation": { - "fg": "#c792ea" - }, - "info": { - "fg": "#ffcb6b" - }, - "comment": { - "fg": "#546e7a" - }, - "class_hint": { - "fg": "#888888" - }, - "type_hint": { - "fg": "#6a6a6a" - }, - "custom_type": { - "fg": "#f9a825" - }, - "hex": { - "fg": "#f9a825" - }, - "bin": { - "fg": "#4fc3f7" - }, - "ip": { - "fg": "#fff176" - }, - "date": { - "fg": "#ff8a80" - }, - "chr_type": { - "fg": "#80cbc4" - }, - "helper": { - "fg": "#ffd700", - "font": "italic" - } - } - }, - "display_class": "[IntBase]" + "error": null }, { "index": 3, @@ -179,69 +47,7 @@ "output": "255.255.0.0", "result_type": "FourBytes", "success": true, - "error": null, - "output_raw": { - "parts": [ - [ - "info", - "mask = 255.255.0.0" - ] - ], - "formatted_text": "[info]mask = 255.255.0.0", - "tag_info": { - "error": { - "fg": "#ff6b6b", - "font": "bold" - }, - "result": { - "fg": "#abdbe3" - }, - "symbolic": { - "fg": "#82aaff" - }, - "numeric": { - "fg": "#c3e88d" - }, - "equation": { - "fg": "#c792ea" - }, - "info": { - "fg": "#ffcb6b" - }, - "comment": { - "fg": "#546e7a" - }, - "class_hint": { - "fg": "#888888" - }, - "type_hint": { - "fg": "#6a6a6a" - }, - "custom_type": { - "fg": "#f9a825" - }, - "hex": { - "fg": "#f9a825" - }, - "bin": { - "fg": "#4fc3f7" - }, - "ip": { - "fg": "#fff176" - }, - "date": { - "fg": "#ff8a80" - }, - "chr_type": { - "fg": "#80cbc4" - }, - "helper": { - "fg": "#ffd700", - "font": "italic" - } - } - }, - "display_class": "[FourBytes]" + "error": null }, { "index": 5, @@ -250,7 +56,9 @@ "result_type": "dict", "success": true, "error": null, - "exec_result": "{'mask': FourBytes('255.255.0.0')}" + "exec_result": { + "mask": "255.255.0.0" + } }, { "index": 6, @@ -258,73 +66,7 @@ "output": "[-I, I]", "result_type": "list", "success": true, - "error": null, - "output_raw": { - "parts": [ - [ - "result", - "[-I, I]" - ], - [ - "class_hint", - "[List]" - ] - ], - "formatted_text": "[result][-I, I][class_hint][List]", - "tag_info": { - "error": { - "fg": "#ff6b6b", - "font": "bold" - }, - "result": { - "fg": "#abdbe3" - }, - "symbolic": { - "fg": "#82aaff" - }, - "numeric": { - "fg": "#c3e88d" - }, - "equation": { - "fg": "#c792ea" - }, - "info": { - "fg": "#ffcb6b" - }, - "comment": { - "fg": "#546e7a" - }, - "class_hint": { - "fg": "#888888" - }, - "type_hint": { - "fg": "#6a6a6a" - }, - "custom_type": { - "fg": "#f9a825" - }, - "hex": { - "fg": "#f9a825" - }, - "bin": { - "fg": "#4fc3f7" - }, - "ip": { - "fg": "#fff176" - }, - "date": { - "fg": "#ff8a80" - }, - "chr_type": { - "fg": "#80cbc4" - }, - "helper": { - "fg": "#ffd700", - "font": "italic" - } - } - }, - "display_class": "[list]" + "error": null }, { "index": 7, diff --git a/debug_templates/README.md b/debug_templates/README.md index d5cf475..04422ea 100644 --- a/debug_templates/README.md +++ b/debug_templates/README.md @@ -52,10 +52,10 @@ python simple_debug.py debug_templates/basic_test.json --verbose - Sistema de ecuaciones ### `display_format_test.json` -**Propósito**: Demostración de formatos de display y output_raw +**Propósito**: Demostración de diferentes tipos de resultados - Diferentes tipos de resultados (IP, hex, símbolos, matrices) - Comentarios y errores -- Comparación entre `output` y `output_raw` +- Verificación del comportamiento de la aplicación ## Formato de Template @@ -142,47 +142,36 @@ Cada template es un archivo JSON con esta estructura: "output": "10.1.1.2", "result_type": "FourBytes", "success": true, + "error": null +} +``` + +### Resultado Individual para Query `exec` + +```json +{ + "index": 1, + "input": "type(engine.last_result).__name__", + "output": "FourBytes", + "result_type": "str", + "success": true, "error": null, - "display_class": "[FourBytes]", - "output_raw": { - "parts": [ - ["custom_type", "10.1.1.2"], - ["class_hint", "[FourBytes]"] - ], - "formatted_text": "[custom_type]10.1.1.2[class_hint][FourBytes]", - "tag_info": { - "custom_type": {"fg": "#f9a825"}, - "class_hint": {"fg": "#888888"} - } - } + "exec_result": "FourBytes" } ``` ### Campos del Resultado -- **`output`**: Resultado básico (antes del post-procesamiento) -- **`output_raw`**: Resultado exacto como se muestra en la aplicación - - **`parts`**: Lista de tuplas `[tag, contenido]` con información de color/formato - - **`formatted_text`**: Texto formateado como se vería en la aplicación - - **`tag_info`**: Información de colores y estilos para cada tag +- **`output`**: Texto tal como se muestra en la aplicación (queries `input`) +- **`exec_result`**: Valor directo de la evaluación Python (queries `exec`) - **`result_type`**: Tipo del objeto resultado -- **`display_class`**: Nombre de clase para mostrar - -### Tags de Color Disponibles - -- **`error`**: `#ff6b6b` (rojo) - Errores -- **`result`**: `#abdbe3` (azul claro) - Resultados generales -- **`symbolic`**: `#82aaff` (azul) - Expresiones simbólicas -- **`numeric`**: `#c3e88d` (verde) - Aproximaciones numéricas -- **`custom_type`**: `#f9a825` (naranja) - Tipos personalizados -- **`ip`**: `#fff176` (amarillo) - Direcciones IP -- **`hex`**: `#f9a825` (naranja) - Números hexadecimales -- **`class_hint`**: `#888888` (gris) - Pistas de clase +- **`success`**: `true` si la evaluación fue exitosa +- **`error`**: Mensaje de error si `success` es `false` ## Tips - Usa `index` secuencial para facilitar la lectura de resultados - Combina queries `input` y `exec` para verificar comportamiento y estado - El archivo de resultados contiene información detallada de éxito/error -- **Usa `output_raw` para entender exactamente cómo se mostraría el resultado en la aplicación** +- **Usa `output` para ver exactamente el texto que muestra la aplicación** - Puedes copiar y modificar templates existentes para casos específicos \ No newline at end of file diff --git a/error_debug_results.json b/error_debug_results.json index 15fa665..6f6e4a7 100644 --- a/error_debug_results.json +++ b/error_debug_results.json @@ -1,6 +1,6 @@ { "execution_info": { - "timestamp": "2025-06-05T18:01:38.085095Z", + "timestamp": "2025-06-05T18:27:08.607608Z", "total_queries": 11, "successful": 9, "failed": 2, @@ -13,8 +13,7 @@ "output": "255.240.0.3", "result_type": "FourBytes", "success": true, - "error": null, - "display_class": "[FourBytes]" + "error": null }, { "index": 1, @@ -22,8 +21,7 @@ "output": "None", "result_type": "NoneType", "success": false, - "error": "\n❌ Máscara inválida: 255.240.0.3 (0xFFF00003)\n\n🔍 Análisis binario: 11111111.11110000.00000000.00000011\n Los bits deben ser contiguos: todos los 1s seguidos de todos los 0s\n\n✅ Ejemplos de máscaras válidas:\n /24 → 255.255.255.0 (11111111.11111111.11111111.00000000)\n /20 → 255.240.0.0 (11111111.11110000.00000000.00000000)\n /16 → 255.255.0.0 (11111111.11111111.00000000.00000000)\n /12 → 255.240.0.0 (11111111.11110000.00000000.00000000)\n\n💡 ¿Quizás querías usar 255.240.0.0 en lugar de 255.240.0.3?\n", - "display_class": "[NoneType]" + "error": "\n❌ Máscara inválida: 255.240.0.3 (0xFFF00003)\n\n🔍 Análisis binario: 11111111.11110000.00000000.00000011\n Los bits deben ser contiguos: todos los 1s seguidos de todos los 0s\n\n✅ Ejemplos de máscaras válidas:\n /24 → 255.255.255.0 (11111111.11111111.11111111.00000000)\n /20 → 255.240.0.0 (11111111.11110000.00000000.00000000)\n /16 → 255.255.0.0 (11111111.11111111.00000000.00000000)\n /12 → 255.240.0.0 (11111111.11110000.00000000.00000000)\n\n💡 ¿Quizás querías usar 255.240.0.0 en lugar de 255.240.0.3?\n" }, { "index": 2, @@ -40,8 +38,7 @@ "output": "None", "result_type": "NoneType", "success": false, - "error": "Error en asignación: Elemento inválido: '300'", - "display_class": "[NoneType]" + "error": "Error en asignación: Elemento inválido: '300'" }, { "index": 4, @@ -58,8 +55,7 @@ "output": "16", "result_type": "Integer", "success": true, - "error": null, - "display_class": "[Integer]" + "error": null }, { "index": 6, @@ -76,8 +72,7 @@ "output": "zoo", "result_type": "ComplexInfinity", "success": true, - "error": null, - "display_class": "[ComplexInfinity]" + "error": null }, { "index": 8, @@ -94,8 +89,7 @@ "output": "undefined_var + 5", "result_type": "Add", "success": true, - "error": null, - "display_class": "[Add]" + "error": null }, { "index": 10, diff --git a/simple_debug.py b/simple_debug.py index edd5569..a986a20 100644 --- a/simple_debug.py +++ b/simple_debug.py @@ -6,6 +6,9 @@ API CLI simple que usa el motor de evaluación existente para generar debug trac 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 @@ -20,238 +23,6 @@ from pathlib import Path # Importar el motor de evaluación existente from main_evaluation import HybridEvaluationEngine -import sympy - - -def _process_evaluation_result_for_debug(result, engine): - """ - Procesa el resultado de evaluación tal como lo haría la aplicación - Retorna información de formato, colores y contenido exacto - """ - output_parts = [] - - if result.is_error: - # Intentar obtener ayuda como lo hace la app - ayuda = _obtener_ayuda_simulada(result.original_line, engine) - if ayuda: - ayuda_linea = ayuda.replace("\n", " ").replace("\r", " ") - if len(ayuda_linea) > 120: - ayuda_linea = ayuda_linea[:117] + "..." - output_parts.append(("helper", ayuda_linea)) - else: - output_parts.append(("error", f"Error: {result.error}")) - elif result.result_type == "comment": - output_parts.append(("comment", result.original_line)) - elif result.result_type == "equation_added": - output_parts.append(("equation", result.symbolic_result)) - elif result.result_type == "assignment": - output_parts.append(("info", result.symbolic_result)) - # Mostrar evaluación numérica para asignaciones si existe - if result.numeric_result is not None and result.numeric_result != result.result: - output_parts.append(("numeric", f"≈ {result.numeric_result}")) - else: - # Resultado normal - if result.result is not None: - # Determinar tag basado en tipo (simulando lógica dinámica) - tag = _get_result_tag_dynamic_debug(result.result, engine) - - # Verificar si es resultado interactivo (simulado) - if _is_interactive_result(result.result): - interactive_tag, display_text = _create_interactive_tag_debug(result.result) - if interactive_tag: - output_parts.append((interactive_tag, display_text)) - else: - output_parts.append((tag, str(result.result))) - else: - output_parts.append((tag, str(result.result))) - - # Añadir pista de clase para el resultado principal - class_display_name = _get_class_display_name_dynamic_debug(result.result, engine) - if class_display_name: - output_parts.append(("class_hint", f"[{class_display_name}]")) - - # Mostrar evaluación numérica si existe - if result.numeric_result is not None and result.numeric_result != result.result: - output_parts.append(("numeric", f"≈ {result.numeric_result}")) - - # Mostrar información adicional - if result.info: - output_parts.append(("info", f"({result.info})")) - - # Convertir partes a string formateado como la app - formatted_output = _format_output_parts_debug(output_parts) - - return { - 'parts': output_parts, - 'formatted_text': formatted_output, - 'tag_info': _get_tag_color_info() - } - - -def _obtener_ayuda_simulada(input_str, engine): - """Simula la obtención de ayuda como lo hace la app""" - try: - # Intentar usar los helpers del engine si están disponibles - if hasattr(engine, 'HELPERS'): - for helper in engine.HELPERS: - try: - ayuda = helper(input_str) - if ayuda: - return ayuda - except: - continue - except: - pass - return None - - -def _get_result_tag_dynamic_debug(result, engine): - """Simula _get_result_tag_dynamic de la app""" - try: - registered_classes = engine.get_available_types().get('registered_classes', {}) - - # Verificar si es una instancia de alguna clase registrada - for name, cls in registered_classes.items(): - if isinstance(result, cls): - name_lower = name.lower() - if name_lower == "hex": - return "hex" - elif name_lower == "bin": - return "bin" - elif name_lower in ["ip4", "ip"]: - return "ip" - elif name_lower == "chr": - return "chr_type" - elif name_lower == "date": - return "date" - else: - return "custom_type" - - except Exception: - pass - - # Fallback a tags existentes para tipos no registrados - if isinstance(result, sympy.Basic): - return "symbolic" - else: - return "result" - - -def _get_class_display_name_dynamic_debug(obj, engine): - """Simula _get_class_display_name_dynamic de la app""" - try: - # Verificar si es una clase registrada dinámicamente - registered_classes = engine.get_available_types().get('registered_classes', {}) - - for name, cls in registered_classes.items(): - if isinstance(obj, cls): - return name - - except Exception: - pass - - # Fallback a lógica existente para tipos nativos - if isinstance(obj, sympy.logic.boolalg.BooleanAtom): - return "Boolean" - elif isinstance(obj, sympy.Basic): - if hasattr(obj, 'is_number') and obj.is_number: - if hasattr(obj, 'is_Integer') and obj.is_Integer: - return "Integer" - elif hasattr(obj, 'is_Rational') and obj.is_Rational and not obj.is_Integer: - return "Rational" - elif hasattr(obj, 'is_Float') and obj.is_Float: - return "Float" - else: - return "SympyNumber" - else: - return "Sympy" - elif isinstance(obj, bool): - return "Boolean" - elif isinstance(obj, (int, float, str, list, dict, tuple, type(None))): - class_display_name = type(obj).__name__.capitalize() - if class_display_name == "Nonetype": - class_display_name = "None" - return class_display_name - - return "" - - -def _is_interactive_result(result): - """Simula la lógica is_interactive de EvaluationResult""" - try: - # Intentar importar PlotResult si existe - from tl_popup import PlotResult - if isinstance(result, PlotResult): - return True - except ImportError: - pass - - return isinstance(result, sympy.Matrix) or \ - (isinstance(result, list) and len(result) > 3) - - -def _create_interactive_tag_debug(result): - """Simula la creación de tags interactivos""" - try: - from tl_popup import PlotResult - if isinstance(result, PlotResult): - return f"plot_{id(result)}", f"📊 Ver {result.plot_type.title()}" - except ImportError: - pass - - if isinstance(result, sympy.Matrix): - rows, cols = result.shape - return f"matrix_{id(result)}", f"📋 Ver Matriz {rows}×{cols}" - elif isinstance(result, list) and len(result) > 5: - return f"list_{id(result)}", f"📋 Ver Lista ({len(result)} elementos)" - elif isinstance(result, dict) and len(result) > 3: - return f"dict_{id(result)}", f"🔍 Ver Diccionario ({len(result)} entradas)" - - return None, None - - -def _format_output_parts_debug(output_parts): - """Simula cómo _display_output formatea las partes para mostrar""" - formatted_lines = [] - - for part_idx, (tag, content) in enumerate(output_parts): - if not content: - continue - - prefix = "" - if part_idx > 0: - prev_tag, prev_content = output_parts[part_idx-1] if part_idx > 0 else (None, None) - - if tag not in ["class_hint", "numeric", "info"] and prev_content: - prefix = " ; " - elif tag in ["numeric", "info"] and prev_content: - prefix = " " - - formatted_lines.append(f"{prefix}[{tag}]{content}") - - return "".join(formatted_lines) - - -def _get_tag_color_info(): - """Información sobre los colores de los tags como en setup_output_tags""" - return { - "error": {"fg": "#ff6b6b", "font": "bold"}, - "result": {"fg": "#abdbe3"}, - "symbolic": {"fg": "#82aaff"}, - "numeric": {"fg": "#c3e88d"}, - "equation": {"fg": "#c792ea"}, - "info": {"fg": "#ffcb6b"}, - "comment": {"fg": "#546e7a"}, - "class_hint": {"fg": "#888888"}, - "type_hint": {"fg": "#6a6a6a"}, - "custom_type": {"fg": "#f9a825"}, - "hex": {"fg": "#f9a825"}, - "bin": {"fg": "#4fc3f7"}, - "ip": {"fg": "#fff176"}, - "date": {"fg": "#ff8a80"}, - "chr_type": {"fg": "#80cbc4"}, - "helper": {"fg": "#ffd700", "font": "italic"} - } def run_debug(input_file: str, output_file: str = None, verbose: bool = False): @@ -298,6 +69,7 @@ def run_debug(input_file: str, output_file: str = None, verbose: bool = False): # 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'], @@ -307,17 +79,6 @@ def run_debug(input_file: str, output_file: str = None, verbose: bool = False): 'error': result.error if hasattr(result, 'is_error') and result.is_error else None } - # Generar output_raw: resultado exacto como se muestra en la aplicación - try: - output_raw_data = _process_evaluation_result_for_debug(result, engine) - output['output_raw'] = output_raw_data - except Exception as e: - output['output_raw'] = f"Error generando output_raw: {e}" - - # Añadir información adicional si está disponible - if hasattr(result, 'result') and hasattr(result.result, '__class__'): - output['display_class'] = f"[{result.result.__class__.__name__}]" - if not (hasattr(result, 'is_error') and result.is_error): successful += 1 else: @@ -377,22 +138,7 @@ def run_debug(input_file: str, output_file: str = None, verbose: bool = False): # Guardar resultados try: - # Usar un encoder personalizado para objetos no serializables - def json_serializer(obj): - """Serializar objetos no estándar a string""" - try: - # Intentar conversión normal primero - json.dumps(obj) - return obj - except TypeError: - # Si no es serializable, convertir a string - return str(obj) - - # Aplicar serialización personalizada a exec_result - for result in final_output['results']: - if 'exec_result' in result: - result['exec_result'] = json_serializer(result['exec_result']) - + # 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)