IPython Notebook Javascript: recupera contenido de variables de JavaScript

¿Hay alguna forma para que una función (llamada por una celda de cuaderno de IPython) recupere el contenido de una variable de JavaScript (por ejemplo, IPython.notebook.notebook_path que contiene la ruta del cuaderno actual)?

Lo siguiente funciona bien cuando se escribe directamente dentro de una celda (por ejemplo, basado en esta pregunta y sus comentarios):

 from IPython.display import display,Javascript Javascript('IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");') 

Pero eso se desmorona si trato de ponerlo en una función:

 # this doesn't work from IPython.display import display,Javascript def getname(): my_js = """ IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'"); """ Javascript(my_js) return mypath 

(Y sí, he intentado hacer global la variable mypath , tanto desde dentro del script my_js como desde dentro de la función. También tenga en cuenta: no se deje engañar por los posibles valores sobrantes en las variables de los comandos anteriores; para asegurarse, use mypath = None; del mypath para restablecer la variable antes de llamar a la función, o reiniciar el kernel.)

Otra forma de formular la pregunta es: “¿cuál es el scope (hora y lugar) de una variable establecida por IPython.notebook.kernel.execute() “?

Creo que no es una pregunta inocua, y probablemente esté relacionada con el mecanismo que utiliza IPython para controlar sus núcleos y sus variables y de lo que no sé mucho. El siguiente experimento ilustra algún aspecto de ese mecanismo. Lo siguiente funciona cuando se realiza en dos celdas separadas, pero no funciona si las dos celdas se fusionan:

Celda [1] :

 my_out = None del my_out my_js = """ IPython.notebook.kernel.execute("my_out = 'hello world'"); """ Javascript(my_js) 

Celda [2] :

 print(my_out) 

Esto funciona y produce el esperado hello world . Pero si combina las dos celdas, no funciona ( NameError: name 'my_out' is not defined ).

Creo que el problema está relacionado con el hecho de que Javascript sea asíncrono, mientras que Python no. Normalmente, usted pensaría que el comando Javascript (“” “python cmd” “”) se ejecuta, y luego su estado de impresión debería funcionar correctamente como se esperaba. Sin embargo, el comando de Javascript se activa pero no se ejecuta. En su mayoría, se ejecuta después de que la ejecución de la celda 1 se complete por completo.

Probé tu ejemplo con la función del sueño. No ayudó.

El problema de asnyc se puede ver simplemente agregando una statement de alerta dentro de my_js, pero antes de la línea kernel.execute. La alerta debe activarse incluso antes de intentar ejecutar un comando de python.

Pero ante la presencia de la statement de impresión (my_out) dentro de la celda 1, nuevamente obtendrá el mismo error sin alertas. Si quita la línea de impresión, verá que la alerta aparece dentro de la celda 1. Pero la varibale my_out se establece después.

 my_out = None del my_out my_js = """ **alert ("about to execute python comand");** IPython.notebook.kernel.execute("my_out = 'hello world'"); """ Javascript(my_js) 

Hay otras utilidades de javascript dentro del cuaderno como IPython.display.display_xxx que varía de visualización de video a objeto de texto, pero incluso la opción de objeto de texto no funciona.

Curiosamente, lo probé con mi aplicación de canvas webgl que muestra objetos en el canvas HTML5; ¿Display.display_javascript (objeto javascript) funciona bien (que es un documento html5 de looong) mientras que las dos piezas de palabras de salida no aparecen? Tal vez debería incrustar la salida en la aplicación de canvas en algún lugar, para que se muestre en el canvas 🙂

De acuerdo, encontré una manera de solucionar el problema: llamar a una función de Python desde Javascript y hacer que haga todo lo que necesito, en lugar de devolver el nombre a “arriba” y trabajar con ese nombre allí.

Para el contexto: mis colegas y yo tenemos muchos cuadernos experimentales; Experimentamos por un tiempo y probamos varias cosas (en un contexto de aprendizaje automático). Al final de cada variación / ejecución, quiero guardar el cuaderno, copiarlo con un nombre que refleje la hora, subirlo a S3, eliminarlo de su salida y enviarlo a git, registrar el nombre de archivo, los comentarios y el resultado puntuaciones en una base de datos, etc. En resumen, quiero realizar un seguimiento automático de todos nuestros experimentos.

Esto es lo que tengo hasta ahora. En la parte inferior de mis cuadernos, pongo:

 In [127]: import mymodule.utils.lognote as lognote lognote.snap() In [128]: # not to be run in the same shot as above lognote.last Out[128]: {'file': '/data/notebook-snapshots/2015/06/18/20150618-004408-save-note-exp.ipynb', 'time': datetime.datetime(2015, 6, 18, 0, 44, 8, 419907)} 

Y en un archivo separado, por ejemplo, mymodule/utils/lognote.py :

 # (...) from datetime import datetime from subprocess import call from os.path import basename, join from IPython.display import display, Javascript # TODO: find out where the topdir really is instead of hardcoding it _notebook_dir = '/data/notebook' _snapshot_dir = '/data/notebook-snapshots' def jss(): return """ IPython.notebook.save_notebook(); IPython.notebook.kernel.execute("import mymodule.utils.lognote as lognote"); IPython.notebook.kernel.execute("lognote._snap('" + IPython.notebook.notebook_path + "')"); """ def js(): return Javascript(jss()) def _snap(x): global last snaptime = datetime.now() src = join(_notebook_dir, x) dstdir = join(_snapshot_dir, '{}'.format(snaptime.strftime("%Y/%m/%d"))) dstfile = join(dstdir, '{}-{}'.format(snaptime.strftime("%Y%m%d-%H%M%S"), basename(x))) call(["mkdir", "-p", dstdir]) call(["cp", src, dstfile]) last = { 'time': snaptime, 'file': dstfile } def snap(): display(js()) 

Para agregar a las otras grandes respuestas, hay un matiz de los navegadores que intentan ejecutar el jupyter nb javascript magic en nb load.

Para demostrar: crea y ejecuta la siguiente celda:

 %%javascript IPython.notebook.kernel.execute('1') 

Ahora guarde el cuaderno, ciérrelo y vuelva a abrirlo. Cuando haces eso, de repente debajo de esa celda verás un error en rojo:

 Javascript error adding output! TypeError: Cannot read property 'execute' of null See your browser Javascript console for more details. 

Eso significa que el navegador ha analizado algunos códigos js y trató de ejecutarlo. Este es el error en Chrome, probablemente será diferente en un navegador diferente.

No tengo ni idea de por qué esta celda mágica jupascript de jupyter se está ejecutando en carga y por qué la notebook jupyter no se está escapando correctamente, pero el navegador ve un código js, ​​por lo que lo ejecuta y falla, porque el kernel de la notebook aún no existe !

Entonces debes agregar un cheque de que el objeto existe:

 %%javascript if (IPython.notebook.kernel) { IPython.notebook.kernel.execute('1') } 

y ahora no hay problema en la carga.

En mi caso, necesitaba guardar el cuaderno y ejecutar un script externo en él, así que terminé usando este código:

 from IPython.display import display, Javascript def nb_auto_export(): display(Javascript("if (IPython.notebook) { IPython.notebook.save_notebook() }; if (IPython.notebook.kernel) { IPython.notebook.kernel.execute('!./notebook2script.py ' + IPython.notebook.notebook_name )}")) 

y en la última celda del cuaderno:

 nb_auto_export()