On Tue, 19 Oct 2004 08:00:23 -0700, Guido van Rossum email@example.com wrote:
Let me suggest two variations that I have used successfully in my day job (which is also my night job :).
- 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.
The opt* property builders could be substituted by a single opt which took the default value as an argument:
opt(section_name, key_name, default_value)
The default_value type would be used for conversion on reading & writing:
class Config(MyConfigWrapper): poll_time = opt("network-parameters", "poll-time", 1.0) use_ssl = opt("network-parameters", "use-ssl", False) window_title = opt("ui-parameters", "window-title", '')
It solves the type cheking and the default value requirements with a single parameter. It's also extensible -- any other type that knows how to construct itself out of a string could be used as an option type.
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.
It works well as far as the option names are unique. In some cases, there are sections with a similar internal structure, and in this case the use of nested structures to represent sections is better. I had one such situation in a communications program of mine a few years ago: each interface (com1:, com2:, etc) had its own section in the config file, with the same parameters being stated for each 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.
One of the discussion we've had was about what ordering was desired: arbitrary (hash ordering), alphabethical, or declaration ordering. Alphabethical is better than arbitrary, and current implementations can solve this by sorting the key names before writing the data. I personally like to have my config files ordered as per the original declaration ordering. For example: a webserver most relevant parameter for a quick-and-dirty setup is the port number; if stored in alphabethical ordering, it may be hidden down the list. The use of the original source ordering allows for the developer to write the parameters in the order that makes more sense (from a usability standpoint) for the users that may need to read or edit them, without the need to provide a explicity ordering list. The problem with the list is that it's easy to forget to update it as one adds new parameters, specially if this is done using inheritance.