I'm trying to write a Jupyter nbextension where the user can configure the notebook-wide extension behavior using IPython magics. I'm planning on siting the configuration data on the JS side, under an application-specific key in Jupyter.notebook.metadata
, "tempvars"
. In order to do this, I need the magics to be able to change the appropriate values within that ....metadata["tempvars"]
.
If I load a Jupyter notebook and make metadata changes using IPython.display.Javascript
directly from a notebook cell, they apply successfully.
JS console:
>> Jupyter.notebook.metadata["tempvars"]["universal"] = false
<- false
Jupyter cell:
[ ]: from IPython.display import Javascript
[ ]: Javascript("Jupyter.notebook.metadata['tempvars']['universal'] = true")
JS console:
>> Jupyter.notebook.metadata["tempvars"]["universal"]
<- true // CHANGED AS EXPECTED
However, if I try to do the same thing from inside a magic, it does not work:
From my magics definition module, within the broader jupyter_tempvars
package (please don't mind the very WIP implementation):
from IPython.core.magic import register_line_magic
def load_ipython_extension(ipython):
@register_line_magic
def tempvars(line):
subcommand, arg = line.strip().split(" ")
if subcommand == "universal":
Javascript(f"Jupyter.notebook.metadata['tempvars']['universal'] = {arg.lower()};")
From a freshly loaded notebook, starting in the JS console:
>> Jupyter.notebook.metadata["tempvars"]["universal"] = false
<- false
Jupyter cells:
[ ]: %load_ext jupyter_tempvars
[ ]: %tempvars universal true
JS console:
>> Jupyter.notebook.metadata["tempvars"]["universal"]
<- false // DID NOT CHANGE
What is different about the IPython magic context that is making this Javascript
call fail?
According to the IPython docs for the
Javascript
object:As it turns out, the rendering of the JS code upon simply being returned by an expression is not a universal behavior. In particular, inside an IPython magic, you must pass the
Javascript
instance toIPython.display.display()
in order for it to be rendered.This is what IPython does in its own built-in (and deprecation-pending)
%javascript
magic.