Configuration toolkit

Configuration toolkit

Dragonfly’s configuration toolkit makes it very easy to store program data in a separate file from the main program logic. It uses a three-phase setup – load – use system:

  • setup – a Config object is created and its structure and default contents are defined.

  • load – a separate file containing the user’s configuration settings is looked for and, if found, its values are loaded into the Config object.

  • use – the program directly accesses the configuration through easy Config object attributes.

This configuration toolkit uses the following three classes:

  • Config – a collection of configuration settings, grouped within one or more sections

  • Section – a group of items and/or subsections

  • Item – a single configuration setting

Usage example

The main program using Dragonfly’s configuration toolkit would normally look something like this:

from dragonfly import Config, Section, Item

# *Setup* phase.
# This defines a configuration object with the name "Example
#  configuration".  It contains one section with the title
#  "Test section", which has two configuration items.  Both
#  these items have a default value and a docstring.
config                 = Config("Example configuration")
config.test            = Section("Test section")
config.test.fruit      = Item("apple", doc="Must eat fruit.")
config.test.color      = Item("blue", doc="The color of life.")

# *Load* phase.
# This searches for a file with the same name as the main program,
#  but with the extension ".py" replaced by ".txt".  It is also
#  possible to explicitly specify the configuration file's path.
#  See Config.load() for more details.
config.load()

# *Use* phase.
# The configuration values can now be accessed through the
#  configuration object as follows.
print("The color of life is %s" % config.test.color)
print("You must eat an %s every day" % config.test.fruit)

The configuration defined above is basically complete. Every configuration item has a default value and can be accessed by the program. But if the user would like to modify some or all of these settings, he can do so in an external configuration file without modifying the main program code.

This external configuration file is interpreted as Python code. It may be generated with Config.generate_config_file():

# *Generate* an external configuration file for the program above.
# By default, this writes configuration settings to a file with
#  the same name as the main program, but with the extension ".py"
#  replaced by ".txt".
#
# If the file already exists, it will be  overwritten.  As such,
#  if this method is present in a program, it will usually be
#  invoked once and then commented out.
config.generate_config_file()

External configuration files give grammar authors powerful tools for determining the desired configuration settings. However, they will usually consist merely of variable assignments. The configuration file for the program above might look something like this:

#
# Dragonfly config for Example configuration
#

#--- Test section ------------------------------------------------------

# Must eat fruit.
# Default: 'apple'
test.fruit = "banana"   # Bananas have more potassium.

# The color of life.
# Default: 'blue'
test.color = "white"    # I like light colors.

The output contains the configuration name (Example configuration), followed by a single section (Test section) and its two items (fruit and color), which have been given custom values.

This separation of program data from program logic makes the configuration toolkit suitable for documenting voice commands.

Example command modules

The configuration toolkit is utilized in a number of command modules in the t4ngo/dragonfly-modules repository, available on GitHub. See Related Resources: Command modules.

Implementation details

This configuration toolkit makes use of Python’s special methods for setting and retrieving object attributes. This makes it much easier to use, as there is no need to use functions such as value = get_config_value(“item_name”); instead the configuration values are immediately accessible as Python objects. It also allows for more extensive error checking; it is for example trivial to implement custom Item classes which only allow specific values or value types, such as integers, boolean values, etc.

Configuration class reference

class Config(name)[source]

Configuration class for storing program settings.

Constructor argument:
  • name (str) – the name of this configuration object.

This class can contain zero or more Section instances, each of which can contain zero or more Item instances. It is these items which store the actual configuration settings. The sections merely divide the items up into groups, so that different configuration topics can be split for easy readability.

generate_config_file(path=None)[source]

Create a configuration file containing this configuration object’s current settings.

  • path (str, default: None) – path to the configuration file to load. If None, then a path is generated from the calling module’s file name by replacing its extension with “.txt”.

load(path=None)[source]

Load the configuration file at the given path, or look for a configuration file associated with the calling module.

  • path (str, default: None) – path to the configuration file to load. If None, then a path is generated from the calling module’s file name by replacing its extension with “.txt”.

If the path is a file, it is loaded. On the other hand, if it does not exist or is not a file, nothing is loaded and this configuration’s defaults remain in place.

class Item(default, doc=None, namespace=None)[source]

Configuration item for storing configuration settings.

Constructor arguments:
  • default – the default value for this item

  • doc (str, default: None) – an optional description of this item

  • namespace (dict, default: None) – an optional namespace dictionary which will be made available to the Python code in the external configuration file during loading

A configuration item is the object that stores the actual configuration settings. Each item has a default value, a current value, an optional description, and an optional namespace.

This class performs the checking of configuration values assigned to it during loading of the configuration file. The default behavior of this class is to only accept values of the same Python type as the item’s default value. So, if the default value is a string, then the value assigned in the configuration file must also be a string. Otherwise an exception will be raised and loading will fail.

Developers who want other kinds of value checking should override the Item.validate() method of this class.

validate(value)[source]

Determine whether the given value is valid.

This method performs validity checking of the configuration value assigned to this item during loading of the external configuration file. If the default behavior is to raise a TypeError if the type of the assigned value is not the same as the type of the default value.

class Section(doc)[source]

Section of a configuration for grouping items.

Constructor argument:
  • doc (str) – the name of this configuration section.

A section can contain zero or more subsections and zero or more configuration items.