# Stem Docs

## Configuration File Handling

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

- the key/value is separated by a space

- anything after a ‘#’ is ignored as a comment

- excess whitespace is trimmed

- empty lines are ignored

- multi-line values can be defined by following the key with lines starting with a ‘|’

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…

- The `config_dict()` provides a dictionary that’s bound to a given configuration. If the “ssh_proxy_config” configuration changes then so will the contents of CONFIG.

- The dictionary we’re passing to `config_dict()` provides two important pieces of information: default values and their types. See the Config’s `get()` method for how these type inferences work.

- The config_validator is a hook we’re adding to make sure CONFIG only gets values we think are valid. In this case it ensures that our timeout value is at least one second, and rejects endpoints or ports that are invalid.

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…

- the username, password, and reconnect attributes took the values in the configuration file

- the ‘config_validator’ we added earlier allows for a minimum timeout of one and rejected the invalid port (with a log message)

- we weren’t able to convert the retries’ “lots” value to an integer so it kept its default value and logged a warning

- the user didn’t supply an endpoint so that remained unchanged

- our CONFIG didn’t have a ‘logging’ attribute so it was ignored

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