5
Based on the standard Python ``ConfigParser`` module, this module provides an
6
enhanced configuration parser capabilities. ``Configuration`` is a drop-in
7
replacement for ``ConfigParser``.
9
A configuration file is broken into sections, and each section is
10
introduced by a section name in brackets. For example::
13
installationDirectory=/usr/local/foo
14
programDirectory: /usr/local/foo/programs
17
searchCommand: find /usr/local/foo -type f -name "*.class"
20
searchFailedMessage=Search failed, sorry.
26
A section name can consist of alphabetics, numerics, underscores and
27
periods. There can be any amount of whitespace before and after the
28
brackets in a section name; the whitespace is ignored.
33
Each section contains zero or more variable settings.
35
- Similar to a Java ``Properties`` file, the variables are specified as
36
name/value pairs, separated by an equal sign ("=") or a colon (":").
37
- Variable names are case-sensitive and may contain alphabetics, numerics,
38
underscores and periods (".").
39
- Variable values may contain anything at all. Leading whitespace in the
40
value is skipped. The way to include leading whitespace in a value is
41
escape the whitespace characters with backslashes.
46
A variable value can interpolate the values of other variables, using a
47
variable substitution syntax. The general form of a variable reference is
48
``${section_name:var_name}``.
50
- *section_name* is the name of the section containing the variable to
51
substitute; if omitted, it defaults to the current section.
52
- *var_name* is the name of the variable to substitute.
57
You can also specify a default value for a variable, using this syntax::
60
${section:foo?default}
62
That is, the sequence ``?default`` after a variable name specifies the
63
default value if the variable has no value. (Normally, if a variable has
64
no value, it is replaced with an empty string.) Defaults can be useful,
65
for instance, to allow overrides from the environment. The following example
66
defines a log file directory that defaults to "/tmp", unless environment
67
variable LOGDIR is set to a non-empty value::
69
logDirectory: ${env:LOGDIR?/var/log}
74
The section names "env", and "program" are reserved for special
77
The ``env`` pseudosection
78
~~~~~~~~~~~~~~~~~~~~~~~~~
80
The "env" pseudosection is used to interpolate values from the environment. On
81
UNIX systems, for instance, ``${env:HOME}`` substitutes home directory of the
82
current user. On some versions of Windows, ``${env:USERNAME}`` will substitute
85
Note: On UNIX systems, environment variable names are typically
86
case-sensitive; for instance, ``${env:USER}`` and ``${env:user}`` refer to
87
different environment variables. On Windows systems, environment variable
88
names are typically case-insensitive; ``${env:USERNAME}`` and
89
``${env:username}`` are equivalent.
91
The ``program`` pseudosection
92
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94
The "program" pseudosection is a placeholder for various special variables
95
provided by the Configuration class. Those variables are:
98
The current working directory. Thus, ``${program:cwd}`` will substitute
99
the working directory, using the appropriate system-specific
100
file separator (e.g., "/" on Unix, "\\" on Windows).
103
The calling program name. Equivalent to the Python expression
104
``os.path.basename(sys.argv[0])``
107
The current time, formatted using the ``time.strftime()`` format
108
``"%Y-%m-%d %H:%M:%S"`` (e.g., "2008-03-03 16:15:27")
113
A special include directive permits inline inclusion of another
114
configuration file. The include directive takes two forms::
121
%include "/home/bmc/mytools/common.cfg"
122
%include "http://configs.example.com/mytools/common.cfg"
124
The included file may contain any content that is valid for this parser. It
125
may contain just variable definitions (i.e., the contents of a section,
126
without the section header), or it may contain a complete configuration
127
file, with individual sections.
129
Note: Attempting to include a file from itself, either directly or
130
indirectly, will cause the parser to throw an exception.
132
Replacing ``ConfigParser``
133
==========================
135
You can use this class anywhere you would use the standard Python
136
``ConfigParser`` class. Thus, to change a piece of code to use enhanced
137
configuration, you might change this:
143
config = ConfigParser.SafeConfigParser()
144
config.read(configPath)
150
from grizzled.config import Configuration
152
config = Configuration()
153
config.read(configPath)
156
Sometimes, however, you have to use an API that expects a path to a
157
configuration file that can *only* be parsed with the (unenhanced)
158
``ConfigParser`` class. In that case, you simply use the ``preprocess()``
164
from grizzled import config
166
logging.config.fileConfig(config.preprocess(pathToConfig))
168
That will preprocess the enhanced configuration file, producing a file
169
that is suitable for parsing by the standard Python ``config`` module.
172
from __future__ import absolute_import
174
__docformat__ = "restructuredtext en"
176
# ---------------------------------------------------------------------------
178
# ---------------------------------------------------------------------------
188
from grizzled.exception import ExceptionWithMessage
189
from grizzled.collections import OrderedDict
191
# ---------------------------------------------------------------------------
193
# ---------------------------------------------------------------------------
195
__all__ = ['Configuration', 'preprocess',
196
'NoOptionError', 'NoSectionError', 'NoVariableError']
198
# ---------------------------------------------------------------------------
200
# ---------------------------------------------------------------------------
202
log = logging.getLogger('grizzled.config')
203
NoOptionError = ConfigParser.NoOptionError
204
NoSectionError = ConfigParser.NoSectionError
206
# ---------------------------------------------------------------------------
208
# ---------------------------------------------------------------------------
210
# Used with _ConfigDict
212
SECTION_OPTION_DELIM = r':'
214
# Section name pattern
215
SECTION_NAME_PATTERN = r'([_.a-zA-Z][_.a-zA-Z0-9]+)'
217
# Pattern of an identifier local to a section.
218
VARIABLE_NAME_PATTERN = r'([_a-zA-Z][_a-zA-Z0-9]+)(\?[^}]+)?'
220
# Pattern of an identifier matched by our version of string.Template.
223
# ${section:option} variable 'option' in section 'section'
224
# ${section:option?default} variable 'option' in section 'section', default
226
# ${option} variable 'option' in the current section
227
# ${option?default} variable 'option' in the current section,
228
# default value 'default'
229
VARIABLE_REF_PATTERN = SECTION_NAME_PATTERN + SECTION_OPTION_DELIM +\
230
VARIABLE_NAME_PATTERN +\
232
VARIABLE_NAME_PATTERN
234
# Simple variable reference
235
SIMPLE_VARIABLE_REF_PATTERN = r'\$\{' + VARIABLE_NAME_PATTERN + '\}'
239
PROGRAM_SECTION = 'program'
241
# ---------------------------------------------------------------------------
243
# ---------------------------------------------------------------------------
245
class NoVariableError(ExceptionWithMessage):
247
Thrown when a configuration file attempts to substitute a nonexistent
248
variable, and the ``Configuration`` object was instantiated with
249
``strict_substitution`` set to ``True``.
253
class Configuration(ConfigParser.SafeConfigParser):
255
Configuration file parser. See the module documentation for details.
260
permit_includes=True,
261
use_ordered_sections=False,
262
strict_substitution=False):
264
Construct a new ``Configuration`` object.
268
dictionary of default values
269
permit_includes : bool
270
whether or not to permit includes
271
use_ordered_sections : bool
272
whether or not to use an ordered dictionary for the section
273
names. If ``True``, then a call to ``sections()`` will return
274
the sections in the order they were encountered in the file.
275
If ``False``, the order is based on the hash keys for the
277
strict_substitution : bool
278
If ``True``, then throw an exception if attempting to
279
substitute a non-existent variable. Otherwise, simple
280
substitute an empty value.
282
ConfigParser.SafeConfigParser.__init__(self, defaults)
283
self.__permit_includes = permit_includes
284
self.__use_ordered_sections = use_ordered_sections
285
self.__strict_substitution = strict_substitution
287
if use_ordered_sections:
288
self._sections = OrderedDict()
292
Returns the instance-wide defaults.
295
:return: the instance-wide defaults, or ``None`` if there aren't any
297
return ConfigParser.SafeConfigParser.defaults(self)
302
Get the list of available sections, not including ``DEFAULT``. It's
303
not really useful to call this method before calling ``read()`` or
306
Returns a list of sections.
308
return ConfigParser.SafeConfigParser.sections(self)
310
def add_section(self, section):
312
Add a section named *section* to the instance. If a section by the
313
given name already exists, ``DuplicateSectionError`` is raised.
317
name of section to add
319
:raise DuplicateSectionError: section already exists
321
ConfigParser.SafeConfigParser.add_section(self, section)
323
def has_section(self, section):
325
Determine whether a section exists in the configuration. Ignores
326
the ``DEFAULT`` section.
333
:return: ``True`` if the section exists in the configuration, ``False``
336
return ConfigParser.SafeConfigParser.has_section(self, section)
338
def options(self, section):
340
Get a list of options available in the specified section.
347
:return: list of available options. May be empty.
349
:raise NoSectionError: no such section
351
return ConfigParser.SafeConfigParser.options(self, section)
353
def has_option(self, section, option):
355
Determine whether a section has a specific option.
361
name of option to check
364
:return: ``True`` if the section exists in the configuration and
365
has the specified option, ``False`` if not.
367
return ConfigParser.SafeConfigParser.has_option(self, section, option)
369
def read(self, filenames):
371
Attempt to read and parse a list of filenames or URLs, returning a
372
list of filenames or URLs which were successfully parsed. If
373
*filenames* is a string or Unicode string, it is treated as a single
374
filename or URL. If a file or URL named in filenames cannot be opened,
375
that file will be ignored. This is designed so that you can specify a
376
list of potential configuration file locations (for example, the
377
current directory, the user's home directory, and some system-wide
378
directory), and all existing configuration files in the list will be
379
read. If none of the named files exist, the ``Configuration`` instance
380
will contain an empty dataset. An application which requires initial
381
values to be loaded from a file should load the required file or files
382
using ``readfp()`` before calling ``read()`` for any optional files:
389
config = Configuration.Configuration()
390
config.readfp(open('defaults.cfg'))
391
config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')])
394
filenames : list or string
395
list of file names or URLs, or the string for a single filename
399
:return: list of successfully parsed filenames or URLs
401
if isinstance(filenames, basestring):
402
filenames = [filenames]
405
for filename in filenames:
407
self.__preprocess(filename, filename)
408
newFilenames += [filename]
410
log.exception('Error reading "%s"' % filename)
414
def readfp(self, fp, filename=None):
416
Read and parse configuration data from a file or file-like object.
417
(Only the ``readline()`` moethod is used.)
421
File-like object with a ``readline()`` method
423
Name associated with ``fp``, for error messages. If omitted or
424
``None``, then ``fp.name`` is used. If ``fp`` has no ``name``
425
attribute, then ``"<???">`` is used.
427
self.__preprocess(fp, filename)
429
def get(self, section, option, optional=False):
431
Get an option from a section.
437
name of option to check
439
``True`` to return None if the option doesn't exist. ``False``
440
to throw an exception if the option doesn't exist.
443
:return: the option value
445
:raise NoSectionError: no such section
446
:raise NoOptionError: no such option in the section
448
def do_get(section, option):
449
val = ConfigParser.SafeConfigParser.get(self, section, option)
450
if len(val.strip()) == 0:
451
raise ConfigParser.NoOptionError(option, section)
455
return self.__get_optional(do_get, section, option)
457
return do_get(section, option)
459
def getint(self, section, option, optional=False):
461
Convenience method that coerces the result of a call to
462
``get()`` to an ``int``.
468
name of option to check
470
``True`` to return None if the option doesn't exist. ``False``
471
to throw an exception if the option doesn't exist.
474
:return: the option value
476
:raise NoSectionError: no such section
477
:raise NoOptionError: no such option in the section
479
def do_get(section, option):
480
return ConfigParser.SafeConfigParser.getint(self, section, option)
483
return self.__get_optional(do_xget, section, option)
485
return do_get(section, option)
487
def getfloat(self, section, option, optional=False):
489
Convenience method that coerces the result of a call to ``get()`` to a
496
name of option to check
498
``True`` to return None if the option doesn't exist. ``False``
499
to throw an exception if the option doesn't exist.
502
:return: the option value
504
:raise NoSectionError: no such section
505
:raise NoOptionError: no such option in the section
507
def do_get(section, option):
508
return ConfigParser.SafeConfigParser.getfloat(self, section, option)
511
return self.__get_optional(do_get, section, option)
513
return do_get(section, option)
515
def getboolean(self, section, option, optional=False):
517
Convenience method that coerces the result of a call to ``get()`` to a
518
boolean. Accepted boolean values are "1", "yes", "true", and "on",
519
which cause this method to return True, and "0", "no", "false", and
520
"off", which cause it to return False. These string values are checked
521
in a case-insensitive manner. Any other value will cause it to raise
528
name of option to check
530
``True`` to return None if the option doesn't exist. ``False``
531
to throw an exception if the option doesn't exist.
534
:return: the option value (``True`` or ``False``)
536
:raise NoSectionError: no such section
537
:raise NoOptionError: no such option in the section
538
:raise ValueError: non-boolean value encountered
540
def do_get(section, option):
541
return ConfigParser.SafeConfigParser.getboolean(self,
546
return self.__get_optional(do_get, section, option)
548
return do_get(section, option)
550
def getlist(self, section, option, sep=None, optional=False):
552
Convenience method that coerces the result of a call to ``get()`` to a
553
list. The value is split using the separator(s) specified by the
554
``sep`` argument. A ``sep`` value of ``None`` uses white space. The
555
result is a list of string values.
561
name of option to check
563
list element separator to use. Defaults to white space.
565
``True`` to return None if the option doesn't exist. ``False``
566
to throw an exception if the option doesn't exist.
569
:return: the option value (``True`` or ``False``)
571
:raise NoSectionError: no such section
572
:raise NoOptionError: no such option in the section
574
def do_get(section, option):
575
value = ConfigParser.SafeConfigParser.get(self, section, option)
576
return value.split(sep)
579
return self.__get_optional(do_get, section, option)
581
return do_get(section, option)
590
Retrieve at most one of a list or set of options from a section. This
591
method is useful if there are multiple possible names for a single
592
option. For example, suppose you permit either a ``user_name`` or a
593
``login_name`` option, but not both, in a section called
594
``credentials``. You can use the following code to retrieve the
599
from grizzled.config import Configuration
601
config = Configuration()
602
config.read('/path/to/config')
603
user = config.get_one_of('credentials', ['user_name', 'login_name'])
605
If both options exist, ``get_one_of()`` will a ``NoOptionError``. If
606
neither option exists, ``get_one_of()`` will throw a ``NoOptionError``
607
if ``optional`` is ``False`` and there's no default value; otherwise,
608
it will return the default value.
613
options : list or set
614
list or set of allowable option names
616
``True`` to return None if the option doesn't exist. ``False``
617
to throw an exception if the option doesn't exist.
619
The default value, if the option does not exist.
621
The type to which to coerce the value. The value is coerced by
625
:return: the option value, or ``None`` if nonexistent and
626
``optional`` is ``True``
628
:raise NoSectionError: no such section
629
:raise NoOptionError: none of the named options are in the section
632
if value_type is bool:
633
get = self.getboolean
637
for option in options:
638
value = get(section, option, optional=True)
645
if (value is None) and (not optional):
646
raise NoOptionError('Section "%s" must contain exactly one of the '
647
'following options: %s' %
648
(section, ', '.join(list(options))))
650
if value is not None:
651
if not (value_type in (bool, str)):
652
value = eval('%s(%s)' % (value_type.__name__, value))
656
def items(self, section):
658
Get all items in a section.
665
:return: a list of (*name*, *value*) tuples for each option in
668
:raise NoSectionError: no such section
670
return ConfigParser.SafeConfigParser.items(self, section)
672
def set(self, section, option, value):
674
If the given section exists, set the given option to the specified
675
value; otherwise raise ``NoSectionError``.
681
name of option to check
685
:raise NoSectionError: no such section
687
ConfigParser.SafeConfigParser.set(self, section, option, value)
689
def write(self, fileobj):
691
Write a representation of the configuration to the specified file-like
692
object. This output can be parsed by a future ``read()`` call.
694
NOTE: Includes and variable references are ``not`` reconstructed.
695
That is, the configuration data is written in *expanded* form.
699
file-like object to which to write the configuration
701
ConfigParser.SafeConfigParser.write(self, fileobj)
703
def remove_section(self, section):
705
Remove a section from the instance. If a section by the given name
706
does not exist, ``NoSectionError`` is raised.
710
name of section to remove
712
:raise NoSectionError: no such section
714
ConfigParser.SafeConfigParser.remove_section(self, section)
716
def optionxform(self, option_name):
718
Transforms the option name in ``option_name`` as found in an input
719
file or as passed in by client code to the form that should be used in
720
the internal structures. The default implementation returns a
721
lower-case version of ``option_name``; subclasses may override this or
722
client code can set an attribute of this name on instances to affect
723
this behavior. Setting this to ``str()``, for example, would make
724
option names case sensitive.
726
return option_name.lower()
728
def __get_optional(self, func, section, option):
730
return func(section, option)
731
except ConfigParser.NoOptionError:
733
except ConfigParser.NoSectionError:
736
def __preprocess(self, fp, name):
740
except AttributeError:
744
# Read-only. Oh, well.
746
except AttributeError:
747
# Read-only. Oh, well.
750
if self.__permit_includes:
751
# Preprocess includes.
752
from grizzled.file import includer
753
tempFile = includer.preprocess(fp)
756
# Parse the resulting file into a local ConfigParser instance.
758
parsedConfig = ConfigParser.SafeConfigParser()
760
if self.__use_ordered_sections:
761
parsedConfig._sections = OrderedDict()
763
parsedConfig.optionxform = str
764
parsedConfig.read(fp)
766
# Process the variable substitutions.
768
self.__normalizeVariableReferences(parsedConfig)
769
self.__substituteVariables(parsedConfig)
771
def __normalizeVariableReferences(self, sourceConfig):
773
Convert all section-local variable references (i.e., those that don't
774
specify a section) to fully-qualified references. Necessary for
775
recursive references to work.
777
simpleVarRefRe = re.compile(SIMPLE_VARIABLE_REF_PATTERN)
778
for section in sourceConfig.sections():
779
for option in sourceConfig.options(section):
780
value = sourceConfig.get(section, option, raw=True)
782
match = simpleVarRefRe.search(value)
784
value = value[0:match.start(1)] +\
786
SECTION_OPTION_DELIM +\
787
value[match.start(1):]
788
match = simpleVarRefRe.search(value)
790
sourceConfig.set(section, option, value)
792
def __substituteVariables(self, sourceConfig):
793
mapping = _ConfigDict(sourceConfig, self.__strict_substitution)
794
for section in sourceConfig.sections():
795
mapping.section = section
796
self.add_section(section)
797
for option in sourceConfig.options(section):
798
value = sourceConfig.get(section, option, raw=True)
800
# Repeatedly substitute, to permit recursive references
803
while value != previousValue:
804
previousValue = value
805
value = _ConfigTemplate(value).safe_substitute(mapping)
807
self.set(section, option, value)
809
class _ConfigTemplate(string.Template):
811
Subclass of string.Template that handles our configuration variable
814
idpattern = VARIABLE_REF_PATTERN
816
class _ConfigDict(dict):
818
Dictionary that knows how to dereference variables within a parsed config.
819
Only used internally.
821
idPattern = re.compile(VARIABLE_REF_PATTERN)
822
def __init__(self, parsedConfig, strict_substitution):
823
self.__config = parsedConfig
824
self.__strict_substitution = strict_substitution
827
def __getitem__(self, key):
829
# Match against the ID regular expression. (If the match fails,
830
# it's a bug, since we shouldn't be in here unless it does.)
832
match = self.idPattern.search(key)
835
# Now, get the value.
838
if SECTION_OPTION_DELIM in key:
840
default = self.__extract_default(match.group(3))
842
section = match.group(1)
843
option = match.group(2)
845
section = self.section
847
option = match.group(3)
849
default = self.__extract_default(match.group(3))
851
result = self.__value_from_section(section, option)
856
except ConfigParser.NoSectionError:
859
except ConfigParser.NoOptionError:
863
if self.__strict_substitution:
864
raise NoVariableError, 'No such variable: "%s"' % key
870
def __extract_default(self, s):
873
default = default[1:] # strip leading '?'
874
if len(default) == 0:
879
def __value_from_program_section(self, option):
882
'now' : time.strftime('%Y-%m-%d %H:%M:%S'),
883
'name' : os.path.basename(sys.argv[0])
886
def __value_from_section(self, section, option):
889
result = os.environ[option]
891
raise KeyError, option
893
elif section == 'program':
894
result = self.__value_from_program_section(option)
897
result = self.__config.get(section, option)
901
# ---------------------------------------------------------------------------
903
# ---------------------------------------------------------------------------
905
def preprocess(file_or_url, defaults=None):
907
This function preprocesses a file or URL for a configuration file,
908
processing all includes and substituting all variables. It writes a new
909
configuration file to a temporary file (or specified output file). The
910
new configuration file can be read by a standard ``ConfigParser``
911
object. Thus, this method is useful when you have an extended
912
configuration file that must be passed to a function or object that can
913
only read a standard ``ConfigParser`` file.
915
For example, here's how you might use the Python ``logging`` API with an
916
extended configuration file:
920
from grizzled.config import Configuration
923
logging.config.fileConfig(Configuration.preprocess('/path/to/config')
927
file or URL to read and preprocess
929
defaults to pass through to the config parser
932
:return: Path to a temporary file containing the expanded configuration.
933
The file will be deleted when the program exits, though the caller
934
is free to delete it sooner.
945
parser = Configuration(use_ordered_sections=True)
946
parser.read(file_or_url)
947
fd, path = tempfile.mkstemp(suffix='.cfg')
948
atexit.register(unlink, path)
949
parser.write(os.fdopen(fd, "w"))
953
# ---------------------------------------------------------------------------
954
# Main program (for testing)
955
# ---------------------------------------------------------------------------
957
if __name__ == '__main__':
960
format = '%(asctime)s %(name)s %(levelname)s %(message)s'
961
logging.basicConfig(level=logging.DEBUG, format=format)
963
configFile = sys.argv[1]
964
config = Configuration()
965
config.read(configFile)
967
if len(sys.argv) > 2:
968
for var in sys.argv[2:]:
969
(section, option) = var.split(':')
970
val = config.get(section, option, optional=True)
971
print '%s=%s' % (var, val)
973
config.write(sys.stdout)