midgard.config.config

Midgard library module for handling of configuration settings

Description:

A Configuration consists of one or several sections. Each ConfigurationSection consists of one or more entries. Each ConfigurationEntry consists of a key and a value.

Examples:

For basic use, an entry is looked up by simple attribute access. For instance if cfg is a Configuration with the section midgard which has an entry foo = bar:

>>> cfg = Configuration("config_name")
>>> cfg.update("midgard", "foo", "bar")
>>> cfg.midgard.foo
ConfigurationEntry(key='foo', value='bar')

ConfigurationEntry has several access methods that convert the entry to a given data type:

>>> cfg.update("midgard", "foo_pi", 3.14, source="command line")
>>> cfg.midgard.foo_pi
ConfigurationEntry(key='foo_pi', value='3.14')
>>> cfg.midgard.foo_pi.float
3.14
>>> cfg.midgard.foo_pi.str
'3.14'
>>> cfg.midgard.foo_pi.tuple
('3.14',)

Sources:

Each configuration entry records its source. That is, where that entry was defined. Examples include read from file, set as a command line option, or programmatically from a dictionary. The source can be looked up on an individual entry, or for all entries in a configuration.

>>> cfg.midgard.foo_pi.source
'command line'
>>> cfg.sources  # doctest: +SKIP
{'/home/midgard/midgard.conf', 'command line'}

Profiles:

Fallback Configuration:

Master Section:

Replacement Variables:

Help text and Type hints:

CasedConfigParser

CasedConfigParser(defaults=None, dict_type=<class 'collections.OrderedDict'>, allow_no_value=False, *, delimiters=('=', ':'), comment_prefixes=('#', ';'), inline_comment_prefixes=None, strict=True, empty_lines_in_values=True, default_section='DEFAULT', interpolation=<object object at 0x7f62cc5921a0>, converters=<object object at 0x7f62cc5921a0>)

ConfigParser with case-sensitive keys

CasedConfigParser.BOOLEAN_STATES (dict)

BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True, '0': False, 'no': False, 'false': False, 'off': False}

CasedConfigParser.NONSPACECRE (SRE_Pattern)

NONSPACECRE = re.compile('\\S')

CasedConfigParser.OPTCRE (SRE_Pattern)

