Embedding IPython Qt console in a PyQt application Embedding IPython Qt console in a PyQt application python python

Embedding IPython Qt console in a PyQt application


Ok, this code seems to do the trick (i.e. it puts a non-blocking ipython interpreter in a Qt widget, which can be embedded into other widgets). Keywords passed to terminal_widget get added to the namespace of the widget

import atexitfrom IPython.zmq.ipkernel import IPKernelAppfrom IPython.lib.kernel import find_connection_filefrom IPython.frontend.qt.kernelmanager import QtKernelManagerfrom IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidgetfrom IPython.utils.traitlets import TraitErrorfrom PyQt4 import QtGui, QtCoredef event_loop(kernel):    kernel.timer = QtCore.QTimer()    kernel.timer.timeout.connect(kernel.do_one_iteration)    kernel.timer.start(1000*kernel._poll_interval)def default_kernel_app():    app = IPKernelApp.instance()    app.initialize(['python', '--pylab=qt'])    app.kernel.eventloop = event_loop    return appdef default_manager(kernel):    connection_file = find_connection_file(kernel.connection_file)    manager = QtKernelManager(connection_file=connection_file)    manager.load_connection_file()    manager.start_channels()    atexit.register(manager.cleanup_connection_file)    return managerdef console_widget(manager):    try: # Ipython v0.13        widget = RichIPythonWidget(gui_completion='droplist')    except TraitError:  # IPython v0.12        widget = RichIPythonWidget(gui_completion=True)    widget.kernel_manager = manager    return widgetdef terminal_widget(**kwargs):    kernel_app = default_kernel_app()    manager = default_manager(kernel_app)    widget = console_widget(manager)    #update namespace                                                               kernel_app.shell.user_ns.update(kwargs)    kernel_app.start()    return widgetapp = QtGui.QApplication([])widget = terminal_widget(testing=123)widget.show()app.exec_()


The accepted answer by @ChrisB is fine for IPython version 0.13, but it doesn't work with newer versions. From the examples section of the IPython kernel repository on github, this is the way to do it in v1.x+ (currently tested with 4.0.1), which has the feature that the console and kernel are in the same process.

Here is an example, based on the official one, which gives a convenience class that can be easily plugged into an application. It's setup to work with pyqt4 and IPython 4.0.1 on Python 2.7:

(Note: you'll need to install the ipykernel and qtconsole packages)

# Set the QT API to PyQt4import osos.environ['QT_API'] = 'pyqt'import sipsip.setapi("QString", 2)sip.setapi("QVariant", 2)from PyQt4.QtGui  import *# Import the console machinery from ipythonfrom qtconsole.rich_ipython_widget import RichIPythonWidgetfrom qtconsole.inprocess import QtInProcessKernelManagerfrom IPython.lib import guisupportclass QIPythonWidget(RichIPythonWidget):    """ Convenience class for a live IPython console widget. We can replace the standard banner using the customBanner argument"""    def __init__(self,customBanner=None,*args,**kwargs):        if not customBanner is None: self.banner=customBanner        super(QIPythonWidget, self).__init__(*args,**kwargs)        self.kernel_manager = kernel_manager = QtInProcessKernelManager()        kernel_manager.start_kernel()        kernel_manager.kernel.gui = 'qt4'        self.kernel_client = kernel_client = self._kernel_manager.client()        kernel_client.start_channels()        def stop():            kernel_client.stop_channels()            kernel_manager.shutdown_kernel()            guisupport.get_app_qt4().exit()                    self.exit_requested.connect(stop)    def pushVariables(self,variableDict):        """ Given a dictionary containing name / value pairs, push those variables to the IPython console widget """        self.kernel_manager.kernel.shell.push(variableDict)    def clearTerminal(self):        """ Clears the terminal """        self._control.clear()        def printText(self,text):        """ Prints some plain text to the console """        self._append_plain_text(text)            def executeCommand(self,command):        """ Execute a command in the frame of the console widget """        self._execute(command,False)class ExampleWidget(QWidget):    """ Main GUI Widget including a button and IPython Console widget inside vertical layout """    def __init__(self, parent=None):        super(ExampleWidget, self).__init__(parent)        layout = QVBoxLayout(self)        self.button = QPushButton('Another widget')        ipyConsole = QIPythonWidget(customBanner="Welcome to the embedded ipython console\n")        layout.addWidget(self.button)        layout.addWidget(ipyConsole)                # This allows the variable foo and method print_process_id to be accessed from the ipython console        ipyConsole.pushVariables({"foo":43,"print_process_id":print_process_id})        ipyConsole.printText("The variable 'foo' and the method 'print_process_id()' are available. Use the 'whos' command for information.")                           def print_process_id():    print 'Process ID is:', os.getpid()        def main():    app  = QApplication([])    widget = ExampleWidget()    widget.show()    app.exec_()    if __name__ == '__main__':    main()


A 2016 update working in PyQt5:

from qtconsole.qt import QtGuifrom qtconsole.rich_jupyter_widget import RichJupyterWidgetfrom qtconsole.inprocess import QtInProcessKernelManagerclass ConsoleWidget(RichJupyterWidget):    def __init__(self, customBanner=None, *args, **kwargs):        super(ConsoleWidget, self).__init__(*args, **kwargs)        if customBanner is not None:            self.banner = customBanner        self.font_size = 6        self.kernel_manager = kernel_manager = QtInProcessKernelManager()        kernel_manager.start_kernel(show_banner=False)        kernel_manager.kernel.gui = 'qt'        self.kernel_client = kernel_client = self._kernel_manager.client()        kernel_client.start_channels()        def stop():            kernel_client.stop_channels()            kernel_manager.shutdown_kernel()            guisupport.get_app_qt().exit()        self.exit_requested.connect(stop)    def push_vars(self, variableDict):        """        Given a dictionary containing name / value pairs, push those variables        to the Jupyter console widget        """        self.kernel_manager.kernel.shell.push(variableDict)    def clear(self):        """        Clears the terminal        """        self._control.clear()        # self.kernel_manager    def print_text(self, text):        """        Prints some plain text to the console        """        self._append_plain_text(text)    def execute_command(self, command):        """        Execute a command in the frame of the console widget        """        self._execute(command, False)if __name__ == '__main__':    app = QtGui.QApplication([])    widget = ConsoleWidget()    widget.show()    app.exec_()