Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedding IPython Qt console in a PyQt application

I'd like to embed an IPython qt console widget in a PyQt application I am working on. The code provided below (and adapted from https://stackoverflow.com/a/9796491/1332492) Accomplishes this for IPython v0.12. However, this crashes in IPython v0.13 at the line self.heartbeat.start() with RuntimeError: threads can only be started once. Commenting out this line brings up the widget, but doesn't respond to user input.

Does anyone know how to achieve the equivalent functionality for IPython v0.13?

""" Adapted from https://stackoverflow.com/a/9796491/1332492 """ import os import atexit  from IPython.zmq.ipkernel import IPKernelApp from IPython.lib.kernel import find_connection_file from IPython.frontend.qt.kernelmanager import QtKernelManager from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget from IPython.config.application import catch_config_error from PyQt4 import QtCore   class IPythonLocalKernelApp(IPKernelApp):     DEFAULT_INSTANCE_ARGS = ['']      @catch_config_error     def initialize(self, argv=None):         super(IPythonLocalKernelApp, self).initialize(argv)         self.kernel.eventloop = self.loop_qt4_nonblocking      def loop_qt4_nonblocking(self, kernel):         """Non-blocking version of the ipython qt4 kernel loop"""         kernel.timer = QtCore.QTimer()         kernel.timer.timeout.connect(kernel.do_one_iteration)         kernel.timer.start(1000*kernel._poll_interval)      def start(self, argv=DEFAULT_INSTANCE_ARGS):         """Starts IPython kernel app         argv: arguments passed to kernel         """         self.initialize(argv)         self.heartbeat.start()          if self.poller is not None:             self.poller.start()          self.kernel.start()   class IPythonConsoleQtWidget(RichIPythonWidget):     _connection_file = None      def __init__(self, *args, **kw):         RichIPythonWidget.__init__(self, *args, **kw)         self._existing = True         self._may_close = False         self._confirm_exit = False      def _init_kernel_manager(self):         km = QtKernelManager(connection_file=self._connection_file, config=self.config)         km.load_connection_file()         km.start_channels(hb=self._heartbeat)         self.kernel_manager = km         atexit.register(self.kernel_manager.cleanup_connection_file)      def connect_kernel(self, connection_file, heartbeat=False):         self._heartbeat = heartbeat         if os.path.exists(connection_file):             self._connection_file = connection_file         else:             self._connection_file = find_connection_file(connection_file)          self._init_kernel_manager()   def main(**kwargs):     kernelapp = IPythonLocalKernelApp.instance()     kernelapp.start()      widget = IPythonConsoleQtWidget()     widget.connect_kernel(connection_file=kernelapp.connection_file)     widget.show()      return widget  if __name__ == "__main__":     from PyQt4.QtGui import QApplication     app = QApplication([''])     main()     app.exec_() 

Traceback for v0.13

RuntimeError                              Traceback (most recent call last) /Users/beaumont/terminal.py in <module>()      80     from PyQt4.QtGui import QApplication      81     app = QApplication(['']) ---> 82     main()         global main = <function main at 0x106d0c848>      83     app.exec_()  /Users/beaumont/terminal.py in main(**kwargs={})      69 def main(**kwargs):      70     kernelapp = IPythonLocalKernelApp.instance() ---> 71     kernelapp.start()         kernelapp.start = <bound method IPythonLocalKernelApp.start of     <__main__.IPythonLocalKernelApp object at 0x106d10590>>      72       73     widget = IPythonConsoleQtWidget()  /Users/beaumont/terminal.py in start(self=<__main__.IPythonLocalKernelApp object>, argv=[''])      33         """      34         self.initialize(argv) ---> 35         self.heartbeat.start()         self.heartbeat.start = <bound method Heartbeat.start of <Heartbeat(Thread-1, started daemon 4458577920)>>      36       37         if self.poller is not None:  /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyc in start(self=<Heartbeat(Thread-1, started daemon 4458577920)>)     487             raise RuntimeError("thread.__init__() not called")     488         if self.__started.is_set(): --> 489             raise RuntimeError("threads can only be started once")         global RuntimeError = undefined     490         if __debug__:     491             self._note("%s.start(): starting thread", self)  RuntimeError: threads can only be started once 
like image 878
ChrisB Avatar asked Jul 16 '12 21:07

ChrisB


People also ask

How do I use IPython console?

The IPython Console allows you to execute commands and interact with data inside IPython interpreters. To launch a new IPython instance, go to New console (default settings) under the Consoles menu, or use the keyboard shortcut Ctrl - T ( Cmd - T on macOS) when the console is focused.

What is IPython QT console?

Jupyter QtConsole The Qtconsole is a very lightweight application that largely feels like a terminal, but provides a number of enhancements only possible in a GUI, such as inline figures, proper multiline editing with syntax highlighting, graphical calltips, and more.

How do you get the IPython console on Spyder?

Spyder can launch new IPython instances itself, through “Open an IPython console” under the Consoles menu, the IPython Console pane menu or its context menu ( Ctrl - T by default), to take advantage of the full suite of Spyder's features.

What is Qt console application?

The Qt console is a GUI application similar to IPython terminal. However, it provides a number of enhancements which are not available in text based IPython terminal. The enhance features are inline figures, multi-line editing with syntax highlighting, graphical calltips, etc.


1 Answers

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 atexit  from IPython.zmq.ipkernel import IPKernelApp from IPython.lib.kernel import find_connection_file from IPython.frontend.qt.kernelmanager import QtKernelManager from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget from IPython.utils.traitlets import TraitError from PyQt4 import QtGui, QtCore  def 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 app  def 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 manager  def 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 widget  def 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 widget  app = QtGui.QApplication([]) widget = terminal_widget(testing=123) widget.show() app.exec_() 
like image 108
ChrisB Avatar answered Oct 06 '22 01:10

ChrisB