diff --git a/IPython/lib/kernel.py b/IPython/lib/kernel.py new file mode 100644 index 0000000..1293344 --- /dev/null +++ b/IPython/lib/kernel.py @@ -0,0 +1,99 @@ +"""Utilities for connecting to kernels + +Authors: + +* Min Ragan-Kelley + +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2011 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import json +import sys +from subprocess import Popen, PIPE + +from IPython.utils.path import filefind +from IPython.utils.py3compat import str_to_bytes + + +#----------------------------------------------------------------------------- +# Functions +#----------------------------------------------------------------------------- + +def get_connection_file(app=None): + """Return the path to the connection file of an app + + Parameters + ---------- + app : KernelApp instance [optional] + If unspecified, the currently running app will be used + """ + if app is None: + from IPython.zmq.kernelapp import KernelApp + if not KernelApp.initialized(): + raise RuntimeError("app not specified, and not in a running Kernel") + + app = KernelApp.instance() + return filefind(app.connection_file, ['.', app.profile_dir.security_dir]) + +def get_connection_info(unpack=False): + """Return the connection information for the current Kernel. + + Parameters + ---------- + unpack : bool [default: False] + if True, return the unpacked dict, otherwise just the string contents + of the file. + + Returns + ------- + The connection dictionary of the current kernel, as string or dict, + depending on `unpack`. + """ + cf = get_connection_file() + with open(cf) as f: + info = f.read() + + if unpack: + info = json.loads(info) + # ensure key is bytes: + info['key'] = str_to_bytes(info.get('key', '')) + return info + +def connect_qtconsole(argv=None): + """Connect a qtconsole to the current kernel. + + This is useful for connecting a second qtconsole to a kernel, or to a + local notebook. + + Parameters + ---------- + argv : list [optional] + Any extra args to be passed to the console. + + Returns + ------- + subprocess.Popen instance running the qtconsole frontend + """ + argv = [] if argv is None else argv + + # get connection file from current kernel + cf = get_connection_file() + + cmd = ';'.join([ + "from IPython.frontend.qt.console import qtconsoleapp", + "qtconsoleapp.main()" + ]) + + return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv, stdout=PIPE, stderr=PIPE) + + diff --git a/IPython/zmq/zmqshell.py b/IPython/zmq/zmqshell.py index e2bafa0..1125e55 100644 --- a/IPython/zmq/zmqshell.py +++ b/IPython/zmq/zmqshell.py @@ -31,9 +31,13 @@ from IPython.core.displaypub import DisplayPublisher from IPython.core.macro import Macro from IPython.core.magic import MacroToEdit from IPython.core.payloadpage import install_payload_page +from IPython.lib.kernel import ( + get_connection_file, get_connection_info, connect_qtconsole +) from IPython.utils import io from IPython.utils.jsonutil import json_clean from IPython.utils.path import get_py_filename +from IPython.utils.process import arg_split from IPython.utils.traitlets import Instance, Type, Dict, CBool from IPython.utils.warn import warn, error from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary @@ -442,18 +446,14 @@ class ZMQInteractiveShell(InteractiveShell): $> ipython --existing """ - from IPython.zmq.kernelapp import KernelApp - if not KernelApp.initialized(): - error("KernelApp is not initialized. I cannot find the connection info") - return - app = KernelApp.instance() try: - with open(app.connection_file) as f: - s = f.read() + connection_file = get_connection_file() + info = get_connection_info(unpack=False) except Exception as e: - error("Could not read connection file: %s" % e) + error("Could not get connection info: %r" % e) return - print (s + '\n') + + print (info + '\n') print ("Paste the above JSON into a file, and connect with:\n" " $> ipython --existing \n" "or, if you are local, you can connect with just:\n" @@ -461,7 +461,7 @@ class ZMQInteractiveShell(InteractiveShell): "or even just:\n" " $> ipython --existing\n" "if this is the most recent IPython session you have started." - % os.path.basename((app.connection_file)) + % os.path.basename(connection_file) ) def magic_qtconsole(self, arg_s): @@ -470,20 +470,12 @@ class ZMQInteractiveShell(InteractiveShell): Useful for connecting a qtconsole to running notebooks, for better debugging. """ - from IPython.zmq.kernelapp import KernelApp - - if not KernelApp.initialized(): - error("KernelApp is not initialized. %qtconsole magic must be run from a Kernel") + try: + p = connect_qtconsole(arg_split(arg_s, os.name=='posix')) + except Exception as e: + error("Could not start qtconsole: %r" % e) return - app = KernelApp.instance() - - cmd = ';'.join([ - "from IPython.frontend.qt.console import qtconsoleapp", - "qtconsoleapp.main()" - ]) - return Popen([sys.executable, '-c', cmd, '--existing', app.connection_file], - stdout=PIPE,stderr=PIPE) def set_next_input(self, text): """Send the specified text to the frontend to be presented at the next