将 Ipython 嵌入到 PyQt4 应用程序中
Posted
技术标签:
【中文标题】将 Ipython 嵌入到 PyQt4 应用程序中【英文标题】:Embedding Ipython into a PyQt4 App 【发布时间】:2013-05-24 14:26:12 【问题描述】:我将 Python 嵌入到 PyQt4 应用程序中,当时它处于 beta 阶段,并且只在 Ipython 的 git 分支上工作。我已经有一年左右没有看代码了,从那以后发生了很多变化——在 Ipython 中似乎有很多重构。我目前安装了 13.2
所以,我需要嵌入 Python,并且我需要它存在于我的 PyQt4 应用程序中,以便我可以使用来自我的 Python 应用程序的数据更改内核的 user_ns
。用于从 git 处理 python 版本的代码如下:
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()
那么,我需要进行哪些更改才能使其与当前 (13.2) 版本的 Ipython 一起工作?
编辑:
13.2 没有进程内内核功能。您仍然需要开发分支。驱使我问这个问题的不是我更新了我的开发分支,而是更新我机器上的 QT/PyQt4 使现有代码中断。我随后更新了 Ipython 开发版本,该版本要求我在 API 发生变化时重构我的代码。
【问题讨论】:
【参考方案1】:我走了同样的路,但最终使用了 IPython 开发,因为嵌入解决方案更干净,没有讨厌的 input()
/ help()
错误。
这是 0.13.x 的解决方法:https://***.com/a/12375397/532513 -- 问题是,例如,如果您使用 help()
,一切都会冻结。
在开发 IPython 中,一切都简单得多。这是一个工作示例:
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()
【讨论】:
这是正确的做法,因为 0.13.2 没有进程内模块。 这个code 运行。但是在运行代码时,我从 ipython 的 git 版本中获得了 errors 版本。有什么线索吗?我在 OS X 上并使用 QT (4.8.4) 和 PyQt4 (4.10.1)。 我看到了问题。您正在加载 PyQt4 API 版本 1(Python 2 上的默认值)。在没有 QT_API 环境变量的情况下,IPython 加载代码会尝试 PySide,然后是 PyQt4 API 版本 2。在您的情况下,它会找到 PyQt4 2,但这与您已经加载的 1 不匹配。要修复,请将您的 PyQt4 导入代码更改为以下内容: import sip; sip.setapi('QString', 2);从 PyQt4.QtGui 导入 QApplication 这适用于 1.1.0,但我认为最好链接到新的 example in the github tree。我在相关问题here中做了稍微详细一点的回答【参考方案2】:这是我制作并一直在使用 PyQt4 和 PySide 应用程序QIPythonWidget 的东西。我没有在 IPython 上做任何工作,我只是对它进行了破解,所以可能有更好的方法来做这件事,但这很有效,并且没有遇到问题。希望对您有所帮助。
【讨论】:
我发现这对于 IPython 0.13.1 来说是一种非常有用的方法,但不幸的是它不适用于较新的版本。 official example 适用于 IPython 1.1.0+。以上是关于将 Ipython 嵌入到 PyQt4 应用程序中的主要内容,如果未能解决你的问题,请参考以下文章
为啥 PyQt4 在 Jupyter 和 IPython 笔记本之间的行为不同?
在 PyQt4 的嵌入式 matplotlib 图中使用 ginput