Stem Docs

Configuration File Handling

Configuration File Handling

Handlers for text configuration files. Configurations are simple string to string mappings, with the configuration files using the following rules…

For instance…

# This is my sample config
user.name Galen
user.password yabba1234 # here's an inline comment
user.notes takes a fancy to pepperjack cheese
blankEntry.example

msg.greeting
|Multi-line message exclaiming of the
|wonder and awe that is pepperjack!

… would be loaded as…

config = {
  'user.name': 'Galen',
  'user.password': 'yabba1234',
  'user.notes': 'takes a fancy to pepperjack cheese',
  'blankEntry.example': '',
  'msg.greeting': 'Multi-line message exclaiming of the\nwonder and awe that is pepperjack!',
}

Configurations are managed via the Config class. The Config can be be used directly with its get() and set() methods, but usually modules will want a local dictionary with just the configurations that it cares about.

To do this use the config_dict() function. For example…

import getpass
from stem.util import conf, connection

def config_validator(key, value):
  if key == 'timeout':
    # require at least a one second timeout
    return max(1, value)
  elif key == 'endpoint':
    if not connection.is_valid_ipv4_address(value):
      raise ValueError("'%s' isn't a valid IPv4 address" % value)
  elif key == 'port':
    if not connection.is_valid_port(value):
      raise ValueError("'%s' isn't a valid port" % value)
  elif key == 'retries':
    # negative retries really don't make sense
    return max(0, value)

CONFIG = conf.config_dict('ssh_login', {
  'username': getpass.getuser(),
  'password': '',
  'timeout': 10,
  'endpoint': '263.12.8.0',
  'port': 22,
  'reconnect': False,
  'retries': 3,
}, config_validator)

There’s several things going on here so lets take it step by step…

Now lets say our user has the following configuration file…

username waddle_doo
password jabberwocky
timeout -15
port 9000000
retries lots
reconnect true
logging debug

… and we load it as follows…

>>> from stem.util import conf
>>> our_config = conf.get_config('ssh_login')
>>> our_config.load('/home/atagar/user_config')
>>> print CONFIG  
{
  "username": "waddle_doo",
  "password": "jabberwocky",
  "timeout": 1,
  "endpoint": "263.12.8.0",
  "port": 22,
  "reconnect": True,
  "retries": 3,
}

Here’s an expanation of what happened…

Module Overview:

config_dict - provides a dictionary that's kept in sync with our config
get_config - singleton for getting configurations
uses_settings - provides an annotation for functions that use configurations
parse_enum_csv - helper funcion for parsing confguration entries for enums

Config - Custom configuration
  |- load - reads a configuration file
  |- save - writes the current configuration to a file
  |- clear - empties our loaded configuration contents
  |- add_listener - notifies the given listener when an update occurs
  |- clear_listeners - removes any attached listeners
  |- keys - provides keys in the loaded configuration
  |- set - sets the given key/value pair
  |- unused_keys - provides keys that have never been requested
  |- get - provides the value for a given key, with type inference
  +- get_value - provides the value for a given key as a string