ConfigDict

class configdict.configdict.ConfigDict(name, default=None, validator=None, docs=None, adaptor=None, precallback=None, persistent=False, load=True, fmt='yaml', sortKeys=False, description='', strict=True, advancedPrefix='.')[source]

Bases: CheckedDict

This is an optionally persistent dictionary used for configuration.

It is saved under the config folder determined by the OS (and is thus OS dependent). In persistent mode no two instances of the same config can coexist.

Parameters:
  • name (str) – a str of the form prefix.name or prefix/name (these are the same) or simply name if this is an isolated configuration. The data will be saved at $USERCONFIGDIR/{prefix}/{name}.{fmt} if prefix is given, or $USERCONFIGDIR/{name}.{fmt}. For instance, in Linux a config with a name “myproj.myconfig” and a yaml format will be saved to “~/.config/mydir/myconfig.yaml”

  • default (Optional[dict[str, Any]]) – a dict with all default values. A config can accept only keys which are already present in the default. This argument can be None if the config is built successively via ConfigDict.addKey() (see example below) but the dict is not usable until all the keys have been added and the user calls ConfigDict.load() explicitely

  • validator (Optional[dict[str, Any]]) –

    a dict containing choices, types and/or ranges for the keys in the default. Given a default like: {'keyA': 'foo', 'keyB': 20}, a validator could be:

    {
      'keyA::choices': ['foo', 'bar'],
      'keyB::type': float,
      'keyB::range': (10, 30)
    }
    

    Choices can be defined lazyly by giving a lambda

  • docs (Optional[dict[str, str]]) – a dict containing documentation for each key

  • persistent – if True, any change to the dict will be automatically saved. Otherwise a dict can be saved manually via ConfigDict.save()

  • load – if True, the saved version will be loaded after creation. This is disabled if no default dict is given. This is the case when building the default after creation - ConfigDict.load() should be called manually in this case (see example).

  • precallback (Optional[Callable[[ConfigDict, str, Any, Any], Any]]) – function (dict, key, oldvalue, newvalue) -> None|newvalue, If given, it is called before the modification is done. This function should return None to allow modification, any value to modify the value, or raise ValueError to stop the transaction

  • sortKeys – if True, keys are sorted whenever the dict is saved/edited.

  • advancedPrefix – keys with this prefix are marked as advanced. Whenever the dict is displayed or edited, these keys appear after all the other keys

Example

# No default given. The default is built by adding keys subsequently.
# load needs to be called to end the declaration
# This method is somewhat similar to ArgParse
config = ConfigDict("myproj.subproj")
config.addKey("keyA", 10, doc="documentaion of keyA")
config.addKey("keyB", 0.5, range=(0, 1))
config.addKey("keyC", "blue", choices=("blue", "red"),
              doc="documentation of keyC")
config.load()

# Alternatively, a config can be built within a context manager. 'load'
is called when exiting the context:

with ConfigDict("maelzel.snd.plotting") as conf
    conf.addKey('backend', 'matplotlib', choices={'matlotlib'})
    conf.addKey('spectrogram.colormap', 'inferno', choices=_cmaps)
    conf.addKey('samplesplot.figsize', (24, 4))
    conf.addKey('spectrogram.figsize', (24, 8))
    conf.addKey('spectrogram.maxfreq', 12000,
                doc="Highest frequency in a spectrogram")

# The same effect can be achieved by passing the default/validator/doc

default = {
    "keyA": 10,
    "keyB": 0.5,
    "keyC": "blue
}

validator = {
    "keyB::range": (0, 1),
    "keyC::choices": ("blue", "red")
}

docs = {
    "keyA": "documentation of keyA"
    "keyC": "documentation of keyC"
}

cfg = ConfigDict("myproj.subproj",
                 default=default,
                 validator=validator,
                 docs=docs)
# no need to call .load in this case

# Using inheritance
class MyConfig(ConfigDict):
    def __init__(self):
        super().__init__(name="myconfig",
                         default=default,
                         validator=validator,
                         docs=docs)

