简体   繁体   中英

embedding ipython qtconsole and passing objects

I want to put an ipython qtconsole in an MDI pyqt application as a subwindow, and then create other subwindows from the qtconsole. So the embedded qtconsole needs to be able to access the namespace of the application. According to this page from the ipython docs, an InProcessKernel would be the best solution. I ran this example script (reproduced below) from a python terminal (if I run it from ipython, I get a MultipleInstanceError). But forget about creating subwindows for now, first I need to figure out how to pass objects into the embedded qtconsole.

  1. The first time I run inprocess_qtconsole.py, the embedded qtconsole's namespace is empty. Why do objects previously created in the initial python terminal, or in the script, not get passed to the embedded qtconsole?
  2. If I close the application containing the embedded qtconsole, define some variables in the initial terminal, and run the script again, why can I now access these variables, as well as the ones from the script under if __name__ == __main__ ?
  3. Is there a way to start the embedded qtconsole without blocking the python terminal that I started it from?

I mostly just want to be able to pass the QMainWindow instance into the embedded qtconsole, because creating subwindows requires passing this object (something like window.mdiArea.addSubWindow() ). It sort of works in a hackish way if I run the script twice.

By the way, the internal_ipkernel module used in one of the other official ipython examples (ipkernel_qtapp.py) seems to be missing from the latest versions of ipython.

Running Python 2.7, IPython 2.2/2.3 and Windows 8.1.

from __future__ import print_function
import os

from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.qt.inprocess import QtInProcessKernelManager
from IPython.lib import guisupport


def print_process_id():
    print('Process ID is:', os.getpid())


def main():
    # Print the ID of the main process
    print_process_id()

    app = guisupport.get_app_qt4()

    # Create an in-process kernel
    # >>> print_process_id()
    # will print the same process ID as the main process
    kernel_manager = QtInProcessKernelManager()
    kernel_manager.start_kernel()
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'
    kernel.shell.push({'foo': 43, 'print_process_id': print_process_id})

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

    def stop():
        kernel_client.stop_channels()
        kernel_manager.shutdown_kernel()
        app.exit()

    control = RichIPythonWidget()
    control.kernel_manager = kernel_manager
    control.kernel_client = kernel_client
    control.exit_requested.connect(stop)
    control.show()

    guisupport.start_event_loop_qt4(app)


if __name__ == '__main__':
    test = 'hello'
    main()

You can use this to start an ipython console in a given qt widget:

from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.qt.inprocess import QtInProcessKernelManager

def put_ipy(parent):
    kernel_manager = QtInProcessKernelManager()
    kernel_manager.start_kernel()
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'

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

    def stop():
        kernel_client.stop_channels()
        kernel_manager.shutdown_kernel()

    layout = QtGui.QVBoxLayout(parent)
    widget = RichIPythonWidget(parent=parent)
    layout.addWidget(widget)
    widget.kernel_manager = kernel_manager
    widget.kernel_client = kernel_client
    widget.exit_requested.connect(stop)
    ipython_widget = widget
    ipython_widget.show()
    kernel.shell.push({'widget':widget,'kernel':kernel, 'parent':parent})
    return {'widget':widget,'kernel':kernel}

To pop up windows from the console, you can run

app = QtGui.QApplication([])
win = QtGui.QWidget(None)
win.show()
put_ipy(win)

but this will swap the original python interpreter with an empty ipy one, with only the variables defined that you passed (widget, kernel, parent here), ie, both the console and the command line have the same kernels, and the original one is blocked.

You can get around such behaviour by doing the above within a qt application with another main window and set of interactions. To pass variables to the kernel, use (as above) kernel.shell.push(dict) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM