[Python-Dev] ConfigParser shootout, preliminary entry

Guido van Rossum gvanrossum at gmail.com
Tue Oct 19 17:00:23 CEST 2004


Let me suggest two variations that I have used successfully in my day
job (which is also my night job :).

1. For parsing .ini files, I wrote a wrapper around ConfigParser. The
Python-level API looks like this (anonymized and idealized):

from XXX import MyConfigWrapper, optstr, optint, optbool, optfloat

class Config(MyConfigWrapper):
    poll_time = optfloat("network-parameters", "poll-time")
    use_ssl = optbool("network-parameters", "use-ssl")
    window_title = optstr("ui-parameters", "window-title")
    # etc.

This allows the Python names for variables to differ from the names
used in the .ini file, and abstracts away the section names completely
from the Python API. This makes it possible to rename variables and
sections in the config file without having to touch the Python code
that uses them. This will save my butt when our marketing team comes
up with the *real* name for our product, since currently the section
names all have the provisional product name in it, and the config file
is considered "user-facing" so references to the old product name have
to be expunged. Also, I don't see much point in having to use longer
references in my Python code -- the total number of config parameters
and their uses are such that I can easily come up with a single unique
name for every option, and yet in the .ini file I'd like to have more
than one section.

Note that optstr etc. construct full properties that allow me to set
and delete the parameter values as well, and then ConfigParser can be
told to write back the modified .ini file. This loses the ordering and
comment, but I don't care (although I wish ConfigParser would order
things alphabetically rather than per dictionary hash). I don't think
I have to explain that optint returns a Python int, etc.

2. We're handling modest amounts of XML, all using home-grown DTDs and
with no specific requirements to interface to other apps or XML tools.
I wrote a metaclass which lets me specify the DTD using Python syntax.
Again, my approach is slightly lower-level than previous proposals
here but has the advantage of letting you be explicit about the
mapping between Python and XML names, both for attributes and for
subelements. The metaclass handles reading and writing. It supports
elements containing text (is that CDATA? I never know) or
sub-elements, but not both. For sub-elements, it supports cases where
one element has any number of sub-elements of a certain type, which
are then collected in a list, so you can refer to them using Python
sequence indexing/slicing notation. It also supports elements that
have zero or one sub-element of a certain type; absence is indicated
by setting the corresponding attribute to None. I don't support
namespaces, although I expect it would be easy enough to add them. I
don't support unrecognized elements or attributes: while everything
can be omitted (and defaults to None), unrecognized attributes or
elements are always rejected. (I suppose that could be fixed too if
desired.) Here's an example:

from XXX import ElementMetaClass, String, Integer, Float, Boolean, Date

class Inner(ElementMetaClass):
    "Definition for <inner>"
    __element__ = "inner"
    __attributes__ = [("count", Integer),
                      ("name", String),
                      ("expiration-date", Date),
                      ("date-created", Date),
                      ("special", Boolean)]
    __characters__ = "text" # CDATA (?) is stored as self.text

class Outer(ElementMetaClass):
    "Definition for <outer>"
    __element__ = "outer"
    __attributes__ = [("name", String)]
    __children__ = [("innerElements[]", Inner)]

Note that for attributes, the name given is used both as the Python
name and as the XML name, except that hyphens in XML are translated
into underscores in Python, and vice versa.

For sub-elements, the __element__ attribute of the class determines
the element name, and the name given in the list of __children__
determines the Python name; if this ends in "[]" it is a repeatable
element.

I'm undecided on whether I like the approach with lists of (name,
type) tuples better than the approach with property factories like in
the first example; the list approach allows me to order the attributes
and sub-elements consistently upon rendering, but I'm not particularly
keen on typing string quotes around Python identifiers.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list