cfg = MyConfig()

Attributes Summary

name

The name of this ConfigDict.

persistent

Is this a persistent ConfigDict?

Methods Summary

__call__(key, value[, type, choices, range, ...])

Call self as a function.

addKey(key, value[, type, choices, range, ...])

Add a key: value pair to the default settings.

asCsv()

Returns this dict as a csv str, with columns: key, value, spec, doc

asYaml([sortKeys])

Returns this dict as yaml str, with comments, defaults, etc.

checkDict(d)

Check if dict d can be used to update self

checkValue(key, value)

Check if value is valid for key

clear()

clone([updates, name, persistent, ...])

Create a clone of this dict

copy()

Create a copy if this dict.

diff([other])

Get a dict containing keys:values which differ from the default or from another dict

dump()

Dump this config to stdout

edit([waitOnModified, sortKeys])

Edit this config by opening it in an external application.

fromkeys([value])

Create a new dictionary with keys from iterable and values set to value.

generateRstDocumentation([maxWidth, ...])

Generate ReST documentation for this dictionary

get(key[, default])

Return the value for key if key is in the dictionary, else default.

getChoices(key)

Return a seq.

getDoc(key)

Get documentation for key (if present)

getPath()

Return the path this dict will be saved to

getRange(key)

Returns the valid range for this key's value, if specified.

getType(key)

Returns the expected type for key's value

getTypestr(key)

The same as .getType but returns a string representation of the type

getValidateFunc(key)

Returns a function to validate a value for key

isCongruentWith(other)

Returns True if self and other share same default

items()

keys()

load([configpath])

Read the saved config, update self.

makeDefault()

Create a version of this class with all values set to the default

normalizeKey(key)

rtype:

str

override(key, value[, default])

The same as value if value is not None else config.get(key, default)

pop(k[,d])

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

registerCallback(func[, pattern])

Register a callback to be fired when a key matching the given pattern is changed.

reset([save])

Reset this dict to its default

resetKey(key)

Reset the given key to its default value

save([path, header])

Save this to its persistent path (or a custom path)

setdefault(key[, default])

Insert key with a value of default if key is not in the dictionary.

update([d])

Update this dict with the values in d.

updated([d])

The same as update(), but returns self

validatorTypes(key)

Return the validator types for a given key

values()

Attributes Documentation

name

The name of this ConfigDict. The name determines where it is saved

persistent

Is this a persistent ConfigDict?

Methods Documentation

__call__(key, value, type=None, choices=None, range=None, doc='', validatefunc=None)

Call self as a function.

Return type:

None

addKey(key, value, type=None, choices=None, range=None, validatefunc=None, adaptor=None, doc=None)

Add a key: value pair to the default settings.

This is used when building the default config item by item (see example). After adding all new keys it is necessary to call ConfigDict.load()

Example

cfg = ConfigDict("foo", load=False)
# We define a default step by step
cfg.addKey("width", 100, range=(50, 150))
cfg.addKey("color", "red", choices=("read", "blue", "green"))
cfg.addKey("height",
           doc="Height should be higher than width",
           validatefunc=lambda cfg, key, height: height > cfg['width'])
# Now update the dict with the newly defined default and any
# saved version
cfg.load()
Parameters:
  • key (str) – a string key

  • value (Any) – a default value

  • type (Union[type, tuple[type, ...], None]) – the type accepted, as passed to isinstance (can be a tuple)

  • choices (Union[Set, tuple, None]) – a set/tuple of possible values

  • range (Optional[tuple[Any, Any]]) – a (min, max) tuple defining an allowed range for this value

  • validatefunc (Optional[Callable[[dict, str, Any], bool]]) – a function (config: dict, key:str, value) -> bool, should return True if value is valid for key or False otherwise

  • doc (Optional[str]) – documentation for this key

Return type:

None

asCsv()[source]

Returns this dict as a csv str, with columns: key, value, spec, doc

Return type:

str

asYaml(sortKeys=False)

