Configuration - part 6

This series has been about the configuration manager within the Socorro project. This posting is about a future direction of the configuration manager. The goal is embrace and unify other configuration sources. If there's a module that does something better or differently than the corresponding configuration manager analog, configuration manager should be able to exploit it.

Configuration manager depends on two sources of information: the definition list and the value source list. The definition list tells the manager about the parameters, their default values and their documentation strings. The values list is a hierarchy of sources of values for the the parameters defined in the definition list.

The configuration manager provides its own "language" for defining configuration parameters. The language consists of namespaces and options. Options consist of a name, a documentation string, a default value, and a conversion function. In the existing world of Pythonic configuration, there are already systems that have similar definition "languages".

Argparse has an API that defines such a language. There is a direct analog between the components of the Socorro configuration language and argparse's configuration language. However, argparse goes beyond Socorro in defining relationships between parameters. It allows some parameters to be assigned values based on "actions" that may interact with other parameters.

Socorro's configuration manager can use argparse's definitions with an adapter. Since argparse can serve in Socorro as both a definition source and a value source, any program already using argparse can simply drop the argparse object into configmanager. Configmanager will delegate to argparse all the responsibilities of definitions and command line parsing. the example below is the canonical argparse demo updated to use configuration manager. With the addition of just a few lines of code, the example has been extended to allow parameter values to come from an ini file as well as the os environment.
import argparse
import socorro.lib.configurationmanager as cm
  
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument(
    "integers", metavar="N", type=int, nargs="+", help="an integer for the accumulator"
)
parser.add_argument(
    "--sum",
    dest="accumulate",
    action="store_const",
    const=sum,
    default=max,
    help="sum the integers (default: find the max)",
)
  
configman = cm.ConfigurationManager((parser,), (ConfigParse, os.environ, parser))
config = configman.get_config()
print config.integers
print config.accumulate
So how will (does) configuration manager do this? For each of the two external lists, definitions and values, there are a collections of adapters. In turn, each of the lists will be walked and the elements of the list offered to the adapter controller. Dispatched by the identity or type of the element, an appropriate adapter is instantiated to wrap the element. The wrapper gives the configuration manager a uniform API to read from. Once all the sources are wrapped with an identical API, the configuration manager can treat all sources equally.

Argparse, unfortunately, isn't so easy to adapt. It's API is a sink for its parameter definitions. Once defined, there is no external API to read them back out. I believe this is an unfortunate oversight and, perhaps, a violation of the build to be extended mantra that I believe is so important to good library design. So configuration manager has to cheat and peer inside argparse's parser object. The violation isn't too serious as it is a read only operation, however, it is still far from ideal.

In the next article of the series, I'll discuss the use of ConfigParse as a value source and why it can't be used as a definition source.