3

I got Python embedded into a PyQt4 app back when it was in the beta stages and only worked on a git branch of Ipython. I haven't looked at the code for a year or so, and a LOT has changed since then -- lots of refactoring it seems in Ipython. I currently have 13.2 installed

So, I need to embed Python, and I need it to exist within my PyQt4 app, so that I may alter the user_ns of the kernel with data from my Python App. The code that used to work against the python version from git is as follows :

import sys
sys.path.insert(0, "../../ipython") #pickup ipython from git in a nonstd dir

from IPython.embedded.ipkernel import EmbeddedKernel
from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.frontend.qt.embedded_kernelmanager import QtEmbeddedKernelManager
from IPython.lib import guisupport
from PyQt4.QtGui import QFrame,QHBoxLayout
from PyQt4.QtGui import QApplication
from collections import namedtuple



class IpythonEmbeddedWidget(QFrame):
    def __init__(self):
        QFrame.__init__(self)
        self._layout = QHBoxLayout()
        self._kernel = EmbeddedKernel()
        self._kernel_manager = QtEmbeddedKernelManager(kernel = self._kernel)
        self._kernel_manager.start_channels()
        self._kernel.frontends.append(self._kernel_manager)
        self._shell_widget = RichIPythonWidget()
        app = guisupport.get_app_qt4()
        self._shell_widget.exit_requested.connect(app.quit)
        self._shell_widget.kernel_manager = self._kernel_manager
        self._layout.addWidget(self._shell_widget)
        self.setLayout(self._layout)
        self._kernel.shell.run_cell("import nltk")
        self._kernel.shell.run_cell("import sys")
        self._kernel.shell.run_cell("sys.path.append('../ipython_scripts')")
        self._kernel.shell.run_cell("cd ../ipython_scripts")


    def set_shell_focus(self):
        pass

if __name__ == '__main__':
    app = QApplication(sys.argv)
    iew = IpythonEmbeddedWidget()
    iew.show()
    app.exec_()
    sys.exit()

So, What do I need to change to go to get it to work with the current (13.2) version of Ipython ?

edit:

13.2 does not have the inprocess-kernel functionality. You still need the development branch. What drove me to ask this question was not that I updated my development branch, but that updating QT/PyQt4 on my machine got the existing code to break. I subsequently updated the Ipython development version which required me to refactor my code as the API had changed.

Hassan Syed
  • 20,075
  • 11
  • 87
  • 171

2 Answers2

2

I went down the same path, but ended up using IPython dev as the embedding solution is cleaner and has no nasty input() / help() bugs.

Here is a work-around for 0.13.x: https://stackoverflow.com/a/12375397/532513 -- problem is, if you use help() for example, everything freezes.

In the development IPython, it's all much simpler. Here's a working example:

from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.frontend.qt.inprocess import QtInProcessKernelManager
from IPython.lib import guisupport
from PyQt4.QtGui import QApplication

app = QApplication(sys.argv)

kernel_manager = QtInProcessKernelManager()
kernel_manager.start_kernel()
kernel = kernel_manager.kernel
kernel.gui = 'qt4'

kernel_client = kernel_manager.client()
kernel_client.start_channels()

def stop():
    kernel_client.stop_channels()
    kernel_manager.shutdown_kernel()
    # here you should exit your application with a suitable call
    sys.exit()

widget = RichIPythonWidget()
widget.kernel_manager = kernel_manager
widget.kernel_client = kernel_client
widget.exit_requested.connect(stop)
widget.setWindowTitle("IPython shell")

ipython_widget = widget
ipython_widget.show()

app.exec_()
sys.exit()
Community
  • 1
  • 1
Charl Botha
  • 4,373
  • 34
  • 53
  • This is the right way to do it because 0.13.2 doesn't have the inprocess modules. – Carlos Cordoba May 25 '13 at 14:48
  • This [code](https://gist.github.com/hsyed/5662570) runs. But I am getting version [errors](https://gist.github.com/hsyed/5662297) from the git version of ipython when running the code. Any clues ? I am on OS X and using QT (4.8.4) and PyQt4 (4.10.1). – Hassan Syed May 28 '13 at 12:56
  • I see the problem. You are loading PyQt4 API version 1 (the default on Python 2). In the absence of the QT_API environment variable, the IPython loading code tries PySide and then PyQt4 API version 2. In your case it finds PyQt4 2, but this is a mismatch with the 1 that you've already loaded. To fix, change your PyQt4 import code to the following: import sip; sip.setapi('QString', 2); from PyQt4.QtGui import QApplication – Charl Botha May 29 '13 at 09:44
  • This works in 1.1.0, but I think it's better to link to the new [example in the github tree](https://github.com/ipython/ipython/blob/master/examples/inprocess/embedded_qtconsole.py). I've made a slightly more detailed answer in the related question [here](http://stackoverflow.com/questions/11513132/embedding-ipython-qt-console-in-a-pyqt-application/20610786#20610786) – Tim Rae Dec 16 '13 at 18:54
0

Here's something that I've made and have been using with both PyQt4 and PySide apps QIPythonWidget. I don't do any work on IPython, I just hacked away at it so there is probably a better way of doing it but this works and haven't ran into problems with it. Hope it helps.

Jeff
  • 6,932
  • 7
  • 42
  • 72
  • 1
    I found this to be a very useful way to do it for IPython 0.13.1, but unfortunately it doesn't work with newer versions. The [official example](https://github.com/ipython/ipython/blob/master/examples/inprocess/embedded_qtconsole.py) works well with IPython 1.1.0+. – Tim Rae Dec 16 '13 at 12:00