Returns this dict as yaml str, with comments, defaults, etc.

Return type:

str

checkDict(d)

Check if dict d can be used to update self

Parameters:

d (dict) – a dict which might update self

Return type:

str

Returns:

An error message if d has any invalid key or value, “” if everything is ok

checkValue(key, value)

Check if value is valid for key

This is only possible if a validator was set

Parameters:
  • key (str) – the key to check

  • value – the value to check according to the contraints defined for the key (range, type, etc)

Return type:

Optional[str]

Returns:

None if the value is acceptable for the key, an error message otherwise

Example

error = config.checkType(key, value)
if error:
    print(error)
clear() None.  Remove all items from D.
clone(updates=None, name=None, persistent=False, cloneCallbacks=True, **kws)[source]

Create a clone of this dict

Parameters:
  • name (Optional[str]) – the name of the clone. If not given, the name of this dict is used.

  • persistent – Should the clone be made persitent?

  • cloneCallbacks – should the registered callbacks of the original (if any) be cloned?

  • updates (Optional[dict]) – a dict with updates

  • **kws – same as updates but only for keys which are valid keywords

Return type:

TypeVar(_ConfigDictT, bound= ConfigDict)

Returns:

the cloned dict

copy()[source]

Create a copy if this dict.

The copy will be unnamed and not persistent. Use ConfigDict.clone() to create a named/persistent clone of this dict.

Return type:

TypeVar(_CheckedDictT, bound= CheckedDict)

Returns:

the copy of this dict

diff(other=None)

Get a dict containing keys:values which differ from the default or from another dict

Parameters:

other (Optional[dict]) – if given, another dict which this is compared against. Otherwise the diff is calculated to the default dict

Return type:

dict

Returns:

a dict containing key – value pairs where self differs from other

dump()[source]

Dump this config to stdout

edit(waitOnModified=True, sortKeys=False)[source]

Edit this config by opening it in an external application.

The format used is yaml. This is independent of the format used for persistence. The application used is the user’s default application for the .yaml format and can be configured at the os level. In macos we use open, in linux xdg-open and in windows start, which all respond to the user’s own configuration regarding default applications.

Note

A temporary file is created for editing. The persisted file is only modified if the editing is accepted.

Parameters:
  • waitOnModified – if True, the transaction is accepted whenever the file being edited is saved. Otherwise a message box is created which needs to be clicked in order to confirm the transaction. Just exiting the application will not cancel the edit job since many applications which have a server mode or unique instance mode might in fact exit right away from the perspective of the subprocess which launched them

  • sortKeys – if True, keys appear in sorted order

Return type:

None

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

generateRstDocumentation(maxWidth=80, withName=True, withDescription=True, withLink=True, linkPrefix='')[source]

Generate ReST documentation for this dictionary

The generated string can then be dumped to a file and included in documentation

Parameters:
  • maxWidth – the max. width of a line

  • withName – if True, add the name of the config (if it has a name)

  • withDescription – if True, add this dict’s description (if it has any)

  • withLink – if True, for each key:value pair generate a RST link using the given linkPrefix For example, for a key ‘foo’ and a linkPrefix=’config’ the generated link will be .. _configfoo. This link can be used within the documentation to link to this key

  • linkPrefix – a prefix to use for all links

Return type:

str

Returns:

the generated rst documentation, as str.

get(key, default=None, /)

Return the value for key if key is in the dictionary, else default.

getChoices(key)

Return a seq. of possible values for key k or None

Return type:

Optional[list]

getDoc(key)

Get documentation for key (if present)

Return type:

Optional[str]

getPath()[source]

Return the path this dict will be saved to

If the dict has no name, an empty string is returned

Return type:

str

getRange(key)

Returns the valid range for this key’s value, if specified.

Parameters:

key (str) – the key to get the range from.

Return type:

Optional[tuple]

Returns:

the range of values allowed for this key, or None if there is no range defined for this key.

Raises KeyError if the key is not present

getType(key)

Returns the expected type for key’s value

Parameters:

key (str) – the key to query

Return type:

Union[type, tuple[type, ...]]

Note

All numbers are reduced to type float, all strings are of type str, otherwise the type of the default value, which can be a collection like a list or a dict

See Also: checkValue()

getTypestr(key)

The same as .getType but returns a string representation of the type

Parameters:

key (str) – the key to query

Return type:

str

getValidateFunc(key)

Returns a function to validate a value for key

A validate function has the form (config, value) -> bool

Parameters:

key (str) – the key to query for a validate function

Return type:

Optional[Callable[[dict, str, Any], bool]]

Returns:

The validate function, or None

isCongruentWith(other)[source]

Returns True if self and other share same default

Return type:

bool

items() a set-like object providing a view on D's items
keys() a set-like object providing a view on D's keys
load(configpath=None)[source]

Read the saved config, update self.

If there is no saved version or the dict has no name, then the dict is set to the default defined at construction.

When defining the default iteratively (via addKey), calling load marks the end of the definition: after calling load no other keys can be added to this dict.

Parameters:

configpath (Optional[str]) – an custom path to load a saved version from. Otherwise it is loaded from ConfigDict.getPath() (this is only possible if the dict has a name, since the resolved path is determined from the name)

Return type:

None

Example

from configdict import ConfigDict
conf = ConfigDict('foo.bar')
conf.addKey('key1', 'value1', ...)
conf.addKey('key2', 'value2', ...)
...
# When finished defining keys, call .load
conf.load()

# Now the dict can be used

When

makeDefault()

Create a version of this class with all values set to the default

Return type:

TypeVar(_CheckedDictT, bound= CheckedDict)

static normalizeKey(key)
Return type:

str

override(key, value, default=None)

The same as value if value is not None else config.get(key, default)

Return type:

None

pop(k[, d]) v, remove specified key and return the corresponding value.

If the key is not found, return the default if given; otherwise, raise a KeyError.

popitem()

Remove and return a (key, value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.

registerCallback(func, pattern='.*')[source]

Register a callback to be fired when a key matching the given pattern is changed.

If no pattern is given, the function will be called for every key.

Parameters:
  • func (Callable[[ConfigDict, str, Any], None]) – a function of the form (dict, key, value) -> None, where dict is this ConfigDict itself, key is the key which was just changed and value is the new value.

  • pattern – a regex pattern. The function will be called if the pattern matches the key being modified.

Return type:

None

reset(save=True)[source]

Reset this dict to its default

Return type:

None

resetKey(key)[source]

Reset the given key to its default value

Return type:

None

save(path=None, header='')[source]

Save this to its persistent path (or a custom path)

If this config was created with the persistent flag on, it does not need to be saved manually, it is saved whenever it is modified. However if it was created with persistent=False then this method can be used to write this dict so it will be loaded in a future session

Parameters:
  • path (Optional[str]) – the path to save the config. If None and this is a named config, it is saved to the path returned by getPath()

  • header – if given, this string is written prior to the dict, as a comment. This is only supported when saving to yaml

Return type:

None

setdefault(key, default=None, /)

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update(d=None, **kws)[source]

Update this dict with the values in d.

Note

keywords have priority over d (similar to builtin dict)

Parameters:
  • d (Optional[dict]) – values in this dictionary will overwrite values in self. Keys not present in self will raise an exception

  • **kws – any key:value here will also be used to update self

Return type:

None

updated(d=None, **kws)

The same as update(), but returns self

Return type:

TypeVar(_CheckedDictT, bound= CheckedDict)

validatorTypes(key)

Return the validator types for a given key

A validator type for a given key can be a choices validator, where a set of possible values is given for a given key; it can be a range, where the value must be within a given range; a type, where a value must be of a certain type; or a function, which must return True if the value is valid, or False or an error message as string if the value is invalid

Parameters:

key (str) – the key to query

Return type:

list[str]

Returns:

a list of validator types, where each item is one of ‘choices’, ‘range’, ‘type’, ‘func’

values() an object providing a view on D's values