ipykernel
ipykernel copied to clipboard
Update embedding examples
The internal_ipkernel.py and ipkernel_qtapp.py are out of date. Some issues:
- It is using
PyQt4, which is very old, and not supported on some platforms (e.g.osx-arm64) - Explicit use of PyQt means it doesn't work with PySide. Should use qtpy so it will work with Pyside2/6 or PyQt5/6.
- This line:
from IPython.lib.kernel import connect_qtconsolefails on recent ipythons. I think the replacement isfrom ipykernel import connect_qtconsole. See https://github.com/ipython/ipython/issues/13610 - The
connectcalls also would need to be updated (I think those are the old style signals).
FWIW something like this works:
#!/usr/bin/env python
"""Example integrating an IPython kernel into a GUI App.
This trivial GUI application internally starts an IPython kernel, to which Qt
consoles can be connected either by the user at the command line or started
from the GUI itself, via a button. The GUI can also manipulate one variable in
the kernel's namespace, and print the namespace to the console.
Play with it by running the script and then opening one or more consoles, and
pushing the 'Counter++' and 'Namespace' buttons.
Upon exit, it should automatically close all consoles opened from the GUI.
Consoles attached separately from a terminal will not be terminated, though
they will notice that their kernel died.
"""
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import sys
import PySide6
from PySide6.QtWidgets import *
from ipykernel import connect_qtconsole
from ipykernel.kernelapp import IPKernelApp
# -----------------------------------------------------------------------------
# Functions and classes
# -----------------------------------------------------------------------------
class InternalIPKernel:
"""An internal ipykernel class."""
def init_ipkernel(self, backend):
"""Start IPython kernel with GUI event loop and mpl support."""
self.ipkernel = IPKernelApp.instance()
self.ipkernel.initialize(
[
"python",
"--matplotlib=qt",
#'--log-level=10'
]
)
# To create and track active qt consoles
self.consoles = []
# This application will also act on the shell user namespace
self.namespace = self.ipkernel.shell.user_ns
# Example: a variable that will be seen by the user in the shell, and
# that the GUI modifies (the 'Counter++' button increments it):
self.namespace["app_counter"] = 0
# self.namespace['ipkernel'] = self.ipkernel # dbg
def print_namespace(self, evt=None):
"""Print the namespace."""
print("\n***Variables in User namespace***")
for k, v in self.namespace.items():
if not k.startswith("_"):
print(f"{k} -> {v!r}")
sys.stdout.flush()
def new_qt_console(self, evt=None):
"""start a new qtconsole connected to our kernel"""
self.consoles.append(connect_qtconsole(self.ipkernel.abs_connection_file))
return self.consoles[-1]
def count(self, evt=None):
"""Get the app counter value."""
self.namespace["app_counter"] += 1
def cleanup_consoles(self, evt=None):
"""Clean up the consoles."""
for c in self.consoles:
c.kill()
self.consoles.clear()
class SimpleWindow(QWidget, InternalIPKernel):
"""A custom Qt widget for IPykernel."""
def __init__(self, app):
"""Initialize the widget."""
QWidget.__init__(self)
self.app = app
self.init_ipkernel("qt")
self.add_widgets()
def add_widgets(self):
"""Add the widget."""
self.setGeometry(300, 300, 400, 70)
self.setWindowTitle("IPython in your app")
# Add simple buttons:
console = QPushButton("Qt Console", self)
console.setGeometry(10, 10, 100, 35)
console.clicked.connect(self.new_qt_console)
namespace = QPushButton("Namespace", self)
namespace.setGeometry(120, 10, 100, 35)
namespace.clicked.connect(self.print_namespace)
count = QPushButton("Count++", self)
count.setGeometry(230, 10, 80, 35)
count.clicked.connect(self.count)
# Quit and cleanup
quit = QPushButton("Quit", self)
quit.setGeometry(320, 10, 60, 35)
quit.clicked.connect(self.ipkernel.kernel.do_shutdown)
self.app.lastWindowClosed.connect(self.ipkernel.kernel.do_shutdown)
self.app.aboutToQuit.connect(self.cleanup_consoles)
# -----------------------------------------------------------------------------
# Main script
# -----------------------------------------------------------------------------
if __name__ == "__main__":
app = QApplication([])
# Create our window
win = SimpleWindow(app)
win.show()
# Very important, IPython-specific step: this gets GUI event loop
# integration going, and it replaces calling app.exec_()
win.ipkernel.start()