Michael said:
ConfigObj (here we go...) my config file parser, if called with just a
filename, parses everything in the config file and presents the
results as a dictionary. That means you can add config file support
with basically 1 line of code (plus the import statement). This is
particularly useful for small admin scripts where you write the config
files yourself - speed and simplicity over flexibility.
I agree that speed and simplicity are important, and if you can get them
without sacrificing flexibility, even better. I looked at ConfigObj, and
I would summarise the advantages of the config module I released over
ConfigObj as follows. It shares the following features which you find
desirable (from the ConfigObj documentation):
* Ease of use - dictionary like access
* Multiple (list) values for keywords
* Easy to create, modify and write files
* Human readable
* Comments are preserved
* Quoting is optional [where unambiguous]
* Powerful set of options for parsing and writing
It also has the following additional features (apologies if ConfigObj
offers them too, I'm going by the documentation):
* There's no limit on the level of nesting of lists or mappings. One of
my main problems with ConfigParser is the limited depth of 2 levels -
sections and keys. This is where I found ConfigObj too limiting, too.
* Easy access to real Python objects such as sys.stderr or logging.DEBUG
or values from modules in the application using the config module.
* Good support for value substitution and value sharing.
* Access via attribute notation (a.b) as well as dictionary notation
(a['b']).
* There's no need for special quoting (like &mjf-quot; and &mjf-lf
.
Triple-quoted and raw strings are not (yet) supported, but you can use
single or double quotes and escape characters inside the string.
* Good integration with optparse.
* Defaults can be handled using ConfigList, which allows looking through
a list of configurations and returns a value from the first
configuration which defines one.
* Support for merging configurations (not an especially common use case)
and including configurations held in separate files (this use case is
more common).
* You can access a value through a path: cfg.a.b[3].c['d e'] is
equivalent to cfg.getByPath("a.b[3].c['d e']"). This is useful where
paths are constructed dynamically in the application, rather than
hard-coded. (For example, using sys.platform in the path to get
platform-dependent values.)
* Can easily handle remote configurations - you simply provide your own
stream opener, e.g. urllib2.urlopen().
Conversely, there is no schema-like support in my module, which
ConfigObj offers through configspecs. I could, of course, add it later
if I felt it necessary. The reason I don't provide schemas is that I
haven't felt it necessary for application configuration, though of
course if makes perfect sense to use them in data-exchange applications
(for which XML is often better, anyway). By not providing a schema, the
main thing users have to deal with is missing values or values which are
of the wrong type. To my mind, roughly the same amount of work is
required to deal with this as with handling exceptions thrown by a
schema validation layer; especially as a schema cannot always catch
semantic errors in the data.
Best Regards,
Vinay Sajip