YAML Configs

The Yaml Config classes are subclassed to form the specification for your config file, and form the root from which loading, writing, and validating configs is performed. The form of this base depends on which Yaml Config class you use.

Yaml Config

Yaml Config uses a KeyedElem as the root, resulting in a strictly keyed root dictionary. Each key must be predefined, but each key may have a unique element type.

class yaml_config.YamlConfigLoader(name='<root>')

Defines a YAML config specification, where the base structure is a strictly keyed dictionary.

To use this, subclass it and override the ELEMENTS class variable with a list of ConfigElement instances that describe the keys for config.

import yaml_config as yc

class StrictConfig(yc.YamlConfigLoader):
    # These are the only keys allowed.
    ELEMENTS = [
        yc.StrElem('first_name', required=True),
        yc.StrElem('last_name', required=True),
        yc.RegexElem('middle_initial', regex=r'[A-Za-z]'),
        yc.IntRangeElem('age', vmin=1, required=True)
    ]
A valid config could look like: ::

first_name: Bob last_name: Sagat age: 59

Variables
  • HEADER ([str]) – The documentation that should appear at the top of the config file.

  • ELEMENTS ([ConfigElement]) – Override this with a list of element types describing your configuration.

dump(outfile, values=None, show_comments=True, show_choices=True)

Write the configuration to the given output stream.

Parameters
  • outfile (stream) – A writable stream object

  • values ({}) – Write the configuration file with the given values inserted. Values should be a dictionary as produced by YamlConfigLoader.load().

  • show_comments (bool) – When dumping the config file, include help_text and general element information as comments. Default True.

  • show_choices (bool) – When creating comments, include the choices available for each item. Default True.

find(dotted_key)

Find the element matching the given dotted key. This is useful for retrieving elements to use their help_text or defaults.

Dotted keys look like normal property references, except that the names of the sub-element for Lists or Collections are given as a ‘*’, since they don’t have an explicit name. An empty string always returns this element.

Examples:

class Config2(yc.YamlConfigLoader):
    ELEMENTS = [
        yc.ListElem('cars', sub_elem=yc.KeyedElem(elements=[
            yc.StrElem('color'),
            yc.StrElem('make'),
            yc.IntElem('year'),
            yc.CollectionElem(
                'accessories',
                sub_elem=yc.KeyedElem(elements=[
                    yc.StrElem('floor_mats')
            ])
        ]
    ]

config = Config2()
config.find('cars.*.color')
Parameters

dotted_key (str) – The path to the sought for element.

Returns ConfigElement

The found Element.

Raises

KeyError – If the element cannot be found.

load(infile, partial=False)

Load a configuration YAML file from the given stream, and then validate against the config specification.

Parameters
  • infile (stream) – The input stream from which to read.

  • partial (bool) – The infile is not expected to be a complete configuration, so missing ‘required’ fields can be ignored.

Returns ConfigDict

A ConfigDict of the contents of the configuration file.

Raises
  • IOError – On stream read failures.

  • YAMLError – (and child exceptions) On YAML format issues.

  • ValueError, RequiredError, KeyError – As per validate().

set_default(dotted_key, value)

Sets the default value of the element found using dotted_key path. See the structure of the elements relative to this one, which is typically the base ConfigElement instance. Each component of the dotted key must correspond to a named key at that level. In cases such as lists where then sub_elem doesn’t have a name, a ‘*’ should be given.

Why ever use this? Because in many cases the default is based on run-time information.

Examples:

class DessertConfig(yc.YamlConfigLoader):
    ELEMENTS = [
        yc.KeyedElem('pie', elements=[
            yc.StrElem('fruit')
        ]
    ]

config = DessertConfig()

# Set the 'fruit' element of the 'pie' element to have a
# default of 'apple'.
config.set_default('pie.fruit', 'apple')

class Config2(yc.YamlConfigLoader):
    ELEMENTS = [
        yc.ListElem('cars', sub_elem=yc.KeyedElem(elements=[
            yc.StrElem('color'),
            yc.StrElem('make')
        ]
    ]

    def __init__(self, default_color):
        # The Config init is a good place to do this.
        # Set all the default color for all cars in the 'cars'
        # list to red.
        config.set_default('cars.*.color', 'red')

        super(self, Config2).__init__()
Parameters
  • dotted_key (str) – The dotted key path to the element to set the default on.

  • value – The value to set the default to. This validated.

Raises

ValueError – If the default fails validation.

Returns

None

validate(value, partial=False)
Ensure the given values conform to the config specification. Also

adds any derived element values.

Parameters
  • value (dict) – The dictionary of values to validate.

  • partial (bool) – Ignore ‘required’.

Returns dict

The validated and type converted value dict.

Raises
  • TypeError – if type conversion can’t occur.

  • ValueError – When the value is not within range.

  • RequiredError – When a required value is missing.

  • KeyError – For duplicate or malformed keys.

Category Yaml Config Loaders

CatYamlConfigLoader uses a CategoryElem as root, resulting in a dictionary that can have flexibly defined keys, but the keys must share an element type. This is for when you know what each config item will look like, but don’t know their names or quantities.

class yaml_config.CatYamlConfigLoader(name='<root>')

This is just like YamlConfigLoader, except instead of giving a list of elements to use as strict keys in a KeyedElem, we get a single BASE to use as the type for each sub-element in a CategoryElem.

Example:

import yaml_config as yc

class UserConfig(yc.CateYamlConfigLoader):
    # This is the type that each key must conform to.
    BASE = yc.KeyedElem(elements=[
        # We define elements just like for the YamlConfigLoader. As a
        # KeyedElem, these are the only keys allowed
        yc.StrElem('first_name', required=True),
        yc.StrElem('last_name', required=True),
        yc.IntRangeElem('age', vmin=1, required=True)
    ]

In this case, a valid config can have many users defined:

coulson:
    first_name: Phillip
    last_name: Coulson
    age: 52

mmay:
    first_name: Melinda
    last_name: May
    age: 54
Variables
  • HEADER ([str]) – The documentation that should appear at the top of the config file.

  • BASE (ConfigElement) – A single ConfigElement describing what all the keys at the base level of this config must look like.

List Yaml Config Loaders

List Yaml Config Loaders have a ListElem as their root, and result in a list as the base of the config data.

class yaml_config.ListYamlConfigLoader(name='<root>')

A YamlConfigLoader where the base element is a ListElem. Like normal list elements, all items in the list must have the same element type, described by BASE.

Example:

import yaml_config as yc

class ShoppingList(yc.ListYamlConfig):
    BASE = yc.StrElem()

An example ‘shopping list’ config could look like:

- banannas
- correctly spelled bananas
- apples
- cantaloupe
Variables
  • HEADER ([str]) – The documentation that should appear at the top of the config file.

  • BASE (ConfigElement) – A single ConfigElement describing what each item in the base level list of this config must look like.

Yaml Config Loader Mixin

This mixin converts a ConfigElement class into a YamlConfig-like class, adding dump and load methods. Unlike most mixins, it should occur after the regular base class in calling order.

class yaml_config.YamlConfigLoaderMixin

Converts a ConfigElement class into a class that also knows how to load and dump the configuration to file. A class variable of some sort, to be overridden by the class end-user, is expected to hold the information to initialize the ConfigElement base. Only KeyedElem, CategoryElem, and ListElem really make since as bases to mix this in with.