change the list notification interface
This commit is contained in:
parent
e7e5af9a53
commit
f73c62c5df
@ -4,17 +4,32 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveListChange(ABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveListIndexUpdated(ActiveListChange):
|
||||||
|
def __init__(self, index: int, oldValue, newValue):
|
||||||
|
self.index = index
|
||||||
|
self.oldValue = oldValue
|
||||||
|
self.newValue = newValue
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveListIndexAppended(ActiveListChange):
|
||||||
|
def __init__(self, index: int, newValue):
|
||||||
|
self.index = index
|
||||||
|
self.newValue = newValue
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveListIndexDeleted(ActiveListChange):
|
||||||
|
def __init__(self, index: int, oldValue):
|
||||||
|
self.index = index
|
||||||
|
self.oldValue = oldValue
|
||||||
|
|
||||||
|
|
||||||
class ActiveListListener(ABC):
|
class ActiveListListener(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def onIndexChanged(self, index, newValue):
|
def onListChange(self, changes: list[ActiveListChange]):
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def onAppend(self, newValue):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def onDelete(self, index):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -35,30 +50,29 @@ class ActiveList:
|
|||||||
|
|
||||||
def append(self, value):
|
def append(self, value):
|
||||||
self.delegate.append(value)
|
self.delegate.append(value)
|
||||||
|
self.__fireChanges([ActiveListIndexAppended(len(self) - 1, value)])
|
||||||
|
|
||||||
|
def __fireChanges(self, changes: list[ActiveListChange]):
|
||||||
for listener in self.listeners:
|
for listener in self.listeners:
|
||||||
try:
|
try:
|
||||||
listener.onAppend(value)
|
listener.onListChange(changes)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Exception during onAppend notification")
|
logger.exception("Exception during onListChange notification")
|
||||||
|
|
||||||
def remove(self, value):
|
def remove(self, value):
|
||||||
self.__delitem__(self.delegate.index(value))
|
self.__delitem__(self.delegate.index(value))
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
|
if self.delegate[key] == value:
|
||||||
|
return
|
||||||
|
oldValue = self.delegate[key]
|
||||||
self.delegate[key] = value
|
self.delegate[key] = value
|
||||||
for listener in self.listeners:
|
self.__fireChanges([ActiveListIndexUpdated(key, oldValue, value)])
|
||||||
try:
|
|
||||||
listener.onIndexChanged(key, value)
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Exception during onKeyChanged notification")
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
|
oldValue = self.delegate[key]
|
||||||
del self.delegate[key]
|
del self.delegate[key]
|
||||||
for listener in self.listeners:
|
self.__fireChanges([ActiveListIndexDeleted(key, oldValue)])
|
||||||
try:
|
|
||||||
listener.onDelete(key)
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Exception during onDelete notification")
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.delegate[key]
|
return self.delegate[key]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.active.list import ActiveList
|
from owrx.active.list import ActiveList, ActiveListIndexUpdated, ActiveListIndexAppended, ActiveListIndexDeleted
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
@ -22,17 +22,23 @@ class ActiveListTest(TestCase):
|
|||||||
listenerMock = Mock()
|
listenerMock = Mock()
|
||||||
list.addListener(listenerMock)
|
list.addListener(listenerMock)
|
||||||
list[0] = "testvalue"
|
list[0] = "testvalue"
|
||||||
listenerMock.onIndexChanged.assert_called_once_with(0, "testvalue")
|
listenerMock.onListChange.assert_called_once()
|
||||||
|
changes, = listenerMock.onListChange.call_args.args
|
||||||
|
self.assertEqual(len(changes), 1)
|
||||||
|
self.assertIsInstance(changes[0], ActiveListIndexUpdated)
|
||||||
|
self.assertEqual(changes[0].index, 0)
|
||||||
|
self.assertEqual(changes[0].oldValue, "initialvalue")
|
||||||
|
self.assertEqual(changes[0].newValue, "testvalue")
|
||||||
|
|
||||||
def testListIndexChangeNotficationNotDisturbedByException(self):
|
def testListIndexChangeNotficationNotDisturbedByException(self):
|
||||||
list = ActiveList(["initialvalue"])
|
list = ActiveList(["initialvalue"])
|
||||||
throwingMock = Mock()
|
throwingMock = Mock()
|
||||||
throwingMock.onIndexChanged.side_effect = RuntimeError("this is a drill")
|
throwingMock.onListChange.side_effect = RuntimeError("this is a drill")
|
||||||
list.addListener(throwingMock)
|
list.addListener(throwingMock)
|
||||||
listenerMock = Mock()
|
listenerMock = Mock()
|
||||||
list.addListener(listenerMock)
|
list.addListener(listenerMock)
|
||||||
list[0] = "testvalue"
|
list[0] = "testvalue"
|
||||||
listenerMock.onIndexChanged.assert_called_once_with(0, "testvalue")
|
listenerMock.onListChange.assert_called_once()
|
||||||
|
|
||||||
def testListAppend(self):
|
def testListAppend(self):
|
||||||
list = ActiveList()
|
list = ActiveList()
|
||||||
@ -45,7 +51,12 @@ class ActiveListTest(TestCase):
|
|||||||
listenerMock = Mock()
|
listenerMock = Mock()
|
||||||
list.addListener(listenerMock)
|
list.addListener(listenerMock)
|
||||||
list.append("testvalue")
|
list.append("testvalue")
|
||||||
listenerMock.onAppend.assert_called_once_with("testvalue")
|
listenerMock.onListChange.assert_called_once()
|
||||||
|
changes, = listenerMock.onListChange.call_args.args
|
||||||
|
self.assertEqual(len(changes), 1)
|
||||||
|
self.assertIsInstance(changes[0], ActiveListIndexAppended)
|
||||||
|
self.assertEqual(changes[0].index, 0)
|
||||||
|
self.assertEqual(changes[0].newValue, "testvalue")
|
||||||
|
|
||||||
def testListDelete(self):
|
def testListDelete(self):
|
||||||
list = ActiveList(["value1", "value2"])
|
list = ActiveList(["value1", "value2"])
|
||||||
@ -53,12 +64,17 @@ class ActiveListTest(TestCase):
|
|||||||
self.assertEqual(len(list), 1)
|
self.assertEqual(len(list), 1)
|
||||||
self.assertEqual(list[0], "value2")
|
self.assertEqual(list[0], "value2")
|
||||||
|
|
||||||
def testListDelteNotification(self):
|
def testListDeleteNotification(self):
|
||||||
list = ActiveList(["value1", "value2"])
|
list = ActiveList(["value1", "value2"])
|
||||||
listenerMock = Mock()
|
listenerMock = Mock()
|
||||||
list.addListener(listenerMock)
|
list.addListener(listenerMock)
|
||||||
del list[0]
|
del list[0]
|
||||||
listenerMock.onDelete.assert_called_once_with(0)
|
listenerMock.onListChange.assert_called_once()
|
||||||
|
changes, = listenerMock.onListChange.call_args.args
|
||||||
|
self.assertEqual(len(changes), 1)
|
||||||
|
self.assertIsInstance(changes[0], ActiveListIndexDeleted)
|
||||||
|
self.assertEqual(changes[0].index, 0)
|
||||||
|
self.assertEqual(changes[0].oldValue, 'value1')
|
||||||
|
|
||||||
def testListDeleteByValue(self):
|
def testListDeleteByValue(self):
|
||||||
list = ActiveList(["value1", "value2"])
|
list = ActiveList(["value1", "value2"])
|
||||||
@ -77,8 +93,8 @@ class ActiveListTest(TestCase):
|
|||||||
listenerMock = Mock()
|
listenerMock = Mock()
|
||||||
list.addListener(listenerMock)
|
list.addListener(listenerMock)
|
||||||
list[0] = "testvalue"
|
list[0] = "testvalue"
|
||||||
listenerMock.onIndexChanged.assert_called_once_with(0, "testvalue")
|
listenerMock.onListChange.assert_called_once()
|
||||||
listenerMock.reset_mock()
|
listenerMock.reset_mock()
|
||||||
list.removeListener(listenerMock)
|
list.removeListener(listenerMock)
|
||||||
list[0] = "someothervalue"
|
list[0] = "someothervalue"
|
||||||
listenerMock.onIndexChanged.assert_not_called()
|
listenerMock.onListChange.assert_not_called()
|
||||||
|
Loading…
Reference in New Issue
Block a user