from abc import ABC
from abc import abstractmethod
_DEFAULT_TAG = ['tune']
[docs]class Parameter(ABC):
def __init__(self, tags=None):
if tags is None:
tags = _DEFAULT_TAG
self.tags = tags
@abstractmethod
def validate(self, value, name):
...
[docs]class Const(Parameter):
def __init__(self, value, tags=None):
super().__init__(tags=tags)
self.value = value
def validate(self, value, name):
if value != self.value:
raise ValueError("{}: {} != {}".format(name, value, self.value))
[docs]class TypeOf(Parameter):
def __init__(self, *types, tags=None):
super().__init__(tags=tags)
self.types = types
def validate(self, value, name):
for t in self.types:
if isinstance(value, t):
return
if len(self.types) == 1:
raise TypeError("{}: {} is not a {}".format(
name, value,
getattr(self.types[0], "__name__", str(self.types[0]))))
type_names = [getattr(t, "__name__", str(t)) for t in self.types]
raise TypeError("{}: {} is not a {}".format(name, value,
" or ".join(type_names)))
[docs]class Enum(Parameter):
def __init__(self, *members, tags=None):
super().__init__(tags=tags)
if len(members) == 0:
raise ValueError("members must have at least one item")
self.members = members
def validate(self, value, name):
if value not in self.members:
members_str = ', '.join(str(m) for m in self.members)
raise ValueError("{} is not in [{}]".format(value, members_str))
[docs]class Union(Parameter):
def __init__(self, *params, tags=None):
if len(params) == 0:
raise ValueError("parameters must have at least one item")
for p in params:
if not isinstance(p, Parameter):
raise ValueError("all parameters must be of type Parameter")
p.tags = []
super().__init__(tags=tags)
self.params = params
def validate(self, value, name):
error_msg = []
for p in self.params:
try:
p.validate(value, name)
return
except (TypeError, ValueError) as e:
error_msg.append(str(e)[len(name) + 2:])
# None of the params validated value
raise ValueError('{}: {}'.format(name, ' and '.join(error_msg)))
[docs]class Interval(TypeOf):
def __init__(self,
typ,
lower=None,
upper=None,
lower_inclusive=True,
upper_inclusive=True,
tags=None):
if lower is None and upper is None:
raise ValueError("lower or upper must be defined")
if None not in (lower, upper) and lower >= upper:
raise ValueError("lower must be strictly less than upper")
super().__init__(typ, tags=tags)
self.lower = lower
self.upper = upper
self.lower_inclusive = lower_inclusive
self.upper_inclusive = upper_inclusive
def validate(self, value, name):
super().validate(value, name)
if self.lower is not None:
if self.lower_inclusive:
lower_in_range = self.lower <= value
else:
lower_in_range = self.lower < value
if not lower_in_range:
raise ValueError(self._get_error_msg(value, name))
if self.upper is not None:
if self.upper_inclusive:
upper_in_range = value <= self.upper
else:
upper_in_range = value < self.upper
if not upper_in_range:
raise ValueError(self._get_error_msg(value, name))
def _get_error_msg(self, value, name):
msg_list = ["{} not in".format(value)]
if self.lower is not None:
if self.lower_inclusive:
lower_str = "[{},".format(self.lower)
else:
lower_str = "({},".format(self.lower)
msg_list.append(lower_str)
else:
msg_list.append("(-inf,")
if self.upper is not None:
if self.upper_inclusive:
upper_str = "{}]".format(self.upper)
else:
upper_str = "{})".format(self.upper)
msg_list.append(upper_str)
else:
msg_list.append("inf)")
return "{}: {}".format(name, " ".join(msg_list))