send property changes in bulk to global subscribers

This commit is contained in:
Jakob Ketterl 2020-12-30 17:14:06 +01:00
parent eb34c45145
commit 2c3146314b
4 changed files with 32 additions and 31 deletions

View File

@ -71,15 +71,22 @@ class PropertyManager(ABC):
pass pass
return self return self
def _fireCallbacks(self, name, value): def _fireCallbacks(self, changes):
if not changes:
return
for c in self.subscribers: for c in self.subscribers:
try: try:
if c.getName() is None: if c.getName() is None:
c.call(name, value) c.call(changes)
elif c.getName() == name: except Exception:
c.call(value) logger.exception("exception while firing changes")
except Exception as e: for name in changes:
logger.exception(e) for c in self.subscribers:
try:
if c.getName() == name:
c.call(changes[name])
except Exception:
logger.exception("exception while firing changes")
class PropertyLayer(PropertyManager): class PropertyLayer(PropertyManager):
@ -97,7 +104,7 @@ class PropertyLayer(PropertyManager):
if name in self.properties and self.properties[name] == value: if name in self.properties and self.properties[name] == value:
return return
self.properties[name] = value self.properties[name] = value
self._fireCallbacks(name, value) self._fireCallbacks({name: value})
def __dict__(self): def __dict__(self):
return {k: v for k, v in self.properties.items()} return {k: v for k, v in self.properties.items()}
@ -116,10 +123,9 @@ class PropertyFilter(PropertyManager):
self.props = props self.props = props
self.pm.wire(self.receiveEvent) self.pm.wire(self.receiveEvent)
def receiveEvent(self, name, value): def receiveEvent(self, changes):
if name not in self.props: changesToForward = {name: value for name, value in changes.items() if name in self.props}
return self._fireCallbacks(changesToForward)
self._fireCallbacks(name, value)
def __getitem__(self, item): def __getitem__(self, item):
if item not in self.props: if item not in self.props:
@ -157,7 +163,7 @@ class PropertyStack(PropertyManager):
""" """
highest priority = 0 highest priority = 0
""" """
self._fireChanges(self._addLayer(priority, pm)) self._fireCallbacks(self._addLayer(priority, pm))
def _addLayer(self, priority: int, pm: PropertyManager): def _addLayer(self, priority: int, pm: PropertyManager):
changes = {} changes = {}
@ -165,8 +171,8 @@ class PropertyStack(PropertyManager):
if key not in self or self[key] != pm[key]: if key not in self or self[key] != pm[key]:
changes[key] = pm[key] changes[key] = pm[key]
def eventClosure(name, value): def eventClosure(changes):
self.receiveEvent(pm, name, value) self.receiveEvent(pm, changes)
sub = pm.wire(eventClosure) sub = pm.wire(eventClosure)
@ -177,7 +183,7 @@ class PropertyStack(PropertyManager):
def removeLayer(self, pm: PropertyManager): def removeLayer(self, pm: PropertyManager):
for layer in self.layers: for layer in self.layers:
if layer["props"] == pm: if layer["props"] == pm:
self._fireChanges(self._removeLayer(layer)) self._fireCallbacks(self._removeLayer(layer))
def _removeLayer(self, layer): def _removeLayer(self, layer):
layer["sub"].cancel() layer["sub"].cancel()
@ -201,16 +207,11 @@ class PropertyStack(PropertyManager):
changes = {**changes, **self._addLayer(priority, pm)} changes = {**changes, **self._addLayer(priority, pm)}
changes = {k: v for k, v in changes.items() if k not in originalState or originalState[k] != v} changes = {k: v for k, v in changes.items() if k not in originalState or originalState[k] != v}
self._fireChanges(changes) self._fireCallbacks(changes)
def _fireChanges(self, changes): def receiveEvent(self, layer, changes):
for k, v in changes.items(): changesToForward = {name: value for name, value in changes.items() if layer == self._getTopLayer(name)}
self._fireCallbacks(k, v) self._fireCallbacks(changesToForward)
def receiveEvent(self, layer, name, value):
if layer != self._getTopLayer(name):
return
self._fireCallbacks(name, value)
def _getTopLayer(self, item): def _getTopLayer(self, item):
layers = [la["props"] for la in sorted(self.layers, key=lambda l: l["priority"])] layers = [la["props"] for la in sorted(self.layers, key=lambda l: l["priority"])]

