首页 > 解决方案 > 从 iPython / Jupyter 嵌入式 Qt 控制台获取结果对象

问题描述

我在使用此处RichJupyterWidget提供的小部件实现的 PyQt5 应用程序中有一个嵌入式 Jupyter 控制台。

控制台集成本身工作正常,Jupyter 控制台嵌入在一个小部件中,可以执行 Python 代码,结果显示在控制台本身内。

然而,我需要做的是,每当我运行一些返回 Pandas 的代码时,都会 在控制台外部DataFrame显示它。TableView

这是我的实现的一个工作示例:

import sys

from PyQt5.QtWidgets import QMainWindow, QApplication
from qtconsole.inprocess import QtInProcessKernelManager
from qtconsole.rich_jupyter_widget import RichJupyterWidget


class IPythonConsole:

    def __init__(self):
        self._kernel_manager = None
        self._kernel = None
        self._kernel_client = None

        self.start()

    @property
    def kernel_manager(self) -> QtInProcessKernelManager:
        return self._kernel_manager

    @property
    def kernel(self):
        return self._kernel

    @property
    def kernel_client(self):
        return self._kernel_client

    def start(self):
        self._kernel_manager = QtInProcessKernelManager()
        self._kernel_manager.start_kernel()
        self._kernel = self._kernel_manager.kernel
        self._kernel.gui = 'qt'

        self._kernel_client = self._kernel_manager.client()
        self._kernel_client.start_channels()

    def stop(self):
        self._kernel_client.stop_channels()
        self._kernel_manager.shutdown_kernel()


class IPythonWidget(RichJupyterWidget):
    """RichIPythonWidget implementation to integrate the IPython console inside a Qt Widget"""

    def __init__(self):
        super().__init__()

        self._console = IPythonConsole()
        self.kernel_manager = self._console.kernel_manager
        self.kernel_client = self._console.kernel_client

    @property
    def console(self):
        return self._console

    def run_command(self, command_str):
        self.execute(command_str, False, True)

    def close(self):
        self._console.stop()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    main_window = QMainWindow()
    ipython_widget = IPythonWidget()
    main_window.layout().addWidget(ipython_widget)
    main_window.setFixedHeight(768)
    main_window.setFixedWidth(1024)

    ipython_widget.run_command("import pandas as pd\n"
                               "df = pd.DataFrame({'Test': ['a', 'b', 'c']})\n"
                               "df")

    main_window.show()

    sys.exit(app.exec_())

到目前为止,我试图覆盖以下方法RichJupyterWidget

 def _handle_execute_result(self, msg):
        """Overridden to handle rich data types, like SVG."""
        self.log.debug("execute_result: %s", msg.get('content', ''))
        if self.include_output(msg):
            self.flush_clearoutput()
            content = msg['content']
            prompt_number = content.get('execution_count', 0)
            data = content['data']
            metadata = msg['content']['metadata']
            if 'image/svg+xml' in data:
                self._pre_image_append(msg, prompt_number)
                self._append_svg(data['image/svg+xml'], True)
                self._append_html(self.output_sep2, True)
            elif 'image/png' in data:
            [...]

但不幸的是,当返回 a 时DataFrame, msg 包含一个带有DataFrameHTML 格式内容的字符串。

编辑

我能够DataFrame从内核外壳中获取对象,如下所示:

if self.ipython_widget.execute("df = pd.DataFrame({'Test': ['a', 'b', 'c']})\n", False, False):
    df = self.ipython_widget.console.kernel.shell.user_ns.get('df')

不幸的是,这只会在我自己运行代码时起作用,而不是当用户在控制台中输入内容时,而且我必须知道包含数据框的变量的名称。

标签: pythonpython-3.xpyqt5jupyterjupyter-console

解决方案


推荐阅读