##// END OF EJS Templates
Remove print statements in ZMQ parent pollers....
Remove print statements in ZMQ parent pollers. These statements were originally inserted for debugging purposes. However, if the parent process owns the child's stdout and the parent dies, the print statements will deadlock, preventing the poller from terminating its process and thereby utterly breaking it.

File last commit:

r3861:e957fe67
r3933:650cb93a
Show More
application.py
230 lines | 7.9 KiB | text/x-python | PythonLexer
# encoding: utf-8
"""
A base class for a configurable application.
Authors:
* Brian Granger
"""
#-----------------------------------------------------------------------------
# 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
#-----------------------------------------------------------------------------
from copy import deepcopy
import logging
import sys
from IPython.config.configurable import SingletonConfigurable
from IPython.config.loader import (
KeyValueConfigLoader, PyFileConfigLoader, Config
)
from IPython.utils.traitlets import (
Unicode, List, Int, Enum, Dict
)
from IPython.utils.text import indent
#-----------------------------------------------------------------------------
# Descriptions for
#-----------------------------------------------------------------------------
flag_description = """
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.
""".strip() # trim newlines of front and back
alias_description = """
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
#-----------------------------------------------------------------------------
# Application class
#-----------------------------------------------------------------------------
class Application(SingletonConfigurable):
"""A singleton application with full configuration support."""
# The name of the application, will usually match the name of the command
# line application
app_name = Unicode(u'application')
# The description of the application that is printed at the beginning
# of the help.
description = Unicode(u'This is an application.')
# default section descriptions
flag_description = Unicode(flag_description)
alias_description = Unicode(alias_description)
keyvalue_description = Unicode(keyvalue_description)
# A sequence of Configurable subclasses whose config=True attributes will
# be exposed at the command line.
classes = List([])
# The version string of this application.
version = Unicode(u'0.0')
# The log level for the application
log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN,
config=True,
help="Set the log level (0,10,20,30,40,50).")
# the alias map for configurables
aliases = Dict(dict(log_level='Application.log_level'))
# 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()
def __init__(self, **kwargs):
SingletonConfigurable.__init__(self, **kwargs)
# Add my class to self.classes so my attributes appear in command line
# options.
self.classes.insert(0, self.__class__)
# ensure self.flags dict is valid
for key,value in self.flags.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)
self.init_logging()
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)
def _log_level_changed(self, name, old, new):
"""Adjust the log level when log_level is set."""
self.log.setLevel(new)
def print_alias_help(self):
"""print the alias part of the help"""
if not self.aliases:
return
print "Aliases"
print "-------"
print self.alias_description
print
classdict = {}
for c in self.classes:
classdict[c.__name__] = c
for alias, longname in self.aliases.iteritems():
classname, traitname = longname.split('.',1)
cls = classdict[classname]
trait = cls.class_traits(config=True)[traitname]
help = trait.get_metadata('help')
print alias, "(%s)"%longname, ':', trait.__class__.__name__
if help:
print indent(help)
print
def print_flag_help(self):
"""print the flag part of the help"""
if not self.flags:
return
print "Flags"
print "-----"
print self.flag_description
print
for m, (cfg,help) in self.flags.iteritems():
print '--'+m
print indent(help)
print
def print_help(self):
"""Print the help for each Configurable class in self.classes."""
self.print_flag_help()
self.print_alias_help()
if self.classes:
print "Class parameters"
print "----------------"
print self.keyvalue_description
print
for cls in self.classes:
cls.class_print_help()
print
def print_description(self):
"""Print the application description."""
print self.description
print
def print_version(self):
"""Print the version string."""
print self.version
def update_config(self, config):
"""Fire the traits events when the config is updated."""
# 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.
self.config = config
def parse_command_line(self, argv=None):
"""Parse the command line arguments."""
argv = sys.argv[1:] if argv is None else argv
if '-h' in argv or '--help' in argv:
self.print_description()
self.print_help()
sys.exit(1)
if '--version' in argv:
self.print_version()
sys.exit(1)
loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
flags=self.flags)
config = loader.load_config()
self.update_config(config)
def load_config_file(self, filename, path=None):
"""Load a .py based config file by filename and path."""
# TODO: this raises IOError if filename does not exist.
loader = PyFileConfigLoader(filename, path=path)
config = loader.load_config()
self.update_config(config)