feat: mejoras notebook functions — discover multi-servidor, write batch ops
jupyter_discover: soporte multi-servidor, detección de modo colaborativo mejorada. jupyter_write: operaciones batch (insert, edit, delete), manejo robusto de Y.js. jupyter_exec: mejoras en ejecución directa al kernel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ from urllib.request import Request, urlopen
|
||||
|
||||
from jupyter_kernel_client import KernelClient
|
||||
from jupyter_nbmodel_client import NbModelClient, get_jupyter_notebook_websocket_url
|
||||
from nbformat import NotebookNode
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -60,6 +61,24 @@ def _resolve_collab_username(server_url: str, token: str) -> str:
|
||||
return "Anonymous"
|
||||
|
||||
|
||||
def _normalize_code_cell(cell: NotebookNode) -> dict:
|
||||
"""Devuelve un dict de celda de codigo con todos los campos requeridos por nbformat.
|
||||
|
||||
Celdas creadas manualmente (no via Jupyter UI) pueden omitir 'outputs' o
|
||||
'execution_count'. El modelo CRDT de jupyter_nbmodel_client accede a estos
|
||||
campos sin comprobar su existencia, produciendo KeyError al ejecutar.
|
||||
Este helper garantiza que el dict tenga la estructura completa.
|
||||
"""
|
||||
return {
|
||||
"id": cell.get("id", ""),
|
||||
"cell_type": "code",
|
||||
"metadata": cell.get("metadata", {}),
|
||||
"source": cell.get("source", ""),
|
||||
"outputs": cell.get("outputs", []),
|
||||
"execution_count": cell.get("execution_count", None),
|
||||
}
|
||||
|
||||
|
||||
def _extract_outputs(raw_outputs: list[dict]) -> list[str]:
|
||||
"""Convierte outputs de nbformat a lista de strings legibles."""
|
||||
result: list[str] = []
|
||||
@@ -141,6 +160,18 @@ async def _async_execute_cell(
|
||||
async with NbModelClient(ws_url, username=username) as nb:
|
||||
await nb.wait_until_synced()
|
||||
|
||||
# Normalizar la celda antes de ejecutar. Las celdas creadas manualmente
|
||||
# (sin pasar por la UI de Jupyter) pueden carecer de los campos 'outputs'
|
||||
# o 'execution_count' en el modelo CRDT, lo que provoca KeyError dentro
|
||||
# de execute_cell al intentar hacer `del ycell["outputs"][:]`.
|
||||
# Reemplazar la celda via __setitem__ fuerza la re-creacion completa del
|
||||
# mapa CRDT con todos los campos requeridos por nbformat.
|
||||
cell = nb[cell_index]
|
||||
if cell.get("cell_type") == "code" and (
|
||||
"outputs" not in cell or "execution_count" not in cell
|
||||
):
|
||||
nb[cell_index] = _normalize_code_cell(cell)
|
||||
|
||||
with KernelClient(server_url=server_url, token=token, kernel_id=kernel_id) as kernel:
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(
|
||||
|
||||
Reference in New Issue
Block a user