##// END OF EJS Templates
First cut at safe appending in the Qt console.
First cut at safe appending in the Qt console.

File last commit:

r4039:b6c5bfb0
r4056:c438abc4
Show More
application.py
393 lines | 13.6 KiB | text/x-python | PythonLexer
Brian Granger
Created config.application and updated Configurable.
r3790 # encoding: utf-8
"""
A base class for a configurable application.
Authors:
* Brian Granger
MinRK
update recently changed modules with Authors in docstring
r4018 * Min RK
Brian Granger
Created config.application and updated Configurable.
r3790 """
#-----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Brian Granger
IPython.config.application.Application updates....
r3794 import logging
MinRK
default config files are automatically generated...
r4025 import os
MinRK
make subcommands optional
r3952 import re
Brian Granger
Created config.application and updated Configurable.
r3790 import sys
MinRK
default config files are automatically generated...
r4025 from copy import deepcopy
Brian Granger
Created config.application and updated Configurable.
r3790
Brian Granger
IPython.config.application.Application updates....
r3794 from IPython.config.configurable import SingletonConfigurable
Brian Granger
Created config.application and updated Configurable.
r3790 from IPython.config.loader import (
MinRK
print usage on invalid command-line arguments
r3951 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
Brian Granger
Created config.application and updated Configurable.
r3790 )
MinRK
move shortname to Application...
r3852 from IPython.utils.traitlets import (
MinRK
add subcommand support
r3949 Unicode, List, Int, Enum, Dict, Instance
MinRK
move shortname to Application...
r3852 )
MinRK
add subcommand support
r3949 from IPython.utils.importstring import import_item
MinRK
wrap helpstring output to 80 cols
r4020 from IPython.utils.text import indent, wrap_paragraphs, dedent
#-----------------------------------------------------------------------------
# function for re-wrapping a helpstring
#-----------------------------------------------------------------------------
MinRK
move shortname to Application...
r3852
Brian Granger
Created config.application and updated Configurable.
r3790 #-----------------------------------------------------------------------------
MinRK
include default value in help output...
r3944 # Descriptions for the various sections
MinRK
add descriptions for the various help sections
r3855 #-----------------------------------------------------------------------------
MinRK
rename macros/shortnames to flags/aliases...
r3861 flag_description = """
MinRK
add descriptions for the various help sections
r3855 Flags are command-line arguments passed as '--<flag>'.
These take no parameters, unlike regular key-value arguments.
They are typically used for setting boolean flags, or enabling
modes that involve setting multiple options together.
MinRK
wrap helpstring output to 80 cols
r4020
Flags *always* begin with '--', never just one '-'.
MinRK
add descriptions for the various help sections
r3855 """.strip() # trim newlines of front and back
MinRK
rename macros/shortnames to flags/aliases...
r3861 alias_description = """
MinRK
add descriptions for the various help sections
r3855 These are commonly set parameters, given abbreviated aliases for convenience.
They are set in the same `name=value` way as class parameters, where
<name> is replaced by the real parameter for which it is an alias.
""".strip() # trim newlines of front and back
keyvalue_description = """
Parameters are set from command-line arguments of the form:
`Class.trait=value`. Parameters will *never* be prefixed with '-'.
This line is evaluated in Python, so simple expressions are allowed, e.g.
`C.a='range(3)'` For setting C.a=[0,1,2]
""".strip() # trim newlines of front and back
#-----------------------------------------------------------------------------
Brian Granger
Created config.application and updated Configurable.
r3790 # Application class
#-----------------------------------------------------------------------------
Brian Granger
Updates to config/application.
r3940 class ApplicationError(Exception):
pass
Brian Granger
IPython.config.application.Application updates....
r3794 class Application(SingletonConfigurable):
Brian Granger
Adding more documentation to config.application related files.
r3796 """A singleton application with full configuration support."""
Brian Granger
Created config.application and updated Configurable.
r3790
# The name of the application, will usually match the name of the command
# line application
Brian Granger
Fixing bugs in BaseIPythonApplication....
r3942 name = Unicode(u'application')
Brian Granger
Created config.application and updated Configurable.
r3790
# The description of the application that is printed at the beginning
# of the help.
description = Unicode(u'This is an application.')
MinRK
add descriptions for the various help sections
r3855 # default section descriptions
MinRK
rename macros/shortnames to flags/aliases...
r3861 flag_description = Unicode(flag_description)
alias_description = Unicode(alias_description)
MinRK
add descriptions for the various help sections
r3855 keyvalue_description = Unicode(keyvalue_description)
Brian Granger
Created config.application and updated Configurable.
r3790
# A sequence of Configurable subclasses whose config=True attributes will
MinRK
rename macros/shortnames to flags/aliases...
r3861 # be exposed at the command line.
Brian Granger
Created config.application and updated Configurable.
r3790 classes = List([])
# The version string of this application.
version = Unicode(u'0.0')
Brian Granger
Added tests for IPython.config.application.Application
r3795 # The log level for the application
MinRK
default config files are automatically generated...
r4025 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
default_value=logging.WARN,
config=True,
help="Set the log level by value or name.")
def _log_level_changed(self, name, old, new):
MinRK
fix setting log_level by name in Application...
r4039 """Adjust the log level when log_level is set."""
MinRK
default config files are automatically generated...
r4025 if isinstance(new, basestring):
MinRK
fix setting log_level by name in Application...
r4039 new = getattr(logging, new)
self.log_level = new
self.log.setLevel(new)
MinRK
move shortname to Application...
r3852
MinRK
rename macros/shortnames to flags/aliases...
r3861 # the alias map for configurables
aliases = Dict(dict(log_level='Application.log_level'))
MinRK
move shortname to Application...
r3852
MinRK
rename macros/shortnames to flags/aliases...
r3861 # flags for loading Configurables or store_const style flags
# flags are loaded from this dict by '--key' flags
# this must be a dict of two-tuples, the first element being the Config/dict
# and the second being the help string for the flag
flags = Dict()
MinRK
wrap helpstring output to 80 cols
r4020 def _flags_changed(self, name, old, new):
"""ensure flags dict is valid"""
for key,value in new.iteritems():
assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
MinRK
move shortname to Application...
r3852
MinRK
add subcommand support
r3949 # subcommands for launching other applications
# if this is not empty, this will be a parent Application
MinRK
wrap helpstring output to 80 cols
r4020 # this must be a dict of two-tuples,
# the first element being the application class/import string
MinRK
add subcommand support
r3949 # and the second being the help string for the subcommand
subcommands = Dict()
# parse_command_line will initialize a subapp, if requested
subapp = Instance('IPython.config.application.Application', allow_none=True)
MinRK
allow extra_args in applications
r3958 # extra command-line arguments that don't set config values
extra_args = List(Unicode)
Brian Granger
IPython.config.application.Application updates....
r3794
Brian Granger
Created config.application and updated Configurable.
r3790 def __init__(self, **kwargs):
Brian Granger
IPython.config.application.Application updates....
r3794 SingletonConfigurable.__init__(self, **kwargs)
Brian Granger
Created config.application and updated Configurable.
r3790 # Add my class to self.classes so my attributes appear in command line
# options.
self.classes.insert(0, self.__class__)
MinRK
move shortname to Application...
r3852
Brian Granger
IPython.config.application.Application updates....
r3794 self.init_logging()
Brian Granger
Updates to config/application.
r3940
def _config_changed(self, name, old, new):
SingletonConfigurable._config_changed(self, name, old, new)
self.log.debug('Config changed:')
self.log.debug(repr(new))
Brian Granger
IPython.config.application.Application updates....
r3794 def init_logging(self):
"""Start logging for this application.
The default is to log to stdout using a StreaHandler. The log level
starts at loggin.WARN, but this can be adjusted by setting the
``log_level`` attribute.
"""
self.log = logging.getLogger(self.__class__.__name__)
self.log.setLevel(self.log_level)
self._log_handler = logging.StreamHandler()
self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
self._log_handler.setFormatter(self._log_formatter)
self.log.addHandler(self._log_handler)
MinRK
add subcommand support
r3949
def initialize(self, argv=None):
"""Do the basic steps to configure me.
Override in subclasses.
"""
self.parse_command_line(argv)
def start(self):
"""Start the app mainloop.
Override in subclasses.
"""
if self.subapp is not None:
return self.subapp.start()
MinRK
rename macros/shortnames to flags/aliases...
r3861 def print_alias_help(self):
MinRK
wrap helpstring output to 80 cols
r4020 """Print the alias part of the help."""
MinRK
rename macros/shortnames to flags/aliases...
r3861 if not self.aliases:
MinRK
move shortname to Application...
r3852 return
MinRK
include default value in help output...
r3944
lines = ['Aliases']
MinRK
add subcommand support
r3949 lines.append('-'*len(lines[0]))
MinRK
include default value in help output...
r3944 lines.append('')
MinRK
wrap helpstring output to 80 cols
r4020 for p in wrap_paragraphs(self.alias_description):
lines.append(p)
lines.append('')
MinRK
add descriptions for the various help sections
r3855
MinRK
move shortname to Application...
r3852 classdict = {}
MinRK
print usage on invalid command-line arguments
r3951 for cls in self.classes:
MinRK
make subcommands optional
r3952 # include all parents (up to, but excluding Configurable) in available names
for c in cls.mro()[:-3]:
MinRK
print usage on invalid command-line arguments
r3951 classdict[c.__name__] = c
MinRK
add descriptions for the various help sections
r3855
MinRK
rename macros/shortnames to flags/aliases...
r3861 for alias, longname in self.aliases.iteritems():
MinRK
move shortname to Application...
r3852 classname, traitname = longname.split('.',1)
cls = classdict[classname]
trait = cls.class_traits(config=True)[traitname]
MinRK
include default value in help output...
r3944 help = cls.class_get_trait_help(trait)
help = help.replace(longname, "%s (%s)"%(alias, longname), 1)
lines.append(help)
lines.append('')
print '\n'.join(lines)
MinRK
move shortname to Application...
r3852
MinRK
rename macros/shortnames to flags/aliases...
r3861 def print_flag_help(self):
MinRK
wrap helpstring output to 80 cols
r4020 """Print the flag part of the help."""
MinRK
rename macros/shortnames to flags/aliases...
r3861 if not self.flags:
MinRK
move shortname to Application...
r3852 return
MinRK
include default value in help output...
r3944 lines = ['Flags']
MinRK
add subcommand support
r3949 lines.append('-'*len(lines[0]))
MinRK
include default value in help output...
r3944 lines.append('')
MinRK
wrap helpstring output to 80 cols
r4020 for p in wrap_paragraphs(self.flag_description):
lines.append(p)
lines.append('')
MinRK
move shortname to Application...
r3852
MinRK
rename macros/shortnames to flags/aliases...
r3861 for m, (cfg,help) in self.flags.iteritems():
MinRK
include default value in help output...
r3944 lines.append('--'+m)
MinRK
wrap helpstring output to 80 cols
r4020 lines.append(indent(dedent(help.strip())))
MinRK
include default value in help output...
r3944 lines.append('')
print '\n'.join(lines)
MinRK
move shortname to Application...
r3852
MinRK
add subcommand support
r3949 def print_subcommands(self):
MinRK
wrap helpstring output to 80 cols
r4020 """Print the subcommand part of the help."""
MinRK
add subcommand support
r3949 if not self.subcommands:
return
lines = ["Subcommands"]
lines.append('-'*len(lines[0]))
MinRK
print usage on invalid command-line arguments
r3951 for subc, (cls,help) in self.subcommands.iteritems():
MinRK
add subcommand support
r3949 lines.append("%s : %s"%(subc, cls))
if help:
MinRK
wrap helpstring output to 80 cols
r4020 lines.append(indent(dedent(help.strip())))
MinRK
add subcommand support
r3949 lines.append('')
print '\n'.join(lines)
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 def print_help(self, classes=False):
"""Print the help for each Configurable class in self.classes.
MinRK
wrap helpstring output to 80 cols
r4020 If classes=False (the default), only flags and aliases are printed.
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 """
MinRK
make subcommands optional
r3952 self.print_subcommands()
MinRK
rename macros/shortnames to flags/aliases...
r3861 self.print_flag_help()
self.print_alias_help()
MinRK
include default value in help output...
r3944
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 if classes:
if self.classes:
print "Class parameters"
print "----------------"
print
MinRK
wrap helpstring output to 80 cols
r4020 for p in wrap_paragraphs(self.keyvalue_description):
print p
print
MinRK
add descriptions for the various help sections
r3855
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 for cls in self.classes:
cls.class_print_help()
print
else:
print "To see all available configurables, use `--help-all`"
Brian Granger
Created config.application and updated Configurable.
r3790 print
def print_description(self):
"""Print the application description."""
MinRK
wrap helpstring output to 80 cols
r4020 for p in wrap_paragraphs(self.description):
print p
print
Brian Granger
Created config.application and updated Configurable.
r3790
def print_version(self):
"""Print the version string."""
print self.version
def update_config(self, config):
Brian Granger
Adding more documentation to config.application related files.
r3796 """Fire the traits events when the config is updated."""
Brian Granger
Created config.application and updated Configurable.
r3790 # Save a copy of the current config.
newconfig = deepcopy(self.config)
# Merge the new config into the current one.
newconfig._merge(config)
# Save the combined config as self.config, which triggers the traits
# events.
Brian Granger
Fixing minor bug in config.application.
r3941 self.config = newconfig
MinRK
add subcommand support
r3949
def initialize_subcommand(self, subc, argv=None):
MinRK
wrap helpstring output to 80 cols
r4020 """Initialize a subcommand with argv."""
MinRK
allow extra_args in applications
r3958 subapp,help = self.subcommands.get(subc)
MinRK
print usage on invalid command-line arguments
r3951
MinRK
add subcommand support
r3949 if isinstance(subapp, basestring):
subapp = import_item(subapp)
MinRK
use App.instance() in Application.initialize_subapp...
r3962 # clear existing instances
self.__class__.clear_instance()
MinRK
add subcommand support
r3949 # instantiate
MinRK
use App.instance() in Application.initialize_subapp...
r3962 self.subapp = subapp.instance()
MinRK
add subcommand support
r3949 # and initialize subapp
self.subapp.initialize(argv)
Brian Granger
Created config.application and updated Configurable.
r3790 def parse_command_line(self, argv=None):
"""Parse the command line arguments."""
Brian Granger
Added tests for IPython.config.application.Application
r3795 argv = sys.argv[1:] if argv is None else argv
Brian Granger
Created config.application and updated Configurable.
r3790
MinRK
make subcommands optional
r3952 if self.subcommands and len(argv) > 0:
# we have subcommands, and one may have been specified
subc, subargv = argv[0], argv[1:]
MinRK
allow extra_args in applications
r3958 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
MinRK
make subcommands optional
r3952 # it's a subcommand, and *not* a flag or class parameter
return self.initialize_subcommand(subc, subargv)
MinRK
add subcommand support
r3949
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 if '-h' in argv or '--help' in argv or '--help-all' in argv:
Brian Granger
Created config.application and updated Configurable.
r3790 self.print_description()
MinRK
add `--help-all` flag, and don't print all configurables by default
r3946 self.print_help('--help-all' in argv)
MinRK
exit cleanly on help/version
r3945 self.exit(0)
Brian Granger
Created config.application and updated Configurable.
r3790
if '--version' in argv:
self.print_version()
MinRK
exit cleanly on help/version
r3945 self.exit(0)
MinRK
rename macros/shortnames to flags/aliases...
r3861
loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
flags=self.flags)
MinRK
print usage on invalid command-line arguments
r3951 try:
config = loader.load_config()
except ArgumentError as e:
self.log.fatal(str(e))
self.print_description()
self.print_help()
self.exit(1)
Brian Granger
Created config.application and updated Configurable.
r3790 self.update_config(config)
MinRK
allow extra_args in applications
r3958 # store unparsed args in extra_args
self.extra_args = loader.extra_args
Brian Granger
Created config.application and updated Configurable.
r3790
def load_config_file(self, filename, path=None):
"""Load a .py based config file by filename and path."""
loader = PyFileConfigLoader(filename, path=path)
config = loader.load_config()
self.update_config(config)
MinRK
default config files are automatically generated...
r4025
def generate_config_file(self):
"""generate default config file from Configurables"""
lines = ["# Configuration file for %s."%self.name]
lines.append('')
lines.append('c = get_config()')
lines.append('')
for cls in self.classes:
lines.append(cls.class_config_section())
return '\n'.join(lines)
Brian Granger
Created config.application and updated Configurable.
r3790
Brian Granger
Updates to config/application.
r3940 def exit(self, exit_status=0):
self.log.debug("Exiting application: %s" % self.name)
sys.exit(exit_status)
MinRK
include default value in help output...
r3944
#-----------------------------------------------------------------------------
# utility functions, for convenience
#-----------------------------------------------------------------------------
def boolean_flag(name, configurable, set_help='', unset_help=''):
MinRK
wrap helpstring output to 80 cols
r4020 """Helper for building basic --trait, --no-trait flags.
MinRK
include default value in help output...
r3944
Parameters
----------
name : str
The name of the flag.
configurable : str
The 'Class.trait' string of the trait to be set/unset with the flag
set_help : unicode
help string for --name flag
unset_help : unicode
help string for --no-name flag
Returns
-------
cfg : dict
A dict with two keys: 'name', and 'no-name', for setting and unsetting
the trait, respectively.
"""
# default helpstrings
set_help = set_help or "set %s=True"%configurable
unset_help = unset_help or "set %s=False"%configurable
cls,trait = configurable.split('.')
MinRK
prevent flags from clobbering entire config sections...
r3957 setter = {cls : {trait : True}}
unsetter = {cls : {trait : False}}
MinRK
include default value in help output...
r3944 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
MinRK
wrap helpstring output to 80 cols
r4020