add the ability to make a layer readonly
This commit is contained in:
parent
2a5448f5c1
commit
8372f198db
@ -5,6 +5,10 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Subscription(object):
|
class Subscription(object):
|
||||||
def __init__(self, subscriptee, name, subscriber):
|
def __init__(self, subscriptee, name, subscriber):
|
||||||
self.subscriptee = subscriptee
|
self.subscriptee = subscriptee
|
||||||
@ -52,6 +56,9 @@ class PropertyManager(ABC):
|
|||||||
def filter(self, *props):
|
def filter(self, *props):
|
||||||
return PropertyFilter(self, *props)
|
return PropertyFilter(self, *props)
|
||||||
|
|
||||||
|
def readonly(self):
|
||||||
|
return PropertyReadOnly(self)
|
||||||
|
|
||||||
def wire(self, callback):
|
def wire(self, callback):
|
||||||
sub = Subscription(self, None, callback)
|
sub = Subscription(self, None, callback)
|
||||||
self.subscribers.append(sub)
|
self.subscribers.append(sub)
|
||||||
@ -155,35 +162,16 @@ class PropertyFilter(PropertyManager):
|
|||||||
return [k for k in self.pm.keys() if k in self.props]
|
return [k for k in self.pm.keys() if k in self.props]
|
||||||
|
|
||||||
|
|
||||||
class PropertyValidationError(Exception):
|
class PropertyDelegator(PropertyManager):
|
||||||
def __init__(self, key, value):
|
def __init__(self, pm: PropertyManager):
|
||||||
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
|
self.pm = pm
|
||||||
self.pm.wire(self._fireCallbacks)
|
self.pm.wire(self._fireCallbacks)
|
||||||
if validators is None:
|
|
||||||
self.validators = {}
|
|
||||||
else:
|
|
||||||
self.validators = {k: Validator.of(v) for k, v in validators.items()}
|
|
||||||
super().__init__()
|
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):
|
def __getitem__(self, item):
|
||||||
return self.pm.__getitem__(item)
|
return self.pm.__getitem__(item)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self.validate(key, value)
|
|
||||||
return self.pm.__setitem__(key, value)
|
return self.pm.__setitem__(key, value)
|
||||||
|
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
@ -199,6 +187,43 @@ class PropertyValidator(PropertyManager):
|
|||||||
return self.pm.keys()
|
return self.pm.keys()
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyValidationError(PropertyError):
|
||||||
|
def __init__(self, key, value):
|
||||||
|
super().__init__('Invalid value for property "{key}": "{value}"'.format(key=key, value=str(value)))
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyValidator(PropertyDelegator):
|
||||||
|
def __init__(self, pm: PropertyManager, validators=None):
|
||||||
|
super().__init__(pm)
|
||||||
|
if validators is None:
|
||||||
|
self.validators = {}
|
||||||
|
else:
|
||||||
|
self.validators = {k: Validator.of(v) for k, v in validators.items()}
|
||||||
|
|
||||||
|
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 __setitem__(self, key, value):
|
||||||
|
self.validate(key, value)
|
||||||
|
return self.pm.__setitem__(key, value)
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyWriteError(PropertyError):
|
||||||
|
def __init__(self, key):
|
||||||
|
super().__init__('Key "{key}" is not writeable'.format(key=key))
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyReadOnly(PropertyDelegator):
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
raise PropertyWriteError(key)
|
||||||
|
|
||||||
|
|
||||||
class PropertyStack(PropertyManager):
|
class PropertyStack(PropertyManager):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
15
test/property/test_property_readonly.py
Normal file
15
test/property/test_property_readonly.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from unittest import TestCase
|
||||||
|
from owrx.property import PropertyLayer, PropertyReadOnly, PropertyWriteError
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyReadOnlyTest(TestCase):
|
||||||
|
def testPreventsWrites(self):
|
||||||
|
layer = PropertyLayer()
|
||||||
|
layer["testkey"] = "initial value"
|
||||||
|
ro = PropertyReadOnly(layer)
|
||||||
|
with self.assertRaises(PropertyWriteError):
|
||||||
|
ro["testkey"] = "new value"
|
||||||
|
with self.assertRaises(PropertyWriteError):
|
||||||
|
ro["otherkey"] = "testvalue"
|
||||||
|
self.assertEqual(ro["testkey"], "initial value")
|
||||||
|
self.assertNotIn("otherkey", ro)
|
Loading…
Reference in New Issue
Block a user