Accessing Config Values

Once the config object is created, the primary way to access values in the config is via the pull() (while you can update individual values using push()). Optionally, you can provide a default value to be returned if the query is not found. If no default value is provided, a SearchFailed error is raised (which is subclass of KeyError). Additionally, the pulls() method allows you to provide any number of fallback queries.

Note

_ and - are interchangeable in config keys

When reading (aka pulling) arguments from the config, if an argument is not found in the current branch and the query is not hidden (i.e. it does not begin with _), it will automatically defer to the higher branches (aka parent branch) as well, which allows users to define more or less “global” arguments depending on how deep the node containing the argument actually is. Although this behavior can be changed using the ask_parents key in the config settings.

For example, given the config object that is loaded from the this yaml file (registered as myconfig):

favorites:
    games: [Innovation, Triumph and Tragedy, Inis, Nations]
    language: Python
    activity: <>games.0

wallpaper:
    color: red

jacket:
    size: 30

nights: 2
trip:
    - location: London
      nights: 3
    - location: Berlin
    - location: Moscow
      nights: 4

app:
    price: 1.99
    color: <>wallpaper.color

When this yaml file is loaded (e.g. config = fig.create_config('myconfig')), we could use it like so:

assert config.pull('favorites.language') == 'Python'
assert config.pull('favorites.0') == 'Innvoation'
assert config.pull('app.color') == 'red'
assert config.pull('favorites.activity') == 'Innovation'
assert config.pull('trip.0.location') == 'London'
assert config.pull('trip.1.nights', 4) == 2
assert config.pull('app.publisher', 'unknown') == 'unknown' # default

assert config.pulls('jacket.color', 'wallpaper.color') == 'red'
assert config.pulls('jacket.price', 'price', 'total_cost', default='too much') == 'too much'

While this example should give you a sense for what kind of features the config system offers, a more comprehensive list of how queries in the config are resolved and the values are processed.

See the feature slide B5.

Queries

In addition to the behavior described above, the keys (or indices) in a config branch have the following features (where {} refers to any value):

  • '_{}' - hidden query - is not visible to child branches when they defer to parents

  • push()/pull() '{1}.{2}' - deep query - equivalent to ['{1}']['{2}']

  • push() '{1}.{2}' where '{1}' is missing - deep push - automatically creates a new branch '{1}' in config and then pushes '{2}' to that new branch

Values

The values of arguments also have a few special features worth noting:

  • '<>{}' - local alias - defer to value of {} starting search for the key here

  • '<o>{}' - (advanced feature) origin alias - defer to value of {} starting search at origin (this only makes a difference when chaining aliases, origin refers to the branch where pull() was called)

  • '_x_' - remove key if encountered (during update) - remove corresponding key it it appears in the config being updated

  • __x__ - cut deferring chain of key - behaves as though this key didn’t exist (and doesn’t defer to parent)

Currently there are no escape sequences, so any values starting with <> or <o> will be treated as aliases and values that are _x_ or __x__ will not be processed as regular strings. However, if necessary, you can easily implement a component to escape these values using the automatic object instantiation, like so:

@fig.autocomponent('escaped-str')
def escape_str(value):
    return value

cfg = fig.create_config(special={'_type': 'escaped-str', 'value':'<>some-value'})

assert cfg.pull('special') == '<>some-value'