mirror of
https://github.com/OpenMTC/OpenMTC.git
synced 2025-06-15 21:28:08 +00:00
179 lines
5.3 KiB
Python
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
|