Connecting to a remote IPython instance

Ohad picture Ohad · Apr 2, 2012 · Viewed 25k times · Source

I would like to run an IPython instance on one machine and connect to it (over LAN) from a different process (to run some python commands). I understand that it is possible with zmq : http://ipython.org/ipython-doc/dev/development/ipythonzmq.html .

However, I can not find documentation on how to do it and whether it is even possible yet.

Any help would be appreciated!


EDIT

I would like to be able to connect to IPython kernel instance and send it python commands. However, this should not be done via a graphic tool (qtconsole) , but I want to be able to connect to that kernel instance from within a different python script...

e.g.

external.py

somehow_connect_to_ipython_kernel_instance
instance.run_command("a=6")

Answer

minrk picture minrk · Apr 2, 2012

If you want to run code in a kernel from another Python program, the easiest way is to connect a BlockingKernelManager. The best example of this right now is Paul Ivanov's vim-ipython client, or IPython's own terminal client.

The gist:

  • ipython kernels write JSON connection files, in IPYTHONDIR/profile_<name>/security/kernel-<id>.json, which contain information necessary for various clients to connect and execute code.
  • KernelManagers are the objects that are used to communicate with kernels (execute code, receive results, etc.). *

A working example:

In a shell, do ipython kernel (or ipython qtconsole, if you want to share a kernel with an already running GUI):

$> ipython kernel
[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing kernel-6759.json

This wrote the 'kernel-6759.json' file

Then you can run this Python snippet to connect a KernelManager, and run some code:

from IPython.lib.kernel import find_connection_file
from IPython.zmq.blockingkernelmanager import BlockingKernelManager

# this is a helper method for turning a fraction of a connection-file name
# into a full path.  If you already know the full path, you can just use that
cf = find_connection_file('6759')

km = BlockingKernelManager(connection_file=cf)
# load connection info and init communication
km.load_connection_file()
km.start_channels()

def run_cell(km, code):
    # now we can run code.  This is done on the shell channel
    shell = km.shell_channel
    print
    print "running:"
    print code

    # execution is immediate and async, returning a UUID
    msg_id = shell.execute(code)
    # get_msg can block for a reply
    reply = shell.get_msg()

    status = reply['content']['status']
    if status == 'ok':
        print 'succeeded!'
    elif status == 'error':
        print 'failed!'
        for line in reply['content']['traceback']:
            print line

run_cell(km, 'a=5')
run_cell(km, 'b=0')
run_cell(km, 'c=a/b')

The output of a run:

running:
a=5
succeeded!

running:
b=0
succeeded!

running:
c=a/b
failed!
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
/Users/minrk/<ipython-input-11-fb3f79bd285b> in <module>()
----> 1 c=a/b

ZeroDivisionError: integer division or modulo by zero

see the message spec for more information on how to interpret the reply. If relevant, stdout/err and display data will come over km.iopub_channel, and you can use the msg_id returned by shell.execute() to associate output with a given execution.

PS: I apologize for the quality of the documentation of these new features. We have a lot of writing to do.