7913116a8e
- .claude/agents/fn-analizador/SKILL.md - .claude/agents/fn-constructor/SKILL.md - .claude/agents/fn-executor/SKILL.md - .claude/agents/fn-mejorador/SKILL.md - .claude/agents/fn-orquestador/SKILL.md - .claude/agents/fn-recopilador/SKILL.md - .claude/commands/app.md - .claude/commands/compile.md - .claude/commands/cpp-app.md - .claude/commands/create_functions.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
134 lines
5.1 KiB
Markdown
134 lines
5.1 KiB
Markdown
---
|
|
name: jupyter_discover
|
|
kind: function
|
|
lang: py
|
|
domain: notebook
|
|
version: "1.1.0"
|
|
purity: impure
|
|
signature: "def jupyter_discover(registry_root: str = \"\", ports: list[int] | None = None) -> list[dict]"
|
|
description: "Descubre instancias de Jupyter Lab activas escaneando archivos .jupyter-port en analysis/ y puertos comunes (8888-8892). Detecta el root_dir real de cada instancia via /proc/pid/cmdline (Linux) para identificar correctamente el analisis en escenarios multi-instancia. Para cada instancia consulta /api/status, /api/config, /api/kernels y /api/sessions via HTTP REST."
|
|
tags: [jupyter, notebook, discovery, api, http, kernels, sessions, analysis, multi-instance, proc, pendiente-usar]
|
|
uses_functions: []
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: [json, os, urllib.error, urllib.request, pathlib]
|
|
params:
|
|
- name: registry_root
|
|
desc: "Raíz del registry para detectar análisis (opcional, usa FN_REGISTRY_ROOT si no se proporciona)"
|
|
- name: ports
|
|
desc: "Puertos a escanear (default: 8888-8892, detecta automáticamente)"
|
|
output: "Lista de dicts con información de instancias Jupyter: url, port, analysis, root_dir, collaborative, kernels, sessions"
|
|
tested: false
|
|
tests: []
|
|
test_file_path: ""
|
|
file_path: "python/functions/notebook/jupyter_discover.py"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```python
|
|
from notebook.jupyter_discover import jupyter_discover
|
|
|
|
# Descubrir con deteccion automatica de puertos
|
|
instances = jupyter_discover(registry_root="$HOME/fn_registry")
|
|
|
|
# Escanear puertos especificos
|
|
instances = jupyter_discover(ports=[8888, 8900])
|
|
|
|
for inst in instances:
|
|
print(inst["url"], inst["analysis"], inst["root_dir"], inst["collaborative"])
|
|
# http://localhost:8888 estudio_mercados $HOME/fn_registry/analysis/estudio_mercados True
|
|
```
|
|
|
|
## Estructura del dict retornado
|
|
|
|
Cada elemento de la lista tiene la siguiente forma:
|
|
|
|
```python
|
|
{
|
|
"url": "http://localhost:8888",
|
|
"port": 8888,
|
|
"analysis": "estudio_mercados", # nombre del subdirectorio en analysis/, detectado via /proc
|
|
"root_dir": "$HOME/fn_registry/analysis/estudio_mercados", # path absoluto real del proceso
|
|
"collaborative": True, # True si YDocExtension esta activo
|
|
"kernels": [
|
|
{
|
|
"id": "abc123...",
|
|
"name": "python3",
|
|
"execution_state": "idle",
|
|
"last_activity": "2026-04-01T10:00:00.000Z"
|
|
}
|
|
],
|
|
"sessions": [
|
|
{
|
|
"notebook": "notebooks/01_exploracion.ipynb",
|
|
"kernel_id": "abc123...",
|
|
"kernel_state": "idle"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## CLI
|
|
|
|
```bash
|
|
# Descubrir con deteccion automatica
|
|
python python/functions/notebook/jupyter_discover.py --registry-root $HOME/fn_registry
|
|
|
|
# Puertos especificos, salida JSON
|
|
python python/functions/notebook/jupyter_discover.py --port 8888 --port 8889 --json
|
|
|
|
# Usando variable de entorno
|
|
FN_REGISTRY_ROOT=$HOME/fn_registry python python/functions/notebook/jupyter_discover.py
|
|
```
|
|
|
|
Ejemplo de salida en modo texto con multi-instancia:
|
|
|
|
```
|
|
Puerto 8888 [colaborativo]
|
|
url: http://localhost:8888
|
|
analysis: estudio_mercados
|
|
root_dir: $HOME/fn_registry/analysis/estudio_mercados
|
|
kernels (1):
|
|
- python3 estado=idle id=abc12345...
|
|
sesiones (1):
|
|
- notebooks/01.ipynb kernel=abc12345... estado=idle
|
|
|
|
Puerto 8889 [estandar]
|
|
url: http://localhost:8889
|
|
analysis: estudio_embeddings
|
|
root_dir: $HOME/fn_registry/analysis/estudio_embeddings
|
|
kernels: ninguno
|
|
sesiones: ninguna
|
|
```
|
|
|
|
## Notas
|
|
|
|
Solo usa stdlib: `urllib`, `json`, `pathlib`, `os`. No requiere `requests` ni clientes Jupyter especializados.
|
|
|
|
El escaneo de puertos tiene un timeout de 2 segundos por instancia para no bloquear en puertos cerrados.
|
|
|
|
### Deteccion de root_dir via /proc
|
|
|
|
En Linux, `_find_jupyter_pid_for_port()` escanea `/proc/*/cmdline` buscando el proceso Jupyter que tenga `--port=N` o `--ServerApp.port=N` en sus argumentos. Para el puerto default 8888, acepta cualquier proceso jupyter sin `--port` explicito.
|
|
|
|
Una vez encontrado el PID, `_get_root_dir_from_proc()` lee los argumentos buscando `--ServerApp.root_dir=` o `--notebook-dir=`. Si ninguno esta presente, usa el cwd del proceso (`/proc/{pid}/cwd`) como fallback.
|
|
|
|
La funcion `_extract_analysis_name()` extrae el nombre del analisis del root_dir: si el path contiene `analysis/{nombre}`, retorna `{nombre}`; en caso contrario retorna el ultimo componente del path.
|
|
|
|
Esta cadena es mas fiable que confiar solo en `.jupyter-port` porque detecta el directorio real del proceso, no el registrado al arranque.
|
|
|
|
### Prioridad de fuentes para analysis name
|
|
|
|
1. root_dir detectado via /proc (mas fiable)
|
|
2. Hint del archivo .jupyter-port (fallback si /proc no esta disponible)
|
|
3. Cadena vacia si ninguno funciona
|
|
|
|
### Modo colaborativo
|
|
|
|
La deteccion de modo colaborativo busca `YDocExtension` o `collaborative` en el JSON de `/api/config`. Esto cubre tanto jupyter-collaboration >= 2.x (que expone la extension bajo `LabApp`) como configuraciones antiguas.
|
|
|
|
Archivos `.jupyter-port`: el pipeline `init_jupyter_analysis` escribe este archivo en cada analisis al lanzar Jupyter, permitiendo que `jupyter_discover` los encuentre sin escanear todos los puertos.
|