feat: enhance jupyter notebook functions with auto-init and kernel management
Auto-create notebooks y sesiones en jupyter_exec (append y cell). Auto-create en jupyter_write (append_code, append_markdown, batch). Nuevos subcomandos cleanup y shutdown-all en jupyter_kernel. README.md renombrado a README.txt para evitar error de parseo del indexer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
# Jupyter Notebook Tools
|
||||
|
||||
Cinco funciones Python para operar notebooks Jupyter programaticamente via API REST y WebSocket colaborativo (CRDT/Y.js). Reemplazan al MCP jupyter y funcionan desde cualquier directorio.
|
||||
|
||||
## Flujo tipico
|
||||
|
||||
```
|
||||
discover → read → write/exec
|
||||
```
|
||||
|
||||
1. **Descubrir** que Jupyter esta corriendo y en que puerto
|
||||
2. **Leer** celdas del notebook (estado en memoria, no disco)
|
||||
3. **Escribir** celdas nuevas o **ejecutar** codigo
|
||||
|
||||
```bash
|
||||
PYTHON="python/.venv/bin/python3"
|
||||
|
||||
# 1. Descubrir instancias activas
|
||||
$PYTHON python/functions/notebook/jupyter_discover.py --json
|
||||
|
||||
# 2. Leer notebook
|
||||
$PYTHON python/functions/notebook/jupyter_read.py notebooks/01.ipynb --json
|
||||
|
||||
# 3. Crear notebook nuevo (si no existe)
|
||||
$PYTHON python/functions/notebook/jupyter_write.py create notebooks/02.ipynb
|
||||
|
||||
# 4. Escribir celdas en batch
|
||||
$PYTHON python/functions/notebook/jupyter_write.py batch notebooks/02.ipynb --from cells.json
|
||||
|
||||
# 5. Ejecutar celda
|
||||
$PYTHON python/functions/notebook/jupyter_exec.py cell notebooks/02.ipynb 0
|
||||
```
|
||||
|
||||
## Funciones
|
||||
|
||||
### jupyter_discover
|
||||
|
||||
Descubre instancias de Jupyter Lab activas. Escanea `.jupyter-port` en `analysis/` y puertos 8888-8892. Detecta el `root_dir` real parseando `/proc/{pid}/cmdline`.
|
||||
|
||||
| Subcomando | Descripcion |
|
||||
|---|---|
|
||||
| *(sin subcomando)* | Lista instancias con puerto, analysis, root_dir, kernels, sesiones |
|
||||
|
||||
```bash
|
||||
$PYTHON jupyter_discover.py --json
|
||||
$PYTHON jupyter_discover.py --port 8888 --port 8889
|
||||
```
|
||||
|
||||
Retorna por instancia: `url`, `port`, `analysis`, `root_dir`, `collaborative`, `kernels`, `sessions`.
|
||||
|
||||
### jupyter_read
|
||||
|
||||
Lee celdas de un notebook via protocolo CRDT (estado en memoria, incluye cambios no guardados).
|
||||
|
||||
| Subcomando | Descripcion |
|
||||
|---|---|
|
||||
| *(sin subcomando)* | Lee todas las celdas (formato legible) |
|
||||
| `--cell N` | Lee solo la celda N |
|
||||
| `--info` | Solo metadata (total celdas, conteo por tipo) |
|
||||
| `--json` | Salida JSON |
|
||||
|
||||
```bash
|
||||
$PYTHON jupyter_read.py notebooks/01.ipynb --json
|
||||
$PYTHON jupyter_read.py notebooks/01.ipynb --cell 3
|
||||
$PYTHON jupyter_read.py notebooks/01.ipynb --info
|
||||
```
|
||||
|
||||
### jupyter_write
|
||||
|
||||
Operaciones de escritura sobre celdas via WebSocket colaborativo. NO ejecuta celdas.
|
||||
|
||||
| Subcomando | Descripcion |
|
||||
|---|---|
|
||||
| `create` | Crea un notebook .ipynb nuevo (API REST PUT) |
|
||||
| `append-code` | Anade celda de codigo al final |
|
||||
| `append-markdown` | Anade celda markdown al final |
|
||||
| `insert` | Inserta celda en posicion especifica |
|
||||
| `edit` | Sobrescribe contenido de celda existente |
|
||||
| `delete` | Elimina una celda |
|
||||
| `batch` | Escribe multiples celdas en una sola conexion WebSocket |
|
||||
|
||||
```bash
|
||||
# Crear notebook
|
||||
$PYTHON jupyter_write.py create notebooks/02.ipynb
|
||||
$PYTHON jupyter_write.py create notebooks/02.ipynb --kernel python3 --force
|
||||
|
||||
# Celdas individuales
|
||||
$PYTHON jupyter_write.py append-code notebooks/02.ipynb "import pandas as pd"
|
||||
$PYTHON jupyter_write.py append-markdown notebooks/02.ipynb "## Titulo"
|
||||
$PYTHON jupyter_write.py insert notebooks/02.ipynb 0 "x = 42" --type code
|
||||
$PYTHON jupyter_write.py edit notebooks/02.ipynb 0 "# Titulo actualizado"
|
||||
$PYTHON jupyter_write.py delete notebooks/02.ipynb 3
|
||||
|
||||
# Batch (una sola conexion para N celdas)
|
||||
$PYTHON jupyter_write.py batch notebooks/02.ipynb --from cells.json
|
||||
cat cells.json | $PYTHON jupyter_write.py batch notebooks/02.ipynb --from -
|
||||
```
|
||||
|
||||
Formato `cells.json`:
|
||||
```json
|
||||
[
|
||||
{"type": "markdown", "source": "# Titulo"},
|
||||
{"type": "code", "source": "import pandas as pd"},
|
||||
{"type": "code", "source": "df = pd.read_csv('data.csv')"}
|
||||
]
|
||||
```
|
||||
|
||||
### jupyter_exec
|
||||
|
||||
Ejecuta codigo en kernels de Jupyter via WebSocket.
|
||||
|
||||
| Subcomando | Descripcion |
|
||||
|---|---|
|
||||
| `append` | Anade celda al notebook y la ejecuta |
|
||||
| `cell` | Ejecuta celda existente por indice |
|
||||
| `kernel` | Ejecuta en el kernel sin tocar notebook |
|
||||
|
||||
```bash
|
||||
$PYTHON jupyter_exec.py append notebooks/01.ipynb "df.describe()"
|
||||
$PYTHON jupyter_exec.py cell notebooks/01.ipynb 3
|
||||
$PYTHON jupyter_exec.py kernel "print(df.shape)"
|
||||
```
|
||||
|
||||
Normaliza automaticamente celdas sin `outputs` o `execution_count` (comun en notebooks creados programaticamente).
|
||||
|
||||
### jupyter_kernel
|
||||
|
||||
CRUD de kernels Jupyter via API REST.
|
||||
|
||||
| Subcomando | Descripcion |
|
||||
|---|---|
|
||||
| `list` | Lista kernels activos |
|
||||
| `start` | Inicia kernel nuevo |
|
||||
| `restart` | Reinicia kernel |
|
||||
| `interrupt` | Interrumpe ejecucion |
|
||||
| `shutdown` | Apaga y elimina kernel |
|
||||
| `sessions` | Lista sesiones (mapeo notebook-kernel) |
|
||||
|
||||
```bash
|
||||
$PYTHON jupyter_kernel.py list
|
||||
$PYTHON jupyter_kernel.py start --name python3
|
||||
$PYTHON jupyter_kernel.py restart <kernel_id>
|
||||
$PYTHON jupyter_kernel.py shutdown <kernel_id>
|
||||
$PYTHON jupyter_kernel.py sessions
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WebSocket 4404 — notebook no existe
|
||||
|
||||
El servidor no puede abrir un documento CRDT para un archivo que no existe en disco.
|
||||
|
||||
**Solucion:** Crear el notebook primero con `jupyter_write.py create`.
|
||||
|
||||
```bash
|
||||
$PYTHON jupyter_write.py create notebooks/nuevo.ipynb
|
||||
$PYTHON jupyter_write.py append-code notebooks/nuevo.ipynb "print('hola')"
|
||||
```
|
||||
|
||||
### KeyError 'outputs' — celda sin estructura completa
|
||||
|
||||
Notebooks creados manualmente (no via Jupyter UI) pueden tener celdas de codigo sin los campos `outputs` y `execution_count` que el protocolo CRDT requiere.
|
||||
|
||||
**Solucion:** `jupyter_exec.py` normaliza automaticamente estas celdas antes de ejecutar. Si el problema persiste, recrear la celda con `jupyter_write.py edit`.
|
||||
|
||||
### "Kernel does not exist" — sesion stale
|
||||
|
||||
El kernel referenciado ya no existe (fue apagado o el servidor se reinicio).
|
||||
|
||||
**Solucion:**
|
||||
```bash
|
||||
# Ver kernels activos
|
||||
$PYTHON jupyter_kernel.py list
|
||||
# Ver sesiones (mapeo notebook-kernel)
|
||||
$PYTHON jupyter_kernel.py sessions
|
||||
# Reiniciar kernel si necesario
|
||||
$PYTHON jupyter_kernel.py restart <kernel_id>
|
||||
```
|
||||
|
||||
### "Document not yet synced" — timing de colaboracion
|
||||
|
||||
El cliente WebSocket no pudo sincronizar el documento CRDT a tiempo.
|
||||
|
||||
**Solucion:** Reintentar. Si persiste, verificar que el servidor tiene `jupyter-collaboration` activo:
|
||||
```bash
|
||||
$PYTHON jupyter_discover.py --json | python3 -c "import sys,json; [print(i['collaborative']) for i in json.load(sys.stdin)]"
|
||||
```
|
||||
|
||||
### Discover muestra analysis incorrecto
|
||||
|
||||
Versiones anteriores podian confundir instancias. La deteccion actual parsea `--ServerApp.root_dir` del cmdline del proceso via `/proc/{pid}/cmdline`.
|
||||
|
||||
**Solucion:** Actualizar a la version actual de `jupyter_discover.py`.
|
||||
|
||||
## Parametros comunes
|
||||
|
||||
Todos los subcomandos aceptan:
|
||||
|
||||
| Flag | Default | Descripcion |
|
||||
|---|---|---|
|
||||
| `--server` | `http://localhost:8888` | URL del servidor Jupyter |
|
||||
| `--token` | `""` (vacio) | Token de autenticacion |
|
||||
|
||||
Los paths de notebooks son siempre **relativos a la raiz del servidor Jupyter** (normalmente `analysis/{tema}/`).
|
||||
|
||||
## Dependencias
|
||||
|
||||
| Paquete | Usado por | Para que |
|
||||
|---|---|---|
|
||||
| `jupyter_nbmodel_client` | write, exec, read | WebSocket colaborativo (CRDT/Y.js) |
|
||||
| `jupyter_kernel_client` | exec | Ejecucion de codigo en kernels |
|
||||
| stdlib (`urllib`, `json`) | discover, kernel, write (create) | API REST |
|
||||
|
||||
## Diferencias con MCP jupyter
|
||||
|
||||
| Aspecto | MCP jupyter | Estas funciones |
|
||||
|---|---|---|
|
||||
| Requiere registro | Si (.mcp.json) | No |
|
||||
| Funciona desde cualquier dir | No (solo desde el dir del MCP) | Si |
|
||||
| Protocolo | MCP sobre stdio | HTTP REST + WebSocket directo |
|
||||
| Crear notebooks | No | Si (`write create`) |
|
||||
| Batch de celdas | No | Si (`write batch`) |
|
||||
| Multi-instancia | No | Si (discover detecta todas) |
|
||||
|
||||
## Limitaciones
|
||||
|
||||
- Requiere Jupyter Lab >= 4 con `jupyter-collaboration` para las funciones que usan WebSocket (write, exec, read)
|
||||
- Las funciones REST (discover, kernel) funcionan con cualquier Jupyter Lab 3.x/4.x y Notebook 6.x/7.x
|
||||
- La deteccion de root_dir via `/proc` solo funciona en Linux
|
||||
- No soportan autenticacion por cookie, solo por token
|
||||
- `jupyter_write batch` requiere JSON como entrada (no YAML)
|
||||
Reference in New Issue
Block a user