View File

@ -11,7 +11,7 @@ class PropertyFilterTest(TestCase):
pf = PropertyFilter(pm, "testkey") pf = PropertyFilter(pm, "testkey")
self.assertEqual(pf["testkey"], "testvalue") self.assertEqual(pf["testkey"], "testvalue")
def testMissesPropert(self): def testMissesProperty(self):
pm = PropertyLayer() pm = PropertyLayer()
pm["testkey"] = "testvalue" pm["testkey"] = "testvalue"
pf = PropertyFilter(pm, "other_key") pf = PropertyFilter(pm, "other_key")
@ -25,7 +25,7 @@ class PropertyFilterTest(TestCase):
mock = Mock() mock = Mock()
pf.wire(mock.method) pf.wire(mock.method)
pm["testkey"] = "testvalue" pm["testkey"] = "testvalue"
mock.method.assert_called_once_with("testkey", "testvalue") mock.method.assert_called_once_with({"testkey": "testvalue"})
def testForwardsPropertyEvent(self): def testForwardsPropertyEvent(self):
pm = PropertyLayer() pm = PropertyLayer()

View File

@ -19,7 +19,7 @@ class PropertyLayerTest(TestCase):
mock = Mock() mock = Mock()
pm.wire(mock.method) pm.wire(mock.method)
pm["testkey"] = "after" pm["testkey"] = "after"
mock.method.assert_called_once_with("testkey", "after") mock.method.assert_called_once_with({"testkey": "after"})
def testUnsubscribe(self): def testUnsubscribe(self):
pm = PropertyLayer() pm = PropertyLayer()
@ -27,7 +27,7 @@ class PropertyLayerTest(TestCase):
mock = Mock() mock = Mock()
sub = pm.wire(mock.method) sub = pm.wire(mock.method)
pm["testkey"] = "between" pm["testkey"] = "between"
mock.method.assert_called_once_with("testkey", "between") mock.method.assert_called_once_with({"testkey": "between"})
mock.reset_mock() mock.reset_mock()
pm.unwire(sub) pm.unwire(sub)

View File

@ -49,7 +49,7 @@ class PropertyStackTest(TestCase):
mock = Mock() mock = Mock()
stack.wire(mock.method) stack.wire(mock.method)
layer["testkey"] = "testvalue" layer["testkey"] = "testvalue"
mock.method.assert_called_once_with("testkey", "testvalue") mock.method.assert_called_once_with({"testkey": "testvalue"})
def testPropertyChangeEventPriority(self): def testPropertyChangeEventPriority(self):
low_layer = PropertyLayer() low_layer = PropertyLayer()
@ -64,7 +64,7 @@ class PropertyStackTest(TestCase):
low_layer["testkey"] = "modified low value" low_layer["testkey"] = "modified low value"
mock.method.assert_not_called() mock.method.assert_not_called()
high_layer["testkey"] = "modified high value" high_layer["testkey"] = "modified high value"
mock.method.assert_called_once_with("testkey", "modified high value") mock.method.assert_called_once_with({"testkey": "modified high value"})
def testPropertyEventOnLayerAdd(self): def testPropertyEventOnLayerAdd(self):
low_layer = PropertyLayer() low_layer = PropertyLayer()
@ -162,7 +162,7 @@ class PropertyStackTest(TestCase):
mock = Mock() mock = Mock()
stack.wire(mock.method) stack.wire(mock.method)
stack.removeLayer(layer) stack.removeLayer(layer)
mock.method.assert_called_once_with("testkey", None) mock.method.assert_called_once_with({"testkey": None})
mock.reset_mock() mock.reset_mock()
layer["testkey"] = "after" layer["testkey"] = "after"