applecider
applecider

Reputation: 2471

IPython notebook ~ Using javascript to run python code?

I am trying to execute python code through javascript directly:

  1. I fire up IPython Notebook on Chrome
  2. Using chrome developer tools I open up the javascript console.

In the javascript consolde, I type: IPython.notebook.kernel.execute("2+2")

enter image description here

But I get a strange output: "6CEA73CC644648DDA978FDD6A913E519"

Is there any way to take advantage of all the IPython javascript functions available, to run python code from the javascript console as depicted in the image? I'm sure there's a way but I've been beating at it for way too long and thought I would post here.

(I need this to build an app on top of IPython)

Thanks in advance!

Upvotes: 11

Views: 4711

Answers (4)

hBy2Py
hBy2Py

Reputation: 1832

In an effort to isolate a minimum viable implementation, I was able to get responses back from the IPython kernel in just a couple of steps using essentially the same approach as ChrCury78.

Since I want to use the data returned from Python within Javascript, in these examples I just stored the message contents in a member on console. (Unlike what ChrCury78 did, where he pushed the result to the output of the notebook cell.) In my real extension, I'll probably just attach it to a name on Jupyter, or maybe an object of my own creation.

>> Jupyter.notebook.kernel.comm_manager.register_target("mycomm", (comm, msg) => {comm.on_msg( m => {console.retval = m.content.data})})
<- undefined
>> Jupyter.notebook.kernel.execute("from ipykernel.comm import Comm; Comm(target_name='mycomm').send('FOO')")
<- "{hex UID}"
>> console.retval
<- "FOO"

Multi-line Python code worked just fine, too; and, since I'd already imported Comm, I didn't need to import it again:

>> Jupyter.notebook.kernel.execute("l = []\nfor x in range(5):\n  l.append(x)\nComm(target_name='mycomm').send(l)")
<- "{hex UID}"
>> console.retval
<- Array(5) [ 0, 1, 2, 3, 4 ]

If you want to keep the kernel namespace unpolluted afterward, you could add a del Comm to the end of the Python command.

I'll definitely be writing wrapper functions of some kind for both of these operations.


This is with Python 3.9.11 and the following packages installed:

ipykernel                         6.9.2
ipython                           8.1.1
ipython-genutils                  0.2.0
ipywidgets                        7.7.0

jupyter                           1.0.0
jupyter-client                    7.1.2
jupyter-console                   6.4.3
jupyter-contrib-core              0.3.3
jupyter-contrib-nbextensions      0.5.1
jupyter-core                      4.9.2
jupyter-highlight-selected-word   0.2.0
jupyter-latex-envs                1.4.6
jupyter-nbextensions-configurator 0.4.1
jupyterlab-pygments               0.1.2
jupyterlab-widgets                1.1.0

Upvotes: 0

ChrCury78
ChrCury78

Reputation: 437

After spending two days on it, here is the solution that worked for me.

To run Python code I am simpy using 'Jupyter.notebook.kernel.execute'. To get the answer from it I found usefull information at this link: https://jupyter-notebook.readthedocs.io/en/stable/comms.html

from ipykernel.comm import Comm

js_input = [] #case willing to track

def func_edit(cobj,text):
    my_comm = Comm(target_name=cobj) #this is the callback
    my_comm.send('' if  text == '' else 'Return: ' + text)

    global js_input
    js_input.append(f'origin={cobj} text={text}')
    
    
    
from IPython.display import display, HTML
html = """
<script>
    var comm_name = "this_control";
    function fcalc(x)
    {
        // here I am passing to the Python function the value to edit and the address for getting the return value
        IPython.notebook.kernel.execute("func_edit('" + comm_name + "','" + x.value + "')")
    }
    Jupyter.notebook.kernel.comm_manager.register_target(comm_name, function(comm, msg) 
        {
          // comm is the frontend comm instance,  msg is the comm_open message, which can carry data

            // Register handlers for later messages:
            comm.on_msg(function(msg) { 
                document.getElementById("out").value = msg.content.data;
            });
            
            //comm.on_close(function(msg) {...});
            //comm.send({'foo': 40}); what is it??
        });
</script>
<label for="in">Input:</label>
<input type="text" id="in" name="in" oninput="fcalc(this)">
<label for="out">Out:</label>
<input type="text" id="out">
"""
display(HTML(html))

Upvotes: 1

Y.N
Y.N

Reputation: 5287

You can call Python code execution from JavaScript with Jupyter.notebook.kernel.execute() function.

Depend on this gist from Craig Dennis you can insert this code in Jupyter cell and run it

%%javascript
window.executePython = function(python) {
    return new Promise((resolve, reject) => {
        var callbacks = {
            iopub: {
                output: (data) => resolve(data.content.text.trim())
            }
        };
        Jupyter.notebook.kernel.execute(`${python}`, callbacks);    
    });
}

function Log_out(r)
{ console.log(r); };

var code = 
'for i in range(1,6):'+
'    print( "#" + str(i))';

window.executePython( code )
    .then(result => Log_out(result)); // Log out

Result would be output to browser javascript console.

Upvotes: 6

arthaigo
arthaigo

Reputation: 453

Are you aware of this blogpost? http://jakevdp.github.io/blog/2013/06/01/ipython-notebook-javascript-python-communication/

I think the exact way he uses doesn't work anymore, but maybe it can get you a step forward

Upvotes: 1

Related Questions