Files
OpenMTC/build/lib/openmtc/configuration.py
Christian Klopp e9af73dfe8 initial commit
2017-11-07 14:41:38 +01:00

179 lines
5.3 KiB
Python

import logging
from abc import ABCMeta, abstractmethod
from enum import Enum
from futile import NOT_SET, identity
from futile.logging import LoggerMixin
from openmtc.exc import OpenMTCError
class ConfigurationError(OpenMTCError):
pass
class ConfigurationKeyError(KeyError, ConfigurationError):
pass
class ConfigurationAttributeError(AttributeError, ConfigurationError):
pass
class ConfigurationValueError(ValueError, ConfigurationError):
pass
class ExtraOptionsStrategy(Enum):
ignore = "ignore"
warn = "warn"
prune = "prune"
fatal = "fatal"
class ConfigurationOption(LoggerMixin):
__metaclass__ = ABCMeta
def __init__(self, type, default=NOT_SET, converter=identity,
*args, **kw):
super(ConfigurationOption, self).__init__(*args, **kw)
self.type = type
self.default = default
self.converter = converter
def convert(self, v):
if v is None:
if self.default is not NOT_SET:
return self.default
raise ConfigurationValueError("Value must not be None")
v = self._convert(v)
return self.converter(v)
@abstractmethod
def _convert(self, v):
return v
class SimpleOption(ConfigurationOption):
def __init__(self, type=str, default=NOT_SET, converter=identity,
*args, **kw):
super(SimpleOption, self).__init__(type=type, default=default,
converter=converter)
def _convert(self, v):
if isinstance(v, self.type):
return v
return self.type(v)
class ListOption(SimpleOption):
def __init__(self, content_type, type=list, default=NOT_SET,
converter=identity, *args, **kw):
super(ListOption, self).__init__(type=type, default=default,
converter=converter)
self.content_type = content_type
def _convert(self, v):
v = super(ListOption, self)._convert(v)
return map(self._convert_content, v)
def _convert_content(self, v):
if not isinstance(v, self.content_type):
v = self.content_type(v)
return v
class BooleanOption(ConfigurationOption):
def __init__(self, default=NOT_SET, converter=identity, *args, **kw):
super(BooleanOption, self).__init__(type=bool, default=default,
converter=converter)
def _convert(self, v):
if isinstance(v, (bool, int)):
return bool(v)
if isinstance(v, basestring):
return v and v.lower() not in ("0", "no", "n", "f", "false")
raise ConfigurationValueError("Illegal value for boolean: %s" % (v, ))
class EnumOption(SimpleOption):
def _convert(self, v):
try:
return super(EnumOption, self)._convert(v)
except Exception as exc:
try:
return getattr(self.type, v)
except:
raise exc
class LowerCaseEnumOption(EnumOption):
def _convert(self, v):
try:
return super(LowerCaseEnumOption, self)._convert(v)
except Exception as exc:
try:
return getattr(self.type, v.lower())
except:
raise exc
class Configuration(dict):
__options__ = {}
__name__ = "configuration"
__extra_options_strategy__ = ExtraOptionsStrategy.ignore
def __init__(self, *args, **kw):
config = dict(*args, **kw)
options = self.__options__.copy()
for k, v in config.copy().items():
try:
option = options.pop(k)
except KeyError:
strategy = self.__extra_options_strategy__
if strategy == ExtraOptionsStrategy.fatal:
raise ConfigurationError("Unknown configuration key in %s:"
" %s" % (self.__name__, k))
if strategy == ExtraOptionsStrategy.prune:
del config[k]
elif strategy == ExtraOptionsStrategy.warn:
self.logger.warn("Unknown configuration key in %s: %s",
self.__name__, k)
else:
config[k] = option.convert(v)
for k, v in options.items():
if v.default is NOT_SET:
raise ConfigurationKeyError("Missing configuration key in"
" %s: %s" %
(self.__name__, k, ))
config[k] = v.default
super(Configuration, self).__init__(config)
def __getitem__(self, k):
try:
return dict.__getitem__(self, k)
except KeyError:
raise ConfigurationKeyError("Missing configuration key in"
" %s: %s" %
(self.__name__, k, ))
def __getattr__(self, k, default=NOT_SET):
try:
return self[k]
except ConfigurationKeyError as exc:
if default is not NOT_SET:
return default
raise ConfigurationAttributeError(str(exc))
class LogLevel(Enum):
trace = logging.DEBUG
debug = logging.DEBUG
warning = logging.WARNING
error = logging.ERROR
fatal = logging.FATAL