##// END OF EJS Templates
Merge pull request #762 from jdmarch/jdmarch-755-execute-file-hack...
Merge pull request #762 from jdmarch/jdmarch-755-execute-file-hack qtconsole ipython widget's execute_file fails if filename contains spaces or quotes

File last commit:

r4595:34eefb9b
r4775:af8cee08 merge
Show More
qtconsoleapp.py
484 lines | 17.8 KiB | text/x-python | PythonLexer
epatters
Created a proper IPython script from the console frontend demo.
r2801 """ A minimal application using the Qt console-style IPython frontend.
MinRK
code updates per review of PR #454
r4021
This is not a complete console app, as subprocess will not be able to receive
input, there is no real readline support, among other limitations.
Authors:
* Evan Patterson
* Min RK
* Erik Tollerud
* Fernando Perez
epatters
* The SVG payload matplotlib backend now works....
r2758 """
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 #-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
MinRK
QtConsole now uses newapp
r3971 # stdlib imports
import os
import signal
import sys
MinRK
add ssh tunnel support to qtconsole
r4594 from getpass import getpass
MinRK
QtConsole now uses newapp
r3971
# System library imports
Evan Patterson
Paved the way for PySide support....
r3304 from IPython.external.qt import QtGui
MinRK
exposed pygments styles as ipythonqt options
r3170 from pygments.styles import get_all_styles
Evan Patterson
Paved the way for PySide support....
r3304
MinRK
Remove IPython dependency in external.ssh...
r4595 # external imports
from IPython.external.ssh import tunnel
epatters
* The SVG payload matplotlib backend now works....
r2758 # Local imports
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 from IPython.config.application import boolean_flag
MinRK
move ipcluster create|list to `ipython profile create|list`...
r4024 from IPython.core.application import BaseIPythonApplication
from IPython.core.profiledir import ProfileDir
epatters
Created a proper IPython script from the console frontend demo.
r2801 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
from IPython.frontend.qt.console.ipython_widget import IPythonWidget
from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
MinRK
exposed pygments styles as ipythonqt options
r3170 from IPython.frontend.qt.console import styles
epatters
* The SVG payload matplotlib backend now works....
r2758 from IPython.frontend.qt.kernelmanager import QtKernelManager
MinRK
add ssh tunnel support to qtconsole
r4594 from IPython.parallel.util import select_random_ports
MinRK
QtConsole now uses newapp
r3971 from IPython.utils.traitlets import (
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
MinRK
QtConsole now uses newapp
r3971 )
from IPython.zmq.ipkernel import (
flags as ipkernel_flags,
aliases as ipkernel_aliases,
IPKernelApp
)
MinRK
finish plumbing config to Session objects...
r4015 from IPython.zmq.session import Session
MinRK
QtConsole now uses newapp
r3971 from IPython.zmq.zmqshell import ZMQInteractiveShell
epatters
* The SVG payload matplotlib backend now works....
r2758
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 #-----------------------------------------------------------------------------
MinRK
Possible fix for GH-169
r3144 # Network Constants
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 #-----------------------------------------------------------------------------
MinRK
Possible fix for GH-169
r3144 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
epatters
Added arguments to the Qt console frontend script for connecting to an existing kernel and for specifying an IP and specific ports.
r2823
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 #-----------------------------------------------------------------------------
Brian Granger
More work on adding examples to help strings.
r4216 # Globals
#-----------------------------------------------------------------------------
_examples = """
ipython qtconsole # start the qtconsole
ipython qtconsole --pylab=inline # start with pylab in inline plotting mode
"""
#-----------------------------------------------------------------------------
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 # Classes
#-----------------------------------------------------------------------------
class MainWindow(QtGui.QMainWindow):
#---------------------------------------------------------------------------
# 'object' interface
#---------------------------------------------------------------------------
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 def __init__(self, app, frontend, existing=False, may_close=True,
confirm_exit=True):
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 """ Create a MainWindow for the specified FrontendWidget.
MinRK
review fixes
r3100
MinRK
comment/doc logic cleanup
r3105 The app is passed as an argument to allow for different
closing behavior depending on whether we are the Kernel's parent.
MinRK
prevent remote frontends from closing the kernel
r3142 If existing is True, then this Console does not own the Kernel.
If may_close is True, then this Console is permitted to close the kernel
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 """
super(MainWindow, self).__init__()
MinRK
changed close Console behavior to leave Kernel alive
r3104 self._app = app
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 self._frontend = frontend
MinRK
added shutdown notification handling to ipythonqt
r3090 self._existing = existing
MinRK
Possible fix for GH-169
r3144 if existing:
MinRK
prevent remote frontends from closing the kernel
r3142 self._may_close = may_close
else:
self._may_close = True
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 self._frontend.exit_requested.connect(self.close)
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 self._confirm_exit = confirm_exit
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 self.setCentralWidget(frontend)
#---------------------------------------------------------------------------
# QWidget interface
#---------------------------------------------------------------------------
def closeEvent(self, event):
Erik Tollerud
docstring fix in CloseEvent to conform to standards
r3190 """ Close the window and the kernel (if necessary).
This will prompt the user if they are finished with the kernel, and if
so, closes the kernel cleanly. Alternatively, if the exit magic is used,
it closes without prompt.
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 """
Erik Tollerud
__builtin__.exit and quit are now hidden - exit magic is now the only exit command
r3185 keepkernel = None #Use the prompt by default
if hasattr(self._frontend,'_keep_kernel_on_exit'): #set by exit magic
keepkernel = self._frontend._keep_kernel_on_exit
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 kernel_manager = self._frontend.kernel_manager
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 if keepkernel is None and not self._confirm_exit:
# don't prompt, just terminate the kernel if we own it
# or leave it alone if we don't
keepkernel = not self._existing
Erik Tollerud
__builtin__.exit and quit are now hidden - exit magic is now the only exit command
r3185 if keepkernel is None: #show prompt
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183 if kernel_manager and kernel_manager.channels_running:
title = self.window().windowTitle()
cancel = QtGui.QMessageBox.Cancel
okay = QtGui.QMessageBox.Ok
if self._may_close:
msg = "You are closing this Console window."
info = "Would you like to quit the Kernel and all attached Consoles as well?"
justthis = QtGui.QPushButton("&No, just this Console", self)
justthis.setShortcut('N')
closeall = QtGui.QPushButton("&Yes, quit everything", self)
closeall.setShortcut('Y')
Evan Patterson
Paved the way for PySide support....
r3304 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
title, msg)
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183 box.setInformativeText(info)
box.addButton(cancel)
box.addButton(justthis, QtGui.QMessageBox.NoRole)
box.addButton(closeall, QtGui.QMessageBox.YesRole)
box.setDefaultButton(closeall)
box.setEscapeButton(cancel)
reply = box.exec_()
if reply == 1: # close All
kernel_manager.shutdown_kernel()
#kernel_manager.stop_channels()
event.accept()
elif reply == 0: # close Console
if not self._existing:
# Have kernel: don't quit, just close the window
self._app.setQuitOnLastWindowClosed(False)
self.deleteLater()
event.accept()
else:
event.ignore()
MinRK
prevent remote frontends from closing the kernel
r3142 else:
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183 reply = QtGui.QMessageBox.question(self, title,
"Are you sure you want to close this Console?"+
"\nThe Kernel and other Consoles will remain active.",
okay|cancel,
defaultButton=okay
)
if reply == okay:
event.accept()
else:
event.ignore()
Erik Tollerud
__builtin__.exit and quit are now hidden - exit magic is now the only exit command
r3185 elif keepkernel: #close console but leave kernel running (no prompt)
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183 if kernel_manager and kernel_manager.channels_running:
if not self._existing:
# I have the kernel: don't quit, just close the window
self._app.setQuitOnLastWindowClosed(False)
event.accept()
Erik Tollerud
__builtin__.exit and quit are now hidden - exit magic is now the only exit command
r3185 else: #close console and kernel (no prompt)
Erik Tollerud
Expanded %exit magic in qtconsole to not exit without prompting and...
r3183 if kernel_manager and kernel_manager.channels_running:
kernel_manager.shutdown_kernel()
event.accept()
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961
#-----------------------------------------------------------------------------
MinRK
QtConsole now uses newapp
r3971 # Aliases and Flags
epatters
* Moved shutdown_kernel method from FrontendWidget to KernelManager....
r2961 #-----------------------------------------------------------------------------
epatters
* The SVG payload matplotlib backend now works....
r2758
MinRK
QtConsole now uses newapp
r3971 flags = dict(ipkernel_flags)
MinRK
command-line pass...
r4247 qt_flags = {
MinRK
QtConsole now uses newapp
r3971 'existing' : ({'IPythonQtConsoleApp' : {'existing' : True}},
"Connect to an existing kernel."),
'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}},
"Use a pure Python kernel instead of an IPython kernel."),
'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}},
"Disable rich text support."),
MinRK
command-line pass...
r4247 }
qt_flags.update(boolean_flag(
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 'gui-completion', 'ConsoleWidget.gui_completion',
"use a GUI widget for tab completion",
"use plaintext output for completion"
))
MinRK
command-line pass...
r4247 qt_flags.update(boolean_flag(
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 'confirm-exit', 'IPythonQtConsoleApp.confirm_exit',
"""Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
to force a direct exit without any confirmation.
""",
"""Don't prompt the user when exiting. This will terminate the kernel
if it is owned by the frontend, and leave it alive if it is external.
"""
))
MinRK
command-line pass...
r4247 flags.update(qt_flags)
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 # the flags that are specific to the frontend
# these must be scrubbed before being passed to the kernel,
# or it will raise an error on unrecognized flags
MinRK
command-line pass...
r4247 qt_flags = qt_flags.keys()
MinRK
QtConsole now uses newapp
r3971
aliases = dict(ipkernel_aliases)
MinRK
command-line pass...
r4247 qt_aliases = dict(
MinRK
QtConsole now uses newapp
r3971 hb = 'IPythonQtConsoleApp.hb_port',
shell = 'IPythonQtConsoleApp.shell_port',
iopub = 'IPythonQtConsoleApp.iopub_port',
stdin = 'IPythonQtConsoleApp.stdin_port',
ip = 'IPythonQtConsoleApp.ip',
style = 'IPythonWidget.syntax_style',
stylesheet = 'IPythonQtConsoleApp.stylesheet',
colors = 'ZMQInteractiveShell.colors',
editor = 'IPythonWidget.editor',
MinRK
fix qtconsole description...
r4222 paging = 'ConsoleWidget.paging',
MinRK
add ssh tunnel support to qtconsole
r4594 ssh = 'IPythonQtConsoleApp.sshserver',
MinRK
command-line pass...
r4247 )
aliases.update(qt_aliases)
# also scrub aliases from the frontend
qt_flags.extend(qt_aliases.keys())
MinRK
fix qtconsole description...
r4222
MinRK
QtConsole now uses newapp
r3971
#-----------------------------------------------------------------------------
# IPythonQtConsole
#-----------------------------------------------------------------------------
Brian Granger
Command line examples added for non-parallel apps.
r4215
MinRK
QtConsole now uses newapp
r3971 class IPythonQtConsoleApp(BaseIPythonApplication):
name = 'ipython-qtconsole'
default_config_file_name='ipython_config.py'
MinRK
code updates per review of PR #454
r4021
description = """
The IPython QtConsole.
This launches a Console-style application using Qt. It is not a full
MinRK
fix qtconsole description...
r4222 console, in that launched terminal subprocesses will not be able to accept
input.
The QtConsole supports various extra features beyond the Terminal IPython
shell, such as inline plotting with matplotlib, via:
ipython qtconsole --pylab=inline
MinRK
code updates per review of PR #454
r4021
MinRK
fix qtconsole description...
r4222 as well as saving your session as HTML, and printing the output.
MinRK
code updates per review of PR #454
r4021
"""
Brian Granger
More work on adding examples to help strings.
r4216 examples = _examples
Brian Granger
Command line examples added for non-parallel apps.
r4215
MinRK
finish plumbing config to Session objects...
r4015 classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session]
MinRK
QtConsole now uses newapp
r3971 flags = Dict(flags)
aliases = Dict(aliases)
kernel_argv = List(Unicode)
MinRK
create missing profiles by default in qtconsole...
r4265 # create requested profiles by default, if they don't exist:
auto_create = CBool(True)
MinRK
QtConsole now uses newapp
r3971 # connection info:
ip = Unicode(LOCALHOST, config=True,
help="""Set the kernel\'s IP address [default localhost].
If the IP address is something other than localhost, then
Consoles on other machines will be able to connect
to the Kernel, so be careful!"""
)
MinRK
add ssh tunnel support to qtconsole
r4594
sshserver = Unicode('', config=True,
help="""The SSH server to use to connect to the kernel.""")
sshkey = Unicode('', config=True,
help="""Path to the ssh key to use for logging in to the ssh server.""")
MinRK
QtConsole now uses newapp
r3971 hb_port = Int(0, config=True,
help="set the heartbeat port [default: random]")
shell_port = Int(0, config=True,
help="set the shell (XREP) port [default: random]")
iopub_port = Int(0, config=True,
help="set the iopub (PUB) port [default: random]")
stdin_port = Int(0, config=True,
help="set the stdin (XREQ) port [default: random]")
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 existing = CBool(False, config=True,
MinRK
QtConsole now uses newapp
r3971 help="Whether to connect to an already running Kernel.")
stylesheet = Unicode('', config=True,
help="path to a custom CSS stylesheet")
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 pure = CBool(False, config=True,
MinRK
QtConsole now uses newapp
r3971 help="Use a pure Python kernel instead of an IPython kernel.")
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 plain = CBool(False, config=True,
MinRK
update docs/default config for qtconsole
r3976 help="Use a plaintext widget instead of rich text (plain can't print/save).")
MinRK
QtConsole now uses newapp
r3971
def _pure_changed(self, name, old, new):
kind = 'plain' if self.plain else 'rich'
self.config.ConsoleWidget.kind = kind
if self.pure:
self.widget_factory = FrontendWidget
elif self.plain:
self.widget_factory = IPythonWidget
MinRK
color settings from ipythonqt propagate down to the ZMQInteractiveShell in the Kernel
r3173 else:
MinRK
QtConsole now uses newapp
r3971 self.widget_factory = RichIPythonWidget
_plain_changed = _pure_changed
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 confirm_exit = CBool(True, config=True,
help="""
Set to display confirmation dialog on exit. You can always use 'exit' or 'quit',
to force a direct exit without any confirmation.""",
)
MinRK
QtConsole now uses newapp
r3971 # the factory for creating a widget
widget_factory = Any(RichIPythonWidget)
def parse_command_line(self, argv=None):
super(IPythonQtConsoleApp, self).parse_command_line(argv)
if argv is None:
argv = sys.argv[1:]
self.kernel_argv = list(argv) # copy
MinRK
add config file inheritance to kernelapp...
r4118 # kernel should inherit default config file from frontend
MinRK
disallow no-prefix `ipython foo=bar` argument style....
r4197 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
MinRK
QtConsole now uses newapp
r3971 # scrub frontend-specific flags
for a in argv:
MinRK
command-line pass...
r4247
if a.startswith('-'):
key = a.lstrip('-').split('=')[0]
if key in qt_flags:
self.kernel_argv.remove(a)
MinRK
add ssh tunnel support to qtconsole
r4594
def init_ssh(self):
MinRK
Remove IPython dependency in external.ssh...
r4595 """set up ssh tunnels, if needed."""
MinRK
add ssh tunnel support to qtconsole
r4594 if not self.sshserver and not self.sshkey:
return
if self.sshkey and not self.sshserver:
self.sshserver = self.ip
self.ip=LOCALHOST
lports = select_random_ports(4)
rports = self.shell_port, self.iopub_port, self.stdin_port, self.hb_port
self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = lports
remote_ip = self.ip
self.ip = LOCALHOST
self.log.info("Forwarding connections to %s via %s"%(remote_ip, self.sshserver))
if tunnel.try_passwordless_ssh(self.sshserver, self.sshkey):
password=False
else:
password = getpass("SSH Password for %s: "%self.sshserver)
for lp,rp in zip(lports, rports):
tunnel.ssh_tunnel(lp, rp, self.sshserver, remote_ip, self.sshkey, password)
MinRK
QtConsole now uses newapp
r3971 def init_kernel_manager(self):
# Don't let Qt or ZMQ swallow KeyboardInterupts.
signal.signal(signal.SIGINT, signal.SIG_DFL)
# Create a KernelManager and start a kernel.
self.kernel_manager = QtKernelManager(
MinRK
cleanup channel names to match function not socket...
r3974 shell_address=(self.ip, self.shell_port),
MinRK
QtConsole now uses newapp
r3971 sub_address=(self.ip, self.iopub_port),
MinRK
cleanup channel names to match function not socket...
r3974 stdin_address=(self.ip, self.stdin_port),
MinRK
finish plumbing config to Session objects...
r4015 hb_address=(self.ip, self.hb_port),
config=self.config
MinRK
QtConsole now uses newapp
r3971 )
# start the kernel
if not self.existing:
kwargs = dict(ip=self.ip, ipython=not self.pure)
kwargs['extra_arguments'] = self.kernel_argv
self.kernel_manager.start_kernel(**kwargs)
self.kernel_manager.start_channels()
def init_qt_elements(self):
# Create the widget.
self.app = QtGui.QApplication([])
local_kernel = (not self.existing) or self.ip in LOCAL_IPS
self.widget = self.widget_factory(config=self.config,
local_kernel=local_kernel)
self.widget.kernel_manager = self.kernel_manager
self.window = MainWindow(self.app, self.widget, self.existing,
MinRK
add confirm_exit option to qtconsole to suppress exit dialog
r3983 may_close=local_kernel,
confirm_exit=self.confirm_exit)
MinRK
QtConsole now uses newapp
r3971 self.window.setWindowTitle('Python' if self.pure else 'IPython')
def init_colors(self):
"""Configure the coloring of the widget"""
# Note: This will be dramatically simplified when colors
# are removed from the backend.
if self.pure:
# only IPythonWidget supports styling
return
# parse the colors arg down to current known labels
try:
colors = self.config.ZMQInteractiveShell.colors
except AttributeError:
colors = None
try:
style = self.config.IPythonWidget.colors
except AttributeError:
style = None
# find the value for colors:
if colors:
colors=colors.lower()
if colors in ('lightbg', 'light'):
colors='lightbg'
elif colors in ('dark', 'linux'):
colors='linux'
else:
colors='nocolor'
elif style:
if style=='bw':
colors='nocolor'
elif styles.dark_style(style):
colors='linux'
else:
colors='lightbg'
MinRK
color settings from ipythonqt propagate down to the ZMQInteractiveShell in the Kernel
r3173 else:
MinRK
QtConsole now uses newapp
r3971 colors=None
# Configure the style.
widget = self.widget
if style:
widget.style_sheet = styles.sheet_from_template(style, colors)
widget.syntax_style = style
MinRK
exposed pygments styles as ipythonqt options
r3170 widget._syntax_style_changed()
widget._style_sheet_changed()
MinRK
added --colors flag to ipythonqt
r3171 elif colors:
# use a default style
widget.set_default_style(colors=colors)
MinRK
exposed pygments styles as ipythonqt options
r3170 else:
# this is redundant for now, but allows the widget's
# defaults to change
MinRK
added --colors flag to ipythonqt
r3171 widget.set_default_style()
MinRK
exposed pygments styles as ipythonqt options
r3170
MinRK
QtConsole now uses newapp
r3971 if self.stylesheet:
MinRK
exposed pygments styles as ipythonqt options
r3170 # we got an expicit stylesheet
MinRK
QtConsole now uses newapp
r3971 if os.path.isfile(self.stylesheet):
with open(self.stylesheet) as f:
MinRK
exposed pygments styles as ipythonqt options
r3170 sheet = f.read()
widget.style_sheet = sheet
widget._style_sheet_changed()
else:
MinRK
QtConsole now uses newapp
r3971 raise IOError("Stylesheet %r not found."%self.stylesheet)
def initialize(self, argv=None):
super(IPythonQtConsoleApp, self).initialize(argv)
MinRK
add ssh tunnel support to qtconsole
r4594 self.init_ssh()
MinRK
QtConsole now uses newapp
r3971 self.init_kernel_manager()
self.init_qt_elements()
self.init_colors()
def start(self):
# draw the window
self.window.show()
MinRK
exposed pygments styles as ipythonqt options
r3170
MinRK
QtConsole now uses newapp
r3971 # Start the application main loop.
self.app.exec_()
epatters
* Tab completion now uses the correct cursor position....
r2841
MinRK
QtConsole now uses newapp
r3971 #-----------------------------------------------------------------------------
# Main entry point
#-----------------------------------------------------------------------------
def main():
app = IPythonQtConsoleApp()
app.initialize()
app.start()
epatters
* The SVG payload matplotlib backend now works....
r2758
if __name__ == '__main__':
main()