config_resolver package

Submodules

config_resolver.core module

Core functionality of config_resolver

class config_resolver.core.ConfigID(group, app)[source]

Bases: tuple

app

Alias for field number 1

group

Alias for field number 0

class config_resolver.core.FileReadability(is_readable, filename, reason, version)[source]

Bases: tuple

filename

Alias for field number 1

is_readable

Alias for field number 0

reason

Alias for field number 2

version

Alias for field number 3

class config_resolver.core.LookupMetadata(active_path, loaded_files, config_id, prefix_filter)[source]

Bases: tuple

active_path

Alias for field number 0

config_id

Alias for field number 2

loaded_files

Alias for field number 1

prefix_filter

Alias for field number 3

class config_resolver.core.LookupResult(config, meta)[source]

Bases: tuple

config

Alias for field number 0

meta

Alias for field number 1

config_resolver.core.effective_filename(config_id: config_resolver.core.ConfigID, config_filename: str) → str[source]

Returns the filename which is effectively used by the application. If overridden by an environment variable, it will return that filename.

config_id is used to determine the name of the variable. If that does not return a value, config_filename will be returned instead.

config_resolver.core.effective_path(config_id: config_resolver.core.ConfigID, search_path: str = '') → List[str][source]

Returns a list of paths to search for config files in order of increasing precedence: the last item in the list will override values of earlier items.

The value in config_id determines the sub-folder structure.

If search_path is specified, that value should have the OS specific path-separator (: or ;) and will completely override the default search order. If it is left empty, the search order is dictated by the XDG standard.

As a “last-resort” override, the value of the environment variable <GROUP_NAME>_<APP_NAME>_PATH will be inspected. If this value is set, it will be used instead of anything found previously (XDG paths, search_path value) unless the value is prefixed with a + sign. In that case it will be appended to the end of the list.

Examples:

>>> # Search the default XDG paths (and the CWD)
>>> effective_path(config_id)

>>> # Search only in "/etc/myapp"
>>> effective_path(config_id, search_path="/etc/myapp")

>>> # Search only in "/etc/myapp" and "/etc/fallback"
>>> effective_path(config_id, search_path="/etc/myapp:/etc/fallback")

>>> # Add "/etc/myapp" to the paths defined by XDG
>>> assert os.environ["FOO_BAR_PATH"] == "+/etc/myapp"
>>> effective_path(ConfigId("foo", "bar"))
config_resolver.core.env_name(config_id: config_resolver.core.ConfigID) → str[source]

Return the name of the environment variable which contains the file-name to load.

config_resolver.core.find_files(config_id: config_resolver.core.ConfigID, search_path: Optional[List[str]] = None, filename: str = '') → Generator[str, None, None][source]

Looks for files in default locations. Returns an iterator of filenames.

Parameters:
  • config_id – A “ConfigID” object used to identify the config folder.
  • search_path – A list of paths to search for files.
  • filename – The name of the file we search for.
config_resolver.core.from_string(data: str, handler: Optional[config_resolver.handler.base.Handler[typing.Any][Any]] = None) → config_resolver.core.LookupResult[source]

Load a config from the string value in data. handler can be used to specify a custom parser/handler.

config_resolver.core.get_config(app_name: str, group_name: str = '', lookup_options: Optional[Dict[str, Any]] = None, handler: Optional[Type[config_resolver.handler.base.Handler[typing.Any][Any]]] = None) → config_resolver.core.LookupResult[source]

Factory function to retrieve new config instances.

app_name is the only required argument for config lookups. If nothing else is specified, this will trigger a lookup in default XDG locations for a config file in a subfolder with that name.

group_name is an optional subfolder which is prefixed to the subfolder based on the app_name. This can be used to group related configurations together.

To summarise the two above paragraphs the relative path (relative to the search locations) will be:

  • <app_name>/<filename> if only app_name is given
  • <group_name>/<app_name>/<filename> if both app_name and group_name are given

lookup_options contains arguments which allow more fine-grained control of the lookup process. See below for details.

The handler may be a class which is responsible for loading the config file. config_resolver uses a “.ini” file handler by default and comes bundled with a JSON handler as well. They can be found in the :py:module:`config_resolver.handler` package.

Note

The type of the returned config-object depends on the handler. Each handler has its own config type!

For example, loading JSON files can be achieved using:

>>> from config_resolver.handler.json import JsonHandler
>>> get_config("myapp", handler=JsonHandler)

lookup_options is a dictionary with the following optional keys:

filename (default=``’’``)
This can be used to override the default filename of the selected handler. If left empty, the handler will be responsible for the filename.
search_path (default=``[]``)
A list of folders that should be searched for config files. The order here is relevant. The folders will be searched in order, and each file which is found will be loaded by the handler. Note that the search path should not include group_name or app_name as they will be appended automatically.
require_load (default=``False``)
A boolean value which determines what happens if no file was loaded. If this is set to True the call to get_config will raise an exception if no file was found. Otherwise it will log a debug message.
version (default=``None``)

This can be a string in the form <major>.<minor>. If specified, the lookup process will request a version number from the handler for each file found. The version in the file will be compared with this value. If the minor-number differs, the file will be loaded, but a warning will be logged. If the major number differs, the file will be skipped and an error will be logged. If the value is left unset, no version checking will be performed. If this is left unspecified and a config file is encountered with a version number, a sanity check is performed on subsequent config-files to ensure that no mismatching major versions are loaded in the lookup-chain.

How the version has to be stored in the config file depends on the handler.

secure (default=``False``)
If set to True, files which are world-readable will be ignored. This forces you to have secure file-access rights because the file will be skipped if the rights are too open.
config_resolver.core.get_xdg_dirs(config_id: config_resolver.core.ConfigID) → List[str][source]

Returns a list of paths specified by the XDG_CONFIG_DIRS environment variable or the appropriate default. See The Freedesktop XDG standard for details.

The list is sorted by precedence, with the most important item coming last (required by the existing config_resolver logic).

The value in config_id is used to determine the sub-folder structure.

config_resolver.core.get_xdg_home(config_id: config_resolver.core.ConfigID) → str[source]

Returns the value specified in the XDG_CONFIG_HOME environment variable or the appropriate default. See The Freedesktop XDG standard for details.

config_resolver.core.is_readable(config_id: config_resolver.core.ConfigID, filename: str, version: Optional[packaging.version.Version] = None, secure: bool = False, handler: Optional[Type[config_resolver.handler.base.Handler[typing.Any][Any]]] = None) → config_resolver.core.FileReadability[source]

Check if filename can be read. Will return boolean which is True if the file can be read, False otherwise.

Parameters:
  • filename – The exact filename which should be checked.
  • version – The expected version, that should be found in the file.
  • secure – Whether we should avoid loading insecure files or not.
  • handler – The handler to be used to open and parse the file.
config_resolver.core.prefixed_logger[source]

Returns a log instance and prefix filter for a given group- & app-name pair.

It applies a filter to the logger which prefixes the log messages with group- and application-name from the config.

The call to this function is cached to ensure we only have one instance in memory.

config_resolver.exc module

Exceptions for the config_resolver package

exception config_resolver.exc.NoVersionError[source]

Bases: Exception

This exception is raised if the application expects a version number to be present in the config file but does not find one.

config_resolver.util module

Helpers and utilities for the config_resolver package.

This module contains stuff which is not directly impacting the business logic of the config_resolver package.

class config_resolver.util.PrefixFilter(prefix: str, separator: str = ' ')[source]

Bases: logging.Filter

A logging filter which prefixes each message with a given text.

Parameters:
  • prefix – The log prefix.
  • separator – A string to put between the prefix and the original log message.
filter(record: logging.LogRecord) → bool[source]

Determine if the specified record is to be logged.

Is the specified record to be logged? Returns 0 for no, nonzero for yes. If deemed appropriate, the record may be modified in-place.

Module contents

The config_resolver package provides an easy way to create an instance of a config object.

The main interface of this package is config_resolver.core.get_config() (also provided via config_resolver.get_config).

This function takes a fair amount of options to control how config files are loaded. The easiest example is:

>>> from config_resolver import get_config
>>> config, metadata = get_config("myapp")

This call will scan through a number of folders and load/update the config with every matching file in that chain. Some customisation of that load process is made available via the get_config() arguments.

The call retuns a config instance, and some meta-data related to the loading process. See get_config() for details.

config_resolver comes with support for .json and .ini files out of the box. It is possible to create your own handlers for other file types by subclassing config_resolver.handler.Handler and passing it to get_config()