introduce PropertyValidator (wrapper)

This commit is contained in:
Jakob Ketterl 2021-01-24 21:19:45 +01:00
parent 40e531c0da
commit ad0a5c27db
2 changed files with 80 additions and 4 deletions

View File

@ -24,7 +24,6 @@ class Subscription(object):
class PropertyManager(ABC):
def __init__(self):
self.subscribers = []
self.validators = {}
@abstractmethod
def __getitem__(self, item):
@ -83,9 +82,6 @@ class PropertyManager(ABC):
except Exception as e:
logger.exception(e)
def setValidator(self, name, validator):
self.validators[name] = Validator.of(validator)
class PropertyLayer(PropertyManager):
def __init__(self):
@ -153,6 +149,49 @@ class PropertyFilter(PropertyManager):
return [k for k in self.pm.keys() if k in self.props]
class PropertyValidationError(Exception):
def __init__(self, key, value):
super().__init__('Invalid value for property "{key}": "{value}"'.format(key=key, value=str(value)))
class PropertyValidator(PropertyManager):
def __init__(self, pm: PropertyManager, validators=None):
self.pm = pm
if validators is None:
self.validators = {}
else:
self.validators = {k: Validator.of(v) for k, v in validators.items()}
super().__init__()
def validate(self, key, value):
if key not in self.validators:
return
if not self.validators[key].isValid(value):
raise PropertyValidationError(key, value)
def setValidator(self, key, validator):
self.validators[key] = Validator.of(validator)
def __getitem__(self, item):
return self.pm.__getitem__(item)
def __setitem__(self, key, value):
self.validate(key, value)
return self.pm.__setitem__(key, value)
def __contains__(self, item):
return self.pm.__contains__(item)
def __dict__(self):
return self.pm.__dict__()
def __delitem__(self, key):
return self.pm.__delitem__(key)
def keys(self):
return self.pm.keys()
class PropertyStack(PropertyManager):
def __init__(self):
super().__init__()

View File

@ -0,0 +1,37 @@
from unittest import TestCase
from owrx.property import PropertyLayer, PropertyValidator, PropertyValidationError
from owrx.property.validators import NumberValidator, StringValidator
class PropertyValidatorTest(TestCase):
def testPassesUnvalidated(self):
pm = PropertyLayer()
pv = PropertyValidator(pm)
pv["testkey"] = "testvalue"
self.assertEqual(pv["testkey"], "testvalue")
self.assertEqual(pm["testkey"], "testvalue")
def testPassesValidValue(self):
pv = PropertyValidator(PropertyLayer(), {"testkey": NumberValidator()})
pv["testkey"] = 42
self.assertEqual(pv["testkey"], 42)
def testThrowsErrorOnInvalidValue(self):
pv = PropertyValidator(PropertyLayer(), {"testkey": NumberValidator()})
with self.assertRaises(PropertyValidationError):
pv["testkey"] = "text"
def testSetValidator(self):
pv = PropertyValidator(PropertyLayer())
pv.setValidator("testkey", NumberValidator())
with self.assertRaises(PropertyValidationError):
pv["testkey"] = "text"
def testUpdateValidator(self):
pv = PropertyValidator(PropertyLayer(), {"testkey": StringValidator()})
# this should pass
pv["testkey"] = "text"
pv.setValidator("testkey", NumberValidator())
# this should raise
with self.assertRaises(PropertyValidationError):
pv["testkey"] = "text"