Source code for pyamp.config.parser
# Copyright 2012 Brett Ponsler
# This file is part of pyamp.
#
# pyamp is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyamp is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyamp. If not, see <http://www.gnu.org/licenses/>.
'''The parser module contains the OptionsParser class which provides the
ability to parse a configuration file and command line given a set of
available options.
.'''
from os.path import exists
from optparse import OptionParser
from pyamp.patterns import Borg
from pyamp.config.configFile import ConfigFile
from pyamp.logging import Colors, Loggable
__all__ = ["OptionsParser"]
[docs]class OptionsParser(Borg, Loggable):
'''The OptionsParser class is responsible for parsing command line and
configuration file options and providing the ability to get the value of a
given option.
This class implements the :class:`pyamp.patterns.Borg` design pattern and
also implements the :class:`pyamp.logging.Loggable` interface.
'''
Variables = {}
'''This property contains a dictionary mapping variable names
to their respective values. These variables can be used
within the configuration file and will be replaced by the
assigned values.
Variables can be used in the configuration file by appending a dollar sign
before the name of the variable. The variable will then replaced with its
value prior to parsing the file.
Example::
# $HOME will be replaced with the user's home directory before parsing
[Section]
Var = $HOME
'''
Options = {}
'''This property contains a dictionary mapping section names to the list of
options contained within that section. Options must be a subclass of
the :class:`Option` class. These are the sections and options that will
be loaded from the configuration file and the command line arguments.
.. note:: Any :class:`.ClOption` objects that are given will be
configurable via the configuration file and from the command line.
'''
ClOptions = []
'''This property contains the list of options that are only configurable
via the command line.
'''
[docs] def init(self, logger=None):
'''Override the :class:`pyamp.patterns.Borg` init function.
* logger -- The :class:`pyamp.logging.Logger` or
:class:`pyamp.logging.LogData` object
'''
self.options = {}
self.clOptions = {}
self.setLogger(logger)
# Create the command line and configuration file parsers
self.__createCommandLineParser()
self.__createConfigParser()
[docs] def setLogger(self, logger, color=Colors.Foreground.White):
'''Set the logger for the OptionsParser.
* logger -- The :class:`pyamp.logging.Logger` or
:class:`pyamp.logging.LogData` object
'''
Loggable.__init__(self, self.__class__.__name__, logger, color)
[docs] def parse(self, argv, filename):
'''Parse the command line options, and the configuration file.
* argv -- The command line options
* filename -- The path to the configuration file
'''
# First parse the configuration file
self.__parseFile(filename)
# Now parse the command line options, which override any
# overlapping configuration properties
self.__parseCommandLine(argv)
# Print out all of the settings that are configured for
# debugging purposes
for _, options in self.options.iteritems():
for optionName, value in options.iteritems():
self.debug("[%s] = %s" % (optionName, str(value)), level=5)
@classmethod
[docs] def get(cls, section, optionName, defaultValue=None):
'''Get the value of an option from the given section.
* section -- The name of the section
* optionName -- The name of the option
* defaultValue -- The default value if the option does not exist
'''
sectionOptions = cls().options.get(section, {})
return sectionOptions.get(optionName, defaultValue)
@classmethod
[docs] def getCl(cls, optionName, defaultValue=None):
'''Get the value of a command line option.
* optionName -- The name of the command line option
* defaultValue -- The default value if the option does not exist
'''
return cls().clOptions.get(optionName, defaultValue)
def __parseCommandLine(self, argv):
'''Parse the command line options.
* argv -- The command line options
'''
# Parse the given command line options
(options, _) = self._commandLineParser.parse_args(argv)
# Join the command line options with our current options and
# allow the command line options to override any currently
# set option values
for section, optionDict in self._commandLineOptions.iteritems():
for optionName, _ in optionDict.iteritems():
value = getattr(options, optionName)
if value is not None:
if section not in self.options:
self.options[section] = {}
self.options[section][optionName] = value
# Store all of the command line option values
for clOption in self.ClOptions:
optionName = clOption.getName()
if hasattr(options, optionName):
value = getattr(options, optionName, None)
self.clOptions[optionName] = value
def __parseFile(self, filename):
'''Parse the configuration file.
* filename -- The configuration file
'''
if exists(filename):
self._configParser.parse(filename)
settings = self._configParser.getSettings()
self.options = dict(self.options.items() + settings.items())
def __createCommandLineParser(self):
'''Create the command line parser object.'''
# Keep a list of all of the command line option variable names
self._commandLineOptions = {}
# Parser for the command line options
parser = OptionParser()
# Traverse all of the configured sections
for section, options in self.Options.iteritems():
# Travese only the options in this section that are configurable
# via the command line
for option in [opt for opt in options if opt.isCommandLine()]:
optionName = option.getName()
defaultValue = option.getDefaultValue()
# @todo: create other Option objects that can use more values
# from this class...help, have no value, etc
parser.add_option("--%s" % optionName, dest=optionName,
default=defaultValue)
if section not in self._commandLineOptions:
self._commandLineOptions[section] = {}
self._commandLineOptions[section][optionName] = defaultValue
# Add all of the command line only options
for clOption in self.ClOptions:
clOption.addOption(parser)
# Store the command line parser locally
self._commandLineParser = parser
def __createConfigParser(self):
'''Create the configuration file parser object.'''
# Create the dictionary mapping sections to their respective Options
self._configOptions = self.Options
# Define all of the configuration variables that can be used
self._configVariables = self.Variables
# Create the configuration parser using the configured variables and
# configuration options
self._configParser = ConfigFile(logger=self._logger,
options=self._configOptions,
variables=self._configVariables)