Browse files

QtConsole now uses newapp

  • Loading branch information...
1 parent 048514e commit 259c3855de04fce0656004fddeed124f44bdf789 @minrk committed Jun 1, 2011
View
54 IPython/frontend/qt/console/console_widget.py
@@ -55,33 +55,39 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
#------ Configuration ------------------------------------------------------
- # Whether to process ANSI escape codes.
- ansi_codes = Bool(True, config=True)
-
- # The maximum number of lines of text before truncation. Specifying a
- # non-positive number disables text truncation (not recommended).
- buffer_size = Int(500, config=True)
-
- # Whether to use a list widget or plain text output for tab completion.
- gui_completion = Bool(False, config=True)
-
- # The type of underlying text widget to use. Valid values are 'plain', which
- # specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
+ ansi_codes = Bool(True, config=True,
+ help="Whether to process ANSI escape codes."
+ )
+ buffer_size = Int(500, config=True,
+ help="""
+ The maximum number of lines of text before truncation. Specifying a
+ non-positive number disables text truncation (not recommended).
+ """
+ )
+ gui_completion = Bool(False, config=True,
+ help="Use a list widget instead of plain text output for tab completion."
+ )
# NOTE: this value can only be specified during initialization.
- kind = Enum(['plain', 'rich'], default_value='plain', config=True)
-
- # The type of paging to use. Valid values are:
- # 'inside' : The widget pages like a traditional terminal.
- # 'hsplit' : When paging is requested, the widget is split
- # horizontally. The top pane contains the console, and the
- # bottom pane contains the paged text.
- # 'vsplit' : Similar to 'hsplit', except that a vertical splitter used.
- # 'custom' : No action is taken by the widget beyond emitting a
- # 'custom_page_requested(str)' signal.
- # 'none' : The text is written directly to the console.
+ kind = Enum(['plain', 'rich'], default_value='plain', config=True,
+ help="""
+ The type of underlying text widget to use. Valid values are 'plain', which
+ specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
+ """
+ )
# NOTE: this value can only be specified during initialization.
paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'],
- default_value='inside', config=True)
+ default_value='inside', config=True,
+ help="""
+ The type of paging to use. Valid values are:
+ 'inside' : The widget pages like a traditional terminal.
+ 'hsplit' : When paging is requested, the widget is split
+ : horizontally. The top pane contains the console, and the
+ : bottom pane contains the paged text.
+ 'vsplit' : Similar to 'hsplit', except that a vertical splitter used.
+ 'custom' : No action is taken by the widget beyond emitting a
+ : 'custom_page_requested(str)' signal.
+ 'none' : The text is written directly to the console.
+ """)
# Whether to override ShortcutEvents for the keybindings defined by this
# widget (Ctrl+n, Ctrl+a, etc). Enable this if you want this widget to take
View
3 IPython/frontend/qt/console/frontend_widget.py
@@ -13,7 +13,7 @@
from IPython.core.inputsplitter import InputSplitter, transform_classic_prompt
from IPython.core.oinspect import call_tip
from IPython.frontend.qt.base_frontend_mixin import BaseFrontendMixin
-from IPython.utils.traitlets import Bool
+from IPython.utils.traitlets import Bool, Instance
from bracket_matcher import BracketMatcher
from call_tip_widget import CallTipWidget
from completion_lexer import CompletionLexer
@@ -106,6 +106,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
_ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
_input_splitter_class = InputSplitter
_local_kernel = False
+ _highlighter = Instance(FrontendHighlighter)
#---------------------------------------------------------------------------
# 'object' interface
View
67 IPython/frontend/qt/console/ipython_widget.py
@@ -23,9 +23,7 @@
from IPython.core.usage import default_gui_banner
from IPython.utils.traitlets import Bool, Str, Unicode
from frontend_widget import FrontendWidget
-from styles import (default_light_style_sheet, default_light_syntax_style,
- default_dark_style_sheet, default_dark_syntax_style,
- default_bw_style_sheet, default_bw_syntax_style)
+import styles
#-----------------------------------------------------------------------------
# Constants
@@ -56,26 +54,35 @@ class IPythonWidget(FrontendWidget):
custom_edit = Bool(False)
custom_edit_requested = QtCore.Signal(object, object)
- # A command for invoking a system text editor. If the string contains a
- # {filename} format specifier, it will be used. Otherwise, the filename will
- # be appended to the end the command.
- editor = Unicode('default', config=True)
-
- # The editor command to use when a specific line number is requested. The
- # string should contain two format specifiers: {line} and {filename}. If
- # this parameter is not specified, the line number option to the %edit magic
- # will be ignored.
- editor_line = Unicode(config=True)
-
- # A CSS stylesheet. The stylesheet can contain classes for:
- # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
- # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
- # 3. IPython: .error, .in-prompt, .out-prompt, etc
- style_sheet = Unicode(config=True)
+ editor = Unicode('default', config=True,
+ help="""
+ A command for invoking a system text editor. If the string contains a
+ {filename} format specifier, it will be used. Otherwise, the filename will
+ be appended to the end the command.
+ """)
+
+ editor_line = Unicode(config=True,
+ help="""
+ The editor command to use when a specific line number is requested. The
+ string should contain two format specifiers: {line} and {filename}. If
+ this parameter is not specified, the line number option to the %edit magic
+ will be ignored.
+ """)
+
+ style_sheet = Unicode(config=True,
+ help="""
+ A CSS stylesheet. The stylesheet can contain classes for:
+ 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
+ 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
+ 3. IPython: .error, .in-prompt, .out-prompt, etc
+ """)
- # If not empty, use this Pygments style for syntax highlighting. Otherwise,
- # the style sheet is queried for Pygments style information.
- syntax_style = Str(config=True)
+
+ syntax_style = Str(config=True,
+ help="""
+ If not empty, use this Pygments style for syntax highlighting. Otherwise,
+ the style sheet is queried for Pygments style information.
+ """)
# Prompts.
in_prompt = Str(default_in_prompt, config=True)
@@ -373,14 +380,14 @@ def set_default_style(self, colors='lightbg'):
"""
colors = colors.lower()
if colors=='lightbg':
- self.style_sheet = default_light_style_sheet
- self.syntax_style = default_light_syntax_style
+ self.style_sheet = styles.default_light_style_sheet
+ self.syntax_style = styles.default_light_syntax_style
elif colors=='linux':
- self.style_sheet = default_dark_style_sheet
- self.syntax_style = default_dark_syntax_style
+ self.style_sheet = styles.default_dark_style_sheet
+ self.syntax_style = styles.default_dark_syntax_style
elif colors=='nocolor':
- self.style_sheet = default_bw_style_sheet
- self.syntax_style = default_bw_syntax_style
+ self.style_sheet = styles.default_bw_style_sheet
+ self.syntax_style = styles.default_bw_syntax_style
else:
raise KeyError("No such color scheme: %s"%colors)
@@ -486,9 +493,13 @@ def _style_sheet_changed(self):
bg_color = self._control.palette().window().color()
self._ansi_processor.set_background_color(bg_color)
+
def _syntax_style_changed(self):
""" Set the style for the syntax highlighter.
"""
+ if self._highlighter is None:
+ # ignore premature calls
+ return
if self.syntax_style:
self._highlighter.set_style(self.syntax_style)
else:
View
348 IPython/frontend/qt/console/ipythonqt.py
@@ -5,17 +5,32 @@
# Imports
#-----------------------------------------------------------------------------
-# Systemm library imports
+# stdlib imports
+import os
+import signal
+import sys
+
+# System library imports
from IPython.external.qt import QtGui
from pygments.styles import get_all_styles
# Local imports
-from IPython.external.argparse import ArgumentParser
+from IPython.core.newapplication import ProfileDir, BaseIPythonApplication
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
from IPython.frontend.qt.console import styles
from IPython.frontend.qt.kernelmanager import QtKernelManager
+from IPython.utils.traitlets import (
+ Dict, List, Unicode, Int, CaselessStrEnum, Bool, Any
+)
+from IPython.zmq.ipkernel import (
+ flags as ipkernel_flags,
+ aliases as ipkernel_aliases,
+ IPKernelApp
+)
+from IPython.zmq.zmqshell import ZMQInteractiveShell
+
#-----------------------------------------------------------------------------
# Network Constants
@@ -127,126 +142,188 @@ def closeEvent(self, event):
event.accept()
#-----------------------------------------------------------------------------
-# Main entry point
+# Aliases and Flags
#-----------------------------------------------------------------------------
-def main():
- """ Entry point for application.
- """
- # Parse command line arguments.
- parser = ArgumentParser()
- kgroup = parser.add_argument_group('kernel options')
- kgroup.add_argument('-e', '--existing', action='store_true',
- help='connect to an existing kernel')
- kgroup.add_argument('--ip', type=str, default=LOCALHOST,
- 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!")
- kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
- help='set the XREQ channel port [default random]')
- kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
- help='set the SUB channel port [default random]')
- kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
- help='set the REP channel port [default random]')
- kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
- help='set the heartbeat port [default random]')
-
- egroup = kgroup.add_mutually_exclusive_group()
- egroup.add_argument('--pure', action='store_true', help = \
- 'use a pure Python kernel instead of an IPython kernel')
- egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
- const='auto', help = \
- "Pre-load matplotlib and numpy for interactive use. If GUI is not \
- given, the GUI backend is matplotlib's, otherwise use one of: \
- ['tk', 'gtk', 'qt', 'wx', 'inline'].")
-
- wgroup = parser.add_argument_group('widget options')
- wgroup.add_argument('--paging', type=str, default='inside',
- choices = ['inside', 'hsplit', 'vsplit', 'none'],
- help='set the paging style [default inside]')
- wgroup.add_argument('--plain', action='store_true',
- help='disable rich text support')
- wgroup.add_argument('--gui-completion', action='store_true',
- help='use a GUI widget for tab completion')
- wgroup.add_argument('--style', type=str,
- choices = list(get_all_styles()),
- help='specify a pygments style for by name')
- wgroup.add_argument('--stylesheet', type=str,
- help='path to a custom CSS stylesheet')
- wgroup.add_argument('--colors', type=str, help = \
- "Set the color scheme (LightBG,Linux,NoColor). This is guessed \
- based on the pygments style if not set.")
-
- args = parser.parse_args()
-
- # parse the colors arg down to current known labels
- if args.colors:
- colors=args.colors.lower()
- if colors in ('lightbg', 'light'):
- colors='lightbg'
- elif colors in ('dark', 'linux'):
- colors='linux'
- else:
- colors='nocolor'
- elif args.style:
- if args.style=='bw':
- colors='nocolor'
- elif styles.dark_style(args.style):
- colors='linux'
+flags = dict(ipkernel_flags)
+
+flags.update({
+ '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."),
+ 'gui-completion' : ({'FrontendWidget' : {'gui_completion' : True}},
+ "use a GUI widget for tab completion"),
+})
+
+qt_flags = ['existing', 'pure', 'plain', 'gui-completion']
+
+aliases = dict(ipkernel_aliases)
+
+aliases.update(dict(
+ hb = 'IPythonQtConsoleApp.hb_port',
+ shell = 'IPythonQtConsoleApp.shell_port',
+ iopub = 'IPythonQtConsoleApp.iopub_port',
+ stdin = 'IPythonQtConsoleApp.stdin_port',
+ ip = 'IPythonQtConsoleApp.ip',
+
+ plain = 'IPythonQtConsoleApp.plain',
+ pure = 'IPythonQtConsoleApp.pure',
+ gui_completion = 'FrontendWidget.gui_completion',
+ style = 'IPythonWidget.syntax_style',
+ stylesheet = 'IPythonQtConsoleApp.stylesheet',
+ colors = 'ZMQInteractiveShell.colors',
+
+ editor = 'IPythonWidget.editor',
+ pi = 'IPythonWidget.in_prompt',
+ po = 'IPythonWidget.out_prompt',
+ si = 'IPythonWidget.input_sep',
+ so = 'IPythonWidget.output_sep',
+ so2 = 'IPythonWidget.output_sep2',
+))
+
+#-----------------------------------------------------------------------------
+# IPythonQtConsole
+#-----------------------------------------------------------------------------
+
+class IPythonQtConsoleApp(BaseIPythonApplication):
+ name = 'ipython-qtconsole'
+ default_config_file_name='ipython_config.py'
+ classes = [IPKernelApp, IPythonWidget, ZMQInteractiveShell, ProfileDir]
+ flags = Dict(flags)
+ aliases = Dict(aliases)
+
+ kernel_argv = List(Unicode)
+
+ # 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!"""
+ )
+ 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]")
+
+ existing = Bool(False, config=True,
+ help="Whether to connect to an already running Kernel.")
+
+ stylesheet = Unicode('', config=True,
+ help="path to a custom CSS stylesheet")
+
+ pure = Bool(False, config=True,
+ help="Use a pure Python kernel instead of an IPython kernel.")
+ plain = Bool(False, config=True,
+ help="Use a pure Python kernel instead of an IPython kernel.")
+
+ 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
else:
- colors='lightbg'
- else:
- colors=None
-
- # Don't let Qt or ZMQ swallow KeyboardInterupts.
- import signal
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
- # Create a KernelManager and start a kernel.
- kernel_manager = QtKernelManager(xreq_address=(args.ip, args.xreq),
- sub_address=(args.ip, args.sub),
- rep_address=(args.ip, args.rep),
- hb_address=(args.ip, args.hb))
- if not args.existing:
- # if not args.ip in LOCAL_IPS+ALL_ALIAS:
- # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
-
- kwargs = dict(ip=args.ip)
- if args.pure:
- kwargs['ipython']=False
+ self.widget_factory = RichIPythonWidget
+
+ _plain_changed = _pure_changed
+
+ # 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
+
+ # scrub frontend-specific flags
+ for a in argv:
+ if a.startswith('--') and a[2:] in qt_flags:
+ self.kernel_argv.remove(a)
+
+ 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(
+ xreq_address=(self.ip, self.shell_port),
+ sub_address=(self.ip, self.iopub_port),
+ rep_address=(self.ip, self.stdin_port),
+ hb_address=(self.ip, self.hb_port)
+ )
+ # 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,
+ may_close=local_kernel)
+ 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'
else:
- extra = []
- if colors:
- extra.append("colors=%s"%colors)
- if args.pylab:
- extra.append("pylab=%s"%args.pylab)
- kwargs['extra_arguments'] = extra
-
- kernel_manager.start_kernel(**kwargs)
- kernel_manager.start_channels()
-
- # Create the widget.
- app = QtGui.QApplication([])
- local_kernel = (not args.existing) or args.ip in LOCAL_IPS
- if args.pure:
- kind = 'plain' if args.plain else 'rich'
- widget = FrontendWidget(kind=kind, paging=args.paging,
- local_kernel=local_kernel)
- elif args.plain:
- widget = IPythonWidget(paging=args.paging, local_kernel=local_kernel)
- else:
- widget = RichIPythonWidget(paging=args.paging,
- local_kernel=local_kernel)
- widget.gui_completion = args.gui_completion
- widget.kernel_manager = kernel_manager
-
- # Configure the style.
- if not args.pure: # only IPythonWidget supports styles
- if args.style:
- widget.syntax_style = args.style
- widget.style_sheet = styles.sheet_from_template(args.style, colors)
+ colors=None
+
+ # Configure the style.
+ widget = self.widget
+ if style:
+ widget.style_sheet = styles.sheet_from_template(style, colors)
+ widget.syntax_style = style
widget._syntax_style_changed()
widget._style_sheet_changed()
elif colors:
@@ -257,23 +334,38 @@ def main():
# defaults to change
widget.set_default_style()
- if args.stylesheet:
+ if self.stylesheet:
# we got an expicit stylesheet
- if os.path.isfile(args.stylesheet):
- with open(args.stylesheet) as f:
+ if os.path.isfile(self.stylesheet):
+ with open(self.stylesheet) as f:
sheet = f.read()
widget.style_sheet = sheet
widget._style_sheet_changed()
else:
- raise IOError("Stylesheet %r not found."%args.stylesheet)
+ raise IOError("Stylesheet %r not found."%self.stylesheet)
+
+ def initialize(self, argv=None):
+ super(IPythonQtConsoleApp, self).initialize(argv)
+ self.init_kernel_manager()
+ self.init_qt_elements()
+ self.init_colors()
+
+ def start(self):
+
+ # draw the window
+ self.window.show()
- # Create the main window.
- window = MainWindow(app, widget, args.existing, may_close=local_kernel)
- window.setWindowTitle('Python' if args.pure else 'IPython')
- window.show()
+ # Start the application main loop.
+ self.app.exec_()
- # Start the application main loop.
- app.exec_()
+#-----------------------------------------------------------------------------
+# Main entry point
+#-----------------------------------------------------------------------------
+
+def main():
+ app = IPythonQtConsoleApp()
+ app.initialize()
+ app.start()
if __name__ == '__main__':

0 comments on commit 259c385

Please sign in to comment.