Reputation: 10181
I'm creating a console driven Qt application using Python. Rather than implement my own custom console, I'd like to embed the IPython Qt console, but also make it responsive to my application. For instance, I would like certain keywords input to the console to trigger actions in my main application. So I type "dothis" in the console and in another window of my application a plot is displayed.
I've seen some questions along these lines: this one discusses how to embed an IPython Qt widget into your application and pass through functions, although it looks like these functions execute in the IPython kernel and not the kernel of my main app. There is also this guy, but I can't execute the code in the examples (it's two years old), and it doesn't look like it's doing what I want either.
Is there a way I can pass in functions or methods that will execute in my main kernel, or at least simulate this behavior somehow by communicating with the IPython kernel? Has anyone done this before?
Upvotes: 1
Views: 571
Reputation: 10181
This is what I came up with, and so far it is working pretty well. I subclass the RichIPythonWidget class and overload the _execute
method. Whenever the user types something into the console, I check it against a list of registered commands; if it matches a command, then I execute the command code, otherwise I just pass the input along to the default _execute
method.
Console Code:
from IPython.qt.console.rich_ipython_widget import RichIPythonWidget
class CommandConsole( RichIPythonWidget ):
"""
This is a thin wrapper around IPython's RichIPythonWidget. It's
main purpose is to register console commands and intercept
them when typed into the console.
"""
def __init__(self, *args, **kw ):
kw['kind'] = 'cc'
super(CommandConsole, self).__init__(*args, **kw)
self.commands = {}
def _execute(self, source, hidden):
"""
Overloaded version of the _execute first checks the console
input against registered commands. If it finds a command it
executes it, otherwise it passes the input to the back kernel
for processing.
"""
try:
possible_cmd = source.split()[0].strip()
except:
return super(CommandConsole, self)._execute("pass", hidden)
if possible_cmd in self.commands.keys():
# Commands return code that is passed to the console for execution.
s = self.commands[possible_cmd].execute()
return super(CommandConsole, self)._execute( s, hidden )
else:
# Default back to the original _execute
return super(CommandConsole, self)._execute(source, hidden)
def register_command( self, name, command ):
"""
This method links the name of a command (name) to the function
that should be called when it is typed into the console (command).
"""
self.commands[name] = command
Example Command:
from PyQt5.QtCore import pyqtSignal, QObject, QFile
class SelectCommand( QObject ):
"""
The Select command class.
"""
# This signal is emitted whenever the command is executed.
executed = pyqtSignal( str, dict, name = "selectExecuted" )
# This is the command as typed into the console.
name = "select"
def execute(self):
"""
This method is executed whenever the ``name`` command is issued
in the console.
"""
name = "data description"
data = { "data dict" : 0 }
# The signal is sent to my Qt Models
self.executed.emit( name, data )
# This code is executed in the console.
return 'print("the select command has been executed")'
Upvotes: 3