OPTCRE = re.compile('\n (?P<option>.*?) # very permissive!\n \\s*(?P<vi>=|:)\\s* # any number of space/tab,\n # followed by any of t, re.VERBOSE)

CasedConfigParser.OPTCRE_NV (SRE_Pattern)

OPTCRE_NV = re.compile('\n (?P<option>.*?) # very permissive!\n \\s*(?: # any number of space/tab,\n (?P<vi>=|:)\\s* # optionally followed , re.VERBOSE)

CasedConfigParser.SECTCRE (SRE_Pattern)

SECTCRE = re.compile('\n \\[ # [\n (?P<header>[^]]+) # very permissive!\n \\] # ]\n ', re.VERBOSE)

CasedConfigParser.optionxform()

optionxform(self, optionstr:str) -> str

Do not turn optionstr (key) into lowercase

Configuration

Configuration(name:str) -> None

Represents a Configuration

Configuration.as_dict()

as_dict(self, getters:Union[Dict[str, Dict[str, str]], NoneType]=None, default_getter:str='str') -> Dict[str, Dict[str, Any]]

The configuration represented as a dictionary

Args:

Returns:

Representation of the configuration as a nested dictionary.

Configuration.as_str()

as_str(self, width:Union[int, NoneType]=None, key_width:int=30, only_used:bool=False, metadata:bool=True) -> str

The configuration represented as a string

This is simililar to what is shown by str(configuration) (and implemented by __str__), but has more flexibility.

Args:

Returns:

String representation of the configuration.

Configuration.clear()

clear(self) -> None

Clear the configuration

Configuration.clear_vars()

clear_vars(self) -> None

Clear the configuration variables

Configuration.get()

get(self, key:str, value:Union[str, NoneType]=None, section:Union[str, NoneType]=None, default:Union[str, NoneType]=None) -> 'ConfigurationEntry'

Get an entry from a configuration with possibility for override and default value

A value for an entry is found using the following priorities:

1. An explicit value given in `value`. None is used as a marker for no value.
2. Looked up in the current configuration.
3. Looked up in any fallback confiurations that are defined.
4. The default value is used.

If value is not None, that value is simply returned as a ConfigurationEntry. If default is not given (is None), and a value is not found in any other way, a MissingEntryError is raised.

Args:

Returns:

Entry representing the value.

Configuration.read_from_file()

read_from_file(cfg_name:str, *file_paths:Union[str, pathlib.Path]) -> 'Configuration'

Read a configuration from one or more files

Args:

Returns:

A Configuration representing the file(s).

Configuration.update()

update(self, section:str, key:str, value:str, *, profile:Union[str, NoneType]=None, source:str='unknown', meta:Union[Dict[str, str], NoneType]=None, allow_new:bool=True, _update_sections:bool=True) -> None

Update a configuration section with a configuration entry

If allow_new is False, the configuration entry must already exist. If it is True the update is allowed to create a new section and a new entry is necessary.

The _update_sections flag can be used to not update the sections of the configuration, only the profiles. This should typically not be done, but is used by some of the other update methods which update the sections themselves.

Args:

Configuration.update_from_config_section()

update_from_config_section(self, other_section:'ConfigurationSection', section:Union[str, NoneType]=None, allow_new:bool=True) -> None

Configuration.update_from_dict()

update_from_dict(self, cfg_dict:Dict[str, Any], section:Union[str, NoneType]=None, source:str='dictionary', allow_new:bool=True) -> None

Configuration.update_from_file()

update_from_file(self, file_path:Union[str, pathlib.Path], allow_new:bool=True, interpolate:bool=False, case_sensitive:bool=False) -> None

Update the configuration from a configuration file

The Python ConfigParser is used to read the file. The file format that is supported is described at https://docs.python.org/library/configparser.html

Different profiles in a configuration file is denoted by double underscores in the sections names. For instance does the following configuration have a foo profile in the spam section (in addition to the default profile):

[spam]
...

[spam__foo]
...

If interpolate is set to True, ExtendedInterpolation of variables in the configuration file is used. See https://docs.python.org/library/configparser.html#configparser.ExtendedInterpolation for details.

Args:

Configuration.update_from_options()

update_from_options(self, options:Union[List[str], NoneType]=None, profile:Union[str, NoneType]=None, source:str='command line', allow_new:bool=False) -> None

Configuration.update_on_file()

update_on_file(file_path:Union[str, pathlib.Path], **as_str_args:Any) -> Generator

Context manager for updating a configuration on file

Configuration.update_vars()

update_vars(self, new_vars:Dict[str, Any]) -> None

Update the configuration variables

Configuration.write_to_file()

write_to_file(self, file_path:Union[str, pathlib.Path], **as_str_args:Any) -> None

Write the configuration to a file

In addition to the file path, arguments can be specified and will be passed on to the as_str() function. See as_str() for more information.

Todo: Use files.open_path

ConfigurationEntry

ConfigurationEntry(key:str, value:Any, *, source:str='', meta:Union[Dict[str, str], NoneType]=None, vars_dict:Union[Dict[str, Any], NoneType]=None, _used_as:Union[Set[str], NoneType]=None) -> None

ConfigurationEntry.as_bool()

as_bool(self) -> bool

Value of ConfigurationEntry converted to a boolean

The conversion is done by looking up the string value of the entry in _BOOLEAN_STATES.

ConfigurationEntry.as_date()

as_date(self, format:str='%Y-%m-%d') -> datetime.date

Value of ConfigurationEntry converted to a date object

Args:

format (String): Format string, see strftime for information about the string.

Returns:

ConfigurationEntry.as_datetime()

as_datetime(self, format:str='%Y-%m-%d %H:%M:%S') -> datetime.datetime

Value of ConfigurationEntry converted to a datetime object

Args:

format (String): Format string, see strftime for information about the string.

Returns:

ConfigurationEntry.as_dict()

as_dict(self, item_split_re:str='[\\s,]', key_value_split_re:str='[:]', convert:Callable=<class 'str'>, maxsplit:int=0) -> Dict[str, Any]

Value of ConfigurationEntry converted to a dictionary

By default the dictionary is created by splitting items at commas and whitespace, and key from value at colons.

Args:

Returns:

Value of entry as dict.

ConfigurationEntry.as_enum()

as_enum(self, enum:str) -> enum.Enum

Value of ConfigurationEntry converted to an enumeration

Args:

enum (String): Name of Enum.

Returns:

ConfigurationEntry.as_float()

as_float(self) -> float

Value of ConfigurationEntry converted to a float

ConfigurationEntry.as_int()

as_int(self) -> int

Value of ConfigurationEntry converted to an integer

ConfigurationEntry.as_list()

as_list(self, split_re:str='[\\s,]', convert:Callable=<class 'str'>, maxsplit:int=0) -> List[Any]

Value of ConfigurationEntry converted to a list

The entry is converted to a list by using the split_re-regular expression. By default the entry will be split at commas and whitespace.

Args:

Returns:

Value of entry as list.

ConfigurationEntry.as_list_of_lists()

as_list_of_lists(self, split_res:Tuple[str, ...]=('[\\s,]', '[^_\\w]'), num_elements:Union[int, NoneType]=None, convert:Callable=<class 'str'>) -> List[List[Any]]

ConfigurationEntry.as_path()

as_path(self) -> pathlib.Path

Value of ConfigurationEntry interpreted as a path string

ConfigurationEntry.as_str()

as_str(self) -> str

Value of ConfigurationEntry as string

ConfigurationEntry.as_tuple()

as_tuple(self, split_re:str='[\\s,]', convert:Callable=<class 'str'>, maxsplit:int=0) -> Tuple[Any, ...]

Value of ConfigurationEntry converted to a tuple

The entry is converted to a tuple by using the split_re-regular expression. By default the entry will be split at commas and whitespace.

Args:

Returns:

Value of entry as tuple.

ConfigurationEntry.entry_as_str()

entry_as_str(self, width:Union[int, NoneType]=None, key_width:int=30, metadata:bool=True) -> str

The configuration entry represented as a string

This is simililar to what is shown by str(entry) (and implemented by __str__), but has more flexibility.

Args:

Returns:

String representation of the configuration entry.

ConfigurationEntry.replace()

replace(self, default:Union[str, NoneType]=None, **replace_vars:str) -> 'ConfigurationEntry'

ConfigurationSection

ConfigurationSection(name:str) -> None

ConfigurationSection.as_dict()

as_dict(self, getters:Dict[str, str]=None, default_getter:str='str') -> Dict[str, Any]

The configuration section represented as a dictionary

Args:

Returns:

Representation of the configuration section as a dictionary.

ConfigurationSection.as_list()

as_list(self) -> List[str]

List of keys of entries in configuration section

Returns:

List of keys of entries in configuration section.

ConfigurationSection.as_str()

as_str(self, width:Union[int, NoneType]=None, key_width:int=30, only_used:bool=False, metadata:bool=True) -> str

The configuration section represented as a string

This is simililar to what is shown by str(section) (and implemented by __str__), but has more flexibility.

Args:

Returns:

String representation of the configuration section.

FMT_date (str)

FMT_date = '%Y-%m-%d'

FMT_datetime (str)

FMT_datetime = '%Y-%m-%d %H:%M:%S'

FMT_dt_file (str)

FMT_dt_file = '%Y%m%d-%H%M%S'