Extrae al registry funciones del proyecto interno footprint_aurgi: - core (6): slugify_ascii, normalize_for_join, cp_provincia_es, infer_provincia_from_cp, safe_read_csv_fallback, csv_to_parquet_duckdb - geo puras (7): haversine_km, point_in_ring, point_in_polygon, point_in_polygons_bbox, polygon_bbox, extent_with_padding, distance_bucket - geo I/O (4): load_geojson_polygons, load_boundary_gdf, add_basemap_osm, add_basemap_with_timeout - valhalla client (4): valhalla_route, valhalla_isochrone, valhalla_isochrones_async, valhalla_matrix_1_to_n - datascience stats (7): trimmed_mean, geometric_mean, detect_distribution_type, best_central_tendency, summary_stats, kde_density_levels, alpha_shape_concave_hull - datascience fuzzy (3): fuzzy_merge_adaptive (rapidfuzz), words_to_dataset, remove_words_from_column - datascience viz (2): plot_kde_2d, plot_heatmap_log - infra (4): compress_pdf_ghostscript, render_table_page_pdfpages, add_header_logo, osm2pgsql_ingest - pipelines (4): setup_geo_stack_docker, compute_centers_reachability, generate_isochrones_by_zone, count_points_per_zone - types geo (4): LonLat, BBox, IsochroneRequest, Centro Incluye: - apps/footprint_geo_stack/ (PostGIS + Martin + Valhalla via docker-compose) - 131/132 tests pasan (1 skip esperado: osm2pgsql en PATH) - Issue tracker dev/issues/0052-footprint-aurgi-extraction.md - Atribucion uniforme: source_repo internal:footprint_aurgi, source_license internal-aurgi - Build con 9 agentes en paralelo (8 wave 1 + 1 wave 2 pipelines) Tambien commitea trabajo previo no commiteado: aggregate_extraction_results, chunk_with_overlap, clean_pdf_text, merge_entity_aliases, extract_graph_gliner2, extract_relations_mrebel, extract_triples_spacy_es, gliner2/mrebel/marianmt/rebel/spacy_es load_model, parse_rebel_output, translate_es_to_en, issue 0050/0051. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.8 KiB
0050 — jupyter_exec falla por cliente colaborativo (workaround documentado)
APP Metadata
| Campo | Valor |
|---|---|
| ID | 0050 |
| Estado | pendiente |
| Prioridad | media |
| Tipo | bug — python/functions/notebook/jupyter_exec.py |
Dependencias
Ninguna. Independiente del resto.
Sintoma
Al ejecutar jupyter_exec.py append <notebook> <code> contra un Jupyter Lab
arrancado con el launcher estandar de los analyses (run-jupyter-lab.sh,
flag --collaborative), la operacion falla con:
{"error": "HTTP Error 405: Method Not Allowed"}
jupyter_write.py append-code y append-markdown SI funcionan (no usan el
canal colaborativo). El bug solo afecta a jupyter_exec, que necesita
ejecutar la celda en el kernel y para eso usa jupyter_nbmodel_client
con websocket Y.js.
Reproducido en 2026-05-04 durante la construccion del analysis
projects/osint_graph/analysis/gliner_glirel_tuning/. El resto de
funciones del modulo notebook/ quedan intactas:
$JX append <nb> <code> # ❌ HTTP 405
$JW append-code <nb> <code> # ✅ OK (sin ejecucion)
$JW append-markdown <nb> <md> # ✅ OK
$JX cell <nb> <idx> # 🔁 No probado, pero usa el mismo cliente
$JX kernel <code> # 🔁 No probado
Diagnostico (parcial)
jupyter_nbmodel_client espera que el server tenga la extension
jupyter_collaboration activa y montada en /api/collaboration/.... El
launcher arranca jupyter con el flag CLI --collaborative, que en
versiones recientes (jupyter_server >= 2.x, jupyter-collaboration >= 4.x)
ya no es suficiente — la extension se carga via entry-point y se
controla con flags distintos (--YDocExtension.disable_rtc o equivalente),
o requiere un fichero de config explicito.
Salida de jupyter_discover.py confirma el sintoma indirectamente:
{ "url": "http://localhost:8888", "collaborative": false, ... }
aunque --collaborative esta en el launch command. Es decir: el server
arranca, expone la API REST, pero la capa colaborativa NO esta activa.
Workaround usado en gliner_glirel_tuning
Cambio de tactica: en lugar de construir el notebook con jupyter_exec append celda a celda, se ejecutan los experimentos en un script
externo y se empotran las celdas (codigo + outputs ya generados) con
nbformat directo a fichero. El notebook resultante es persistente y
no necesita el canal colaborativo.
# build_notebook.py
import nbformat as nbf
nb = nbf.v4.new_notebook()
for src, stdout in cells:
cell = nbf.v4.new_code_cell(src)
cell.outputs = [nbf.v4.new_output("stream", name="stdout", text=stdout)]
nb.cells.append(cell)
nbf.write(nb, "notebooks/01_foo.ipynb")
Si se quieren outputs reales (DataFrames como HTML, figuras matplotlib),
ejecutar despues con nbconvert:
IPYTHONDIR=$(pwd)/.ipython ./.venv/bin/jupyter nbconvert \
--to notebook --execute notebooks/01_foo.ipynb \
--output 01_foo.ipynb --ExecutePreprocessor.timeout=300
Esto bypassa completamente el canal colaborativo y produce un .ipynb
funcional, abrible en Jupyter Lab para ver / iterar / re-ejecutar.
Ver projects/osint_graph/analysis/gliner_glirel_tuning/build_notebook.py
y build_notebook_e2e.py para ejemplos vivos.
Causas raiz a investigar
- Verificar la version de
jupyter-collaborationen el venv del analysis. Si es >=4.x, el flag--collaborativeya no aplica y el launcher (write_jupyter_launcher_bash_io) tiene que actualizarse. - El cliente
jupyter_nbmodel_clientpuede tener su propia ventana de versiones soportadas — comprobar pinning enpython/.venvy en los venvs de analyses. - El endpoint
/api/collaboration/documentdebe responder a unGETcon HTTP 200 cuando la extension esta activa. Si responde405, el cliente intenta una operacion (POST/PUT) sobre un endpoint que solo acepta GET, sintoma de mismatch.
Tareas
- Reproducir el
HTTP 405con un notebook nuevo y un kernel nuevo en un analysis recien creado. - Capturar la URL exacta y el metodo HTTP que dispara el 405
(anadir logging a
jupyter_exec.pylinea ~192/229 donde llama aget_jupyter_notebook_websocket_url). - Verificar version de
jupyter-collaborationen el venv y comparar con la matriz de compatibilidad dejupyter_nbmodel_client. - Una de dos:
- (a) Corregir el flag/config en
write_jupyter_launcher_bash_iopara activar correctamente la colaboracion en versiones nuevas. - (b) Si la API colaborativa cambio mucho, migrar
jupyter_exec.pya usar elJupyterClientclasico (REST + WebSocket directo al kernel sin Y.js) que es estable a traves de versiones.jupyter_kernel.pyya hace algo asi y funciona.
- (a) Corregir el flag/config en
- Anadir un test e2e basico en
tests/que arranca jupyter, lanzajupyter_exec append, verifica que la celda se ejecuto y captura stdout. Sin esto el bug puede regresar.
Out of scope
- Reescribir el sistema completo de notebook collaboration.
- Migrar a un MCP. La regla
notebook_collaboration.mdes explicita: estas funciones reemplazan al MCP jupyter.
Riesgos
- Si la causa es la matriz de versiones, la opcion (a) puede generar
fricion futura cada vez que
jupyter-collaborationhaga un breaking change. La opcion (b) es mas robusta a largo plazo aunque pierde la capacidad de ver cambios en tiempo real desde el navegador.
Notas operativas
Mientras este bug exista, el patron recomendado para construir notebooks desde un agente Claude en un analysis es:
build_notebook.pyconnbformatpara estructura + outputs estaticos.nbconvert --executepara outputs reales (HTML, plots).- Si necesitas tiempo real con el browser, abre el notebook ya generado en Jupyter Lab y reejecuta a mano.
El propio analysis gliner_glirel_tuning es referencia.