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:
getters
: How to get the value of each entry in each section.default_getter
: How to get the value of entries not specified in getters.
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:
width
: Width of text for wrapping. Default is width of console.key_width
: Width of the key column. Default is 30 characters.only_used
: Only include configuration entries that has been used so far.metadata
: Include metadata like type and help text.
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:
key
: Name of option (key in the configuration entry).value
: Value of entry. Used for overriding the configuration.section
: Section in the configuration in which to look up the key.default
: Default value that is returned if value is not found any other way.
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:
file_paths
: File(s) that will be read.
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:
section
: Section to update.key
: Key of entry.value
: Value of entry.profile
: Profile to update.source
: Source of the update.meta
: Metadata like help text and type hints for the entry.allow_new
: Whether to allow the creation of a new section and entry.
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:
file_path
: Path to the configuration file.allow_new
: Whether to allow the creation of new sections and entries.interpolate
: Whether to interpolate variables in the configuration file.case_sensitive
: Whether to read keys as case sensitive (or convert to lower case).
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:
Date
: Value of entry.
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:
Datetime
: Value of entry.
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:
item_split_re
: Regular expression used to split entry into items.key_value_split_re
: Regular expression used to split items into keys and values.convert
: Function used to convert each value in the dictionary.maxsplit
: If nonzero, at most maxsplit splits occur when splitting entry into items.
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:
Enum
: Value of entry as Enum.
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:
split_re
: Regular expression used to split entry into list.convert
: Function used to convert each element of the list.maxsplit
: If nonzero, at most maxsplit splits occur.
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:
split_re
: Regular expression used to split entry into tuple.convert
: Function used to convert each element of the tuple.maxsplit
: If nonzero, at most maxsplit splits occur.
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:
width
: Width of text for wrapping. Default is width of console.key_width
: Width of the key column. Default is 30 characters.metadata
: Include metadata like type and help text.
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:
getters
: How to get the value of each entry in the section.default_getter
: How to get the value of entries not specified in getters.
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:
width
: Width of text for wrapping. Default is width of console.key_width
: Width of the key column. Default is 30 characters.only_used
: Only include configuration entries that has been used so far.metadata
: Include metadata like type and help text.
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'