qtconsoleapp.py
559 lines
| 21.1 KiB
| text/x-python
|
PythonLexer
epatters
|
r2801 | """ A minimal application using the Qt console-style IPython frontend. | ||
MinRK
|
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 | ||||
MinRK
|
r5136 | * Bussonnier Matthias | ||
* Thomas Kluyver | ||||
MinRK
|
r4021 | |||
epatters
|
r2758 | """ | ||
epatters
|
r2961 | #----------------------------------------------------------------------------- | ||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r3971 | # stdlib imports | ||
MinRK
|
r4986 | import json | ||
MinRK
|
r3971 | import os | ||
import signal | ||||
import sys | ||||
MinRK
|
r5073 | import uuid | ||
MinRK
|
r3971 | |||
# System library imports | ||||
Evan Patterson
|
r3304 | from IPython.external.qt import QtGui | ||
epatters
|
r2758 | # Local imports | ||
MinRK
|
r5214 | from IPython.config.application import boolean_flag, catch_config_error | ||
MinRK
|
r4024 | from IPython.core.application import BaseIPythonApplication | ||
from IPython.core.profiledir import ProfileDir | ||||
MinRK
|
r4972 | from IPython.lib.kernel import tunnel_to_kernel, find_connection_file | ||
epatters
|
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
|
r3170 | from IPython.frontend.qt.console import styles | ||
MinRK
|
r5136 | from IPython.frontend.qt.console.mainwindow import MainWindow | ||
epatters
|
r2758 | from IPython.frontend.qt.kernelmanager import QtKernelManager | ||
MinRK
|
r4958 | from IPython.utils.path import filefind | ||
MinRK
|
r4967 | from IPython.utils.py3compat import str_to_bytes | ||
MinRK
|
r3971 | from IPython.utils.traitlets import ( | ||
MinRK
|
r5344 | Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any | ||
MinRK
|
r3971 | ) | ||
from IPython.zmq.ipkernel import ( | ||||
flags as ipkernel_flags, | ||||
aliases as ipkernel_aliases, | ||||
IPKernelApp | ||||
) | ||||
MinRK
|
r4962 | from IPython.zmq.session import Session, default_secure | ||
MinRK
|
r3971 | from IPython.zmq.zmqshell import ZMQInteractiveShell | ||
epatters
|
r2961 | #----------------------------------------------------------------------------- | ||
MinRK
|
r3144 | # Network Constants | ||
epatters
|
r2961 | #----------------------------------------------------------------------------- | ||
MinRK
|
r3144 | from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS | ||
epatters
|
r2823 | |||
epatters
|
r2961 | #----------------------------------------------------------------------------- | ||
Brian Granger
|
r4216 | # Globals | ||
#----------------------------------------------------------------------------- | ||||
_examples = """ | ||||
ipython qtconsole # start the qtconsole | ||||
ipython qtconsole --pylab=inline # start with pylab in inline plotting mode | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r3971 | # Aliases and Flags | ||
epatters
|
r2961 | #----------------------------------------------------------------------------- | ||
epatters
|
r2758 | |||
MinRK
|
r3971 | flags = dict(ipkernel_flags) | ||
MinRK
|
r4247 | qt_flags = { | ||
MinRK
|
r4958 | 'existing' : ({'IPythonQtConsoleApp' : {'existing' : 'kernel*.json'}}, | ||
"Connect to an existing kernel. If no argument specified, guess most recent"), | ||||
MinRK
|
r3971 | 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}}, | ||
"Use a pure Python kernel instead of an IPython kernel."), | ||||
'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}}, | ||||
"Disable rich text support."), | ||||
MinRK
|
r4247 | } | ||
qt_flags.update(boolean_flag( | ||||
MinRK
|
r3983 | 'gui-completion', 'ConsoleWidget.gui_completion', | ||
"use a GUI widget for tab completion", | ||||
"use plaintext output for completion" | ||||
)) | ||||
MinRK
|
r4247 | qt_flags.update(boolean_flag( | ||
MinRK
|
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
|
r4247 | flags.update(qt_flags) | ||
MinRK
|
r3971 | |||
aliases = dict(ipkernel_aliases) | ||||
MinRK
|
r4247 | qt_aliases = dict( | ||
MinRK
|
r3971 | hb = 'IPythonQtConsoleApp.hb_port', | ||
shell = 'IPythonQtConsoleApp.shell_port', | ||||
iopub = 'IPythonQtConsoleApp.iopub_port', | ||||
stdin = 'IPythonQtConsoleApp.stdin_port', | ||||
ip = 'IPythonQtConsoleApp.ip', | ||||
MinRK
|
r4958 | existing = 'IPythonQtConsoleApp.existing', | ||
f = 'IPythonQtConsoleApp.connection_file', | ||||
MinRK
|
r3971 | |||
style = 'IPythonWidget.syntax_style', | ||||
stylesheet = 'IPythonQtConsoleApp.stylesheet', | ||||
colors = 'ZMQInteractiveShell.colors', | ||||
editor = 'IPythonWidget.editor', | ||||
MinRK
|
r4222 | paging = 'ConsoleWidget.paging', | ||
MinRK
|
r4594 | ssh = 'IPythonQtConsoleApp.sshserver', | ||
MinRK
|
r4247 | ) | ||
aliases.update(qt_aliases) | ||||
MinRK
|
r4222 | |||
MinRK
|
r5136 | #----------------------------------------------------------------------------- | ||
# Classes | ||||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r3971 | |||
#----------------------------------------------------------------------------- | ||||
# IPythonQtConsole | ||||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r4215 | |||
MinRK
|
r3971 | class IPythonQtConsoleApp(BaseIPythonApplication): | ||
name = 'ipython-qtconsole' | ||||
default_config_file_name='ipython_config.py' | ||||
Matthias BUSSONNIER
|
r5060 | |||
MinRK
|
r4021 | description = """ | ||
The IPython QtConsole. | ||||
This launches a Console-style application using Qt. It is not a full | ||||
MinRK
|
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
|
r4021 | |||
MinRK
|
r4222 | as well as saving your session as HTML, and printing the output. | ||
MinRK
|
r4021 | |||
""" | ||||
Brian Granger
|
r4216 | examples = _examples | ||
Brian Granger
|
r4215 | |||
MinRK
|
r4015 | classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir, Session] | ||
MinRK
|
r3971 | flags = Dict(flags) | ||
aliases = Dict(aliases) | ||||
kernel_argv = List(Unicode) | ||||
MinRK
|
r4265 | # create requested profiles by default, if they don't exist: | ||
auto_create = CBool(True) | ||||
MinRK
|
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
|
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
|
r5344 | hb_port = Integer(0, config=True, | ||
MinRK
|
r3971 | help="set the heartbeat port [default: random]") | ||
MinRK
|
r5344 | shell_port = Integer(0, config=True, | ||
MinRK
|
r3971 | help="set the shell (XREP) port [default: random]") | ||
MinRK
|
r5344 | iopub_port = Integer(0, config=True, | ||
MinRK
|
r3971 | help="set the iopub (PUB) port [default: random]") | ||
MinRK
|
r5344 | stdin_port = Integer(0, config=True, | ||
MinRK
|
r3971 | help="set the stdin (XREQ) port [default: random]") | ||
MinRK
|
r4958 | connection_file = Unicode('', config=True, | ||
help="""JSON file in which to store connection info [default: kernel-<pid>.json] | ||||
MinRK
|
r3971 | |||
MinRK
|
r4958 | This file will contain the IP, ports, and authentication key needed to connect | ||
clients to this kernel. By default, this file will be created in the security-dir | ||||
of the current profile, but can be specified by absolute path. | ||||
""") | ||||
def _connection_file_default(self): | ||||
return 'kernel-%i.json' % os.getpid() | ||||
existing = Unicode('', config=True, | ||||
help="""Connect to an already running kernel""") | ||||
MinRK
|
r3971 | |||
stylesheet = Unicode('', config=True, | ||||
help="path to a custom CSS stylesheet") | ||||
MinRK
|
r3983 | pure = CBool(False, config=True, | ||
MinRK
|
r3971 | help="Use a pure Python kernel instead of an IPython kernel.") | ||
MinRK
|
r3983 | plain = CBool(False, config=True, | ||
MinRK
|
r3976 | help="Use a plaintext widget instead of rich text (plain can't print/save).") | ||
MinRK
|
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
|
r3173 | else: | ||
MinRK
|
r3971 | self.widget_factory = RichIPythonWidget | ||
_plain_changed = _pure_changed | ||||
MinRK
|
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
|
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
|
r4118 | # kernel should inherit default config file from frontend | ||
MinRK
|
r4197 | self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name) | ||
MinRK
|
r4957 | # Scrub frontend-specific flags | ||
swallow_next = False | ||||
MinRK
|
r5145 | was_flag = False | ||
# copy again, in case some aliases have the same name as a flag | ||||
# argv = list(self.kernel_argv) | ||||
MinRK
|
r4957 | for a in argv: | ||
if swallow_next: | ||||
swallow_next = False | ||||
MinRK
|
r5145 | # last arg was an alias, remove the next one | ||
# *unless* the last alias has a no-arg flag version, in which | ||||
# case, don't swallow the next arg if it's also a flag: | ||||
if not (was_flag and a.startswith('-')): | ||||
self.kernel_argv.remove(a) | ||||
continue | ||||
MinRK
|
r4247 | if a.startswith('-'): | ||
MinRK
|
r5015 | split = a.lstrip('-').split('=') | ||
MinRK
|
r4957 | alias = split[0] | ||
if alias in qt_aliases: | ||||
MinRK
|
r4247 | self.kernel_argv.remove(a) | ||
MinRK
|
r4957 | if len(split) == 1: | ||
# alias passed with arg via space | ||||
swallow_next = True | ||||
MinRK
|
r5145 | # could have been a flag that matches an alias, e.g. `existing` | ||
# in which case, we might not swallow the next arg | ||||
was_flag = alias in qt_flags | ||||
elif alias in qt_flags: | ||||
# strip flag, but don't swallow next, as flags don't take args | ||||
self.kernel_argv.remove(a) | ||||
MinRK
|
r4594 | |||
MinRK
|
r4958 | def init_connection_file(self): | ||
MinRK
|
r4969 | """find the connection file, and load the info if found. | ||
The current working directory and the current profile's security | ||||
directory will be searched for the file if it is not given by | ||||
absolute path. | ||||
When attempting to connect to an existing kernel and the `--existing` | ||||
argument does not match an existing file, it will be interpreted as a | ||||
fileglob, and the matching file in the current profile's security dir | ||||
with the latest access time will be used. | ||||
""" | ||||
MinRK
|
r4958 | if self.existing: | ||
try: | ||||
MinRK
|
r4972 | cf = find_connection_file(self.existing) | ||
except Exception: | ||||
self.log.critical("Could not find existing kernel connection file %s", self.existing) | ||||
self.exit(1) | ||||
MinRK
|
r4958 | self.log.info("Connecting to existing kernel: %s" % cf) | ||
self.connection_file = cf | ||||
# should load_connection_file only be used for existing? | ||||
# as it is now, this allows reusing ports if an existing | ||||
# file is requested | ||||
MinRK
|
r4986 | try: | ||
self.load_connection_file() | ||||
except Exception: | ||||
self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True) | ||||
self.exit(1) | ||||
MinRK
|
r4958 | |||
def load_connection_file(self): | ||||
"""load ip/port/hmac config from JSON connection file""" | ||||
# this is identical to KernelApp.load_connection_file | ||||
# perhaps it can be centralized somewhere? | ||||
try: | ||||
fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir]) | ||||
except IOError: | ||||
self.log.debug("Connection File not found: %s", self.connection_file) | ||||
return | ||||
self.log.debug(u"Loading connection file %s", fname) | ||||
with open(fname) as f: | ||||
s = f.read() | ||||
cfg = json.loads(s) | ||||
if self.ip == LOCALHOST and 'ip' in cfg: | ||||
# not overridden by config or cl_args | ||||
self.ip = cfg['ip'] | ||||
for channel in ('hb', 'shell', 'iopub', 'stdin'): | ||||
name = channel + '_port' | ||||
if getattr(self, name) == 0 and name in cfg: | ||||
# not overridden by config or cl_args | ||||
setattr(self, name, cfg[name]) | ||||
if 'key' in cfg: | ||||
MinRK
|
r4967 | self.config.Session.key = str_to_bytes(cfg['key']) | ||
MinRK
|
r4958 | |||
MinRK
|
r4594 | def init_ssh(self): | ||
MinRK
|
r4595 | """set up ssh tunnels, if needed.""" | ||
MinRK
|
r4594 | if not self.sshserver and not self.sshkey: | ||
return | ||||
if self.sshkey and not self.sshserver: | ||||
MinRK
|
r4971 | # specifying just the key implies that we are connecting directly | ||
MinRK
|
r4594 | self.sshserver = self.ip | ||
MinRK
|
r4971 | self.ip = LOCALHOST | ||
MinRK
|
r4594 | |||
MinRK
|
r4971 | # build connection dict for tunnels: | ||
info = dict(ip=self.ip, | ||||
shell_port=self.shell_port, | ||||
iopub_port=self.iopub_port, | ||||
stdin_port=self.stdin_port, | ||||
hb_port=self.hb_port | ||||
) | ||||
MinRK
|
r4594 | |||
MinRK
|
r4971 | self.log.info("Forwarding connections to %s via %s"%(self.ip, self.sshserver)) | ||
MinRK
|
r4594 | |||
MinRK
|
r4971 | # tunnels return a new set of ports, which will be on localhost: | ||
self.ip = LOCALHOST | ||||
try: | ||||
newports = tunnel_to_kernel(info, self.sshserver, self.sshkey) | ||||
except: | ||||
# even catch KeyboardInterrupt | ||||
self.log.error("Could not setup tunnels", exc_info=True) | ||||
self.exit(1) | ||||
MinRK
|
r4594 | |||
MinRK
|
r4971 | self.shell_port, self.iopub_port, self.stdin_port, self.hb_port = newports | ||
MinRK
|
r4594 | |||
MinRK
|
r4961 | cf = self.connection_file | ||
base,ext = os.path.splitext(cf) | ||||
base = os.path.basename(base) | ||||
self.connection_file = os.path.basename(base)+'-ssh'+ext | ||||
self.log.critical("To connect another client via this tunnel, use:") | ||||
self.log.critical("--existing %s" % self.connection_file) | ||||
MinRK
|
r5073 | |||
def _new_connection_file(self): | ||||
return os.path.join(self.profile_dir.security_dir, 'kernel-%s.json' % uuid.uuid4()) | ||||
Paul Ivanov
|
r4846 | |||
MinRK
|
r3971 | def init_kernel_manager(self): | ||
# Don't let Qt or ZMQ swallow KeyboardInterupts. | ||||
signal.signal(signal.SIGINT, signal.SIG_DFL) | ||||
MinRK
|
r4958 | sec = self.profile_dir.security_dir | ||
try: | ||||
cf = filefind(self.connection_file, ['.', sec]) | ||||
except IOError: | ||||
MinRK
|
r4969 | # file might not exist | ||
MinRK
|
r4958 | if self.connection_file == os.path.basename(self.connection_file): | ||
# just shortname, put it in security dir | ||||
cf = os.path.join(sec, self.connection_file) | ||||
else: | ||||
cf = self.connection_file | ||||
MinRK
|
r3971 | |||
# Create a KernelManager and start a kernel. | ||||
MinRK
|
r4958 | self.kernel_manager = QtKernelManager( | ||
ip=self.ip, | ||||
MinRK
|
r4956 | shell_port=self.shell_port, | ||
MinRK
|
r4959 | iopub_port=self.iopub_port, | ||
MinRK
|
r4956 | stdin_port=self.stdin_port, | ||
hb_port=self.hb_port, | ||||
MinRK
|
r4958 | connection_file=cf, | ||
MinRK
|
r4956 | config=self.config, | ||
MinRK
|
r3971 | ) | ||
# start the kernel | ||||
if not self.existing: | ||||
MinRK
|
r4958 | kwargs = dict(ipython=not self.pure) | ||
MinRK
|
r3971 | kwargs['extra_arguments'] = self.kernel_argv | ||
self.kernel_manager.start_kernel(**kwargs) | ||||
MinRK
|
r4961 | elif self.sshserver: | ||
# ssh, write new connection file | ||||
self.kernel_manager.write_connection_file() | ||||
MinRK
|
r3971 | self.kernel_manager.start_channels() | ||
MinRK
|
r5135 | def new_frontend_master(self): | ||
""" Create and return new frontend attached to new kernel, launched on localhost. | ||||
Matthias BUSSONNIER
|
r5039 | """ | ||
MinRK
|
r5073 | ip = self.ip if self.ip in LOCAL_IPS else LOCALHOST | ||
Matthias BUSSONNIER
|
r5035 | kernel_manager = QtKernelManager( | ||
MinRK
|
r5073 | ip=ip, | ||
connection_file=self._new_connection_file(), | ||||
config=self.config, | ||||
Matthias BUSSONNIER
|
r5035 | ) | ||
# start the kernel | ||||
MinRK
|
r5073 | kwargs = dict(ipython=not self.pure) | ||
Matthias BUSSONNIER
|
r5039 | kwargs['extra_arguments'] = self.kernel_argv | ||
kernel_manager.start_kernel(**kwargs) | ||||
Matthias BUSSONNIER
|
r5035 | kernel_manager.start_channels() | ||
widget = self.widget_factory(config=self.config, | ||||
MinRK
|
r5073 | local_kernel=True) | ||
Matthias BUSSONNIER
|
r5035 | widget.kernel_manager = kernel_manager | ||
MinRK
|
r5138 | widget._existing = False | ||
widget._may_close = True | ||||
widget._confirm_exit = self.confirm_exit | ||||
MinRK
|
r5135 | return widget | ||
def new_frontend_slave(self, current_widget): | ||||
"""Create and return a new frontend attached to an existing kernel. | ||||
Parameters | ||||
---------- | ||||
current_widget : IPythonWidget | ||||
The IPythonWidget whose kernel this frontend is to share | ||||
""" | ||||
Matthias BUSSONNIER
|
r5035 | kernel_manager = QtKernelManager( | ||
MinRK
|
r5073 | connection_file=current_widget.kernel_manager.connection_file, | ||
config = self.config, | ||||
Matthias BUSSONNIER
|
r5035 | ) | ||
MinRK
|
r5073 | kernel_manager.load_connection_file() | ||
Matthias BUSSONNIER
|
r5035 | kernel_manager.start_channels() | ||
widget = self.widget_factory(config=self.config, | ||||
MinRK
|
r5073 | local_kernel=False) | ||
MinRK
|
r5138 | widget._existing = True | ||
widget._may_close = False | ||||
widget._confirm_exit = False | ||||
Matthias BUSSONNIER
|
r5035 | widget.kernel_manager = kernel_manager | ||
MinRK
|
r5135 | return widget | ||
MinRK
|
r3971 | |||
def init_qt_elements(self): | ||||
# Create the widget. | ||||
self.app = QtGui.QApplication([]) | ||||
Matthias BUSSONNIER
|
r5053 | |||
base_path = os.path.abspath(os.path.dirname(__file__)) | ||||
icon_path = os.path.join(base_path, 'resources', 'icon', 'IPythonConsole.svg') | ||||
Matthias BUSSONNIER
|
r5055 | self.app.icon = QtGui.QIcon(icon_path) | ||
QtGui.QApplication.setWindowIcon(self.app.icon) | ||||
Matthias BUSSONNIER
|
r5028 | |||
MinRK
|
r3971 | local_kernel = (not self.existing) or self.ip in LOCAL_IPS | ||
self.widget = self.widget_factory(config=self.config, | ||||
local_kernel=local_kernel) | ||||
MinRK
|
r5138 | self.widget._existing = self.existing | ||
self.widget._may_close = not self.existing | ||||
self.widget._confirm_exit = self.confirm_exit | ||||
Matthias BUSSONNIER
|
r5038 | |||
MinRK
|
r3971 | self.widget.kernel_manager = self.kernel_manager | ||
MinRK
|
r5138 | self.window = MainWindow(self.app, | ||
MinRK
|
r5135 | confirm_exit=self.confirm_exit, | ||
new_frontend_factory=self.new_frontend_master, | ||||
slave_frontend_factory=self.new_frontend_slave, | ||||
) | ||||
Matthias BUSSONNIER
|
r5038 | self.window.log = self.log | ||
Matthias BUSSONNIER
|
r5051 | self.window.add_tab_with_frontend(self.widget) | ||
Matthias BUSSONNIER
|
r5052 | self.window.init_menu_bar() | ||
Matthias BUSSONNIER
|
r5393 | |||
Fernando Perez
|
r5489 | # we need to populate the 'Magic Menu' once the kernel has answer at | ||
# least once | ||||
######################################################################## | ||||
## TEMPORARILY DISABLED - see #1057 for details, uncomment the next | ||||
## line when a proper fix is found: | ||||
## self.kernel_manager.shell_channel.first_reply.connect(self.window.pop.trigger) | ||||
## END TEMPORARY FIX | ||||
######################################################################## | ||||
Matthias BUSSONNIER
|
r5393 | |||
MinRK
|
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: | ||||
MinRK
|
r5127 | style = self.config.IPythonWidget.syntax_style | ||
MinRK
|
r3971 | 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
|
r3173 | else: | ||
MinRK
|
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
|
r3170 | widget._syntax_style_changed() | ||
widget._style_sheet_changed() | ||||
MinRK
|
r3171 | elif colors: | ||
# use a default style | ||||
widget.set_default_style(colors=colors) | ||||
MinRK
|
r3170 | else: | ||
# this is redundant for now, but allows the widget's | ||||
# defaults to change | ||||
MinRK
|
r3171 | widget.set_default_style() | ||
MinRK
|
r3170 | |||
MinRK
|
r3971 | if self.stylesheet: | ||
MinRK
|
r3170 | # we got an expicit stylesheet | ||
MinRK
|
r3971 | if os.path.isfile(self.stylesheet): | ||
with open(self.stylesheet) as f: | ||||
MinRK
|
r3170 | sheet = f.read() | ||
widget.style_sheet = sheet | ||||
widget._style_sheet_changed() | ||||
else: | ||||
MinRK
|
r3971 | raise IOError("Stylesheet %r not found."%self.stylesheet) | ||
MinRK
|
r5214 | @catch_config_error | ||
MinRK
|
r3971 | def initialize(self, argv=None): | ||
super(IPythonQtConsoleApp, self).initialize(argv) | ||||
MinRK
|
r4958 | self.init_connection_file() | ||
MinRK
|
r4962 | default_secure(self.config) | ||
MinRK
|
r4961 | self.init_ssh() | ||
MinRK
|
r3971 | self.init_kernel_manager() | ||
self.init_qt_elements() | ||||
self.init_colors() | ||||
def start(self): | ||||
# draw the window | ||||
self.window.show() | ||||
MinRK
|
r3170 | |||
MinRK
|
r3971 | # Start the application main loop. | ||
self.app.exec_() | ||||
epatters
|
r2841 | |||
MinRK
|
r3971 | #----------------------------------------------------------------------------- | ||
# Main entry point | ||||
#----------------------------------------------------------------------------- | ||||
def main(): | ||||
app = IPythonQtConsoleApp() | ||||
app.initialize() | ||||
app.start() | ||||
epatters
|
r2758 | |||
if __name__ == '__main__': | ||||
main() | ||||