Source code for bag.settings
"""Facilitate materialization of resources indicated in configuration."""
from importlib import import_module
from types import ModuleType
[docs]def read_ini_files(*config_files, encoding="utf-8"):
"""Get a settings object (dict-like) by reading some ``config_files``."""
from configparser import ConfigParser
settings = ConfigParser()
settings.read(config_files, encoding=encoding)
return settings
[docs]def resolve(resource_spec):
"""Return the variable referred to in the ``resource_spec`` string.
Example resource_spec: ``"my.python.module:some_callable"``.
"""
if isinstance(resource_spec, ModuleType) or callable( # arg is a python module
resource_spec
): # arg is a callable
return resource_spec
parts = resource_spec.split(":") # arg is assumed to be a string
if len(parts) == 1:
return import_module(parts[0])
elif len(parts) == 2:
module = import_module(parts[0])
return getattr(module, parts[1])
else:
raise ValueError(
'":" may appear only once in a resource spec, but I received "{}"'.format(
resource_spec
)
)
[docs]def resolve_path(resource_spec):
"""Return a pathlib.Path corresponding to the ``resource_spec`` string.
Example argument: ``"my.python.module:some/subdirectory"``
Similar: ``from pyramid.resource import abspath_from_asset_spec``
"""
from pathlib import Path
module, var = resource_spec.split(":") # arg is assumed to be a string
module = import_module(module)
return Path(module.__path__[0], var)
[docs]def asbool(s):
"""Convert the argument to a boolean.
Return the boolean value ``True`` if the case-lowered value of string
input ``s`` is a truthy string. If ``s`` is already one of the
boolean values ``True`` or ``False``, return it.
"""
if s is None:
return False
if isinstance(s, bool):
return s
val = _boolean_states.get(str(s).strip().lower())
if val is None:
raise ValueError('Not a boolean: "%s"' % s)
return val
_boolean_states = {
"1": True,
"yes": True,
"true": True,
"on": True,
"0": False,
"no": False,
"false": False,
"off": False,
}
[docs]class SettingsReader:
"""Convenient for reading configuration settings in an app.
However, with Python 3.6+ I have used the **pydantic** library
with better results.
"""
def __init__(self, adict):
"""``adict`` should be a settings dictionary."""
self.settings = adict
[docs] def read(self, key, default=None, required=False):
"""Return setting value, or ``default`` if missing.
Raise RuntimeError if ``required`` is true and value is empty.
"""
value = self.settings.get(key, default)
if required and value in (None, ""):
raise RuntimeError('Settings are missing a "{}" entry.'.format(key))
return value
[docs] def bool(self, key, default=None, required=False):
"""Return a boolean setting value."""
value = self.read(key, default=default, required=required)
return asbool(value)
[docs] def resolve(self, key, default=None, required=False):
"""Return the variable or module indicated in the setting value.
Therefore the setting value should be a resource specification
such as ``some.module:SomeClass``.
"""
resource_spec = self.read(key, default=default, required=required)
return None if resource_spec is None else resolve(resource_spec)
[docs] def resolve_path(self, key, default=None, required=False):
"""Return a pathlib.Path corresponding to the setting value.
Example argument: ``"my.python.module:some/subdirectory"``
"""
resource_spec = self.read(key, default=default, required=required)
return None if resource_spec is None else resolve_path(resource_spec)