mirror of
https://github.com/jketterl/openwebrx.git
synced 2026-01-03 15:20:27 +01:00
implement more list transformation events
This commit is contained in:
parent
24c4741215
commit
8a588270f6
|
|
@ -1,4 +1,6 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Union
|
||||
from functools import partial
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -43,10 +45,29 @@ class ActiveListListener(ABC):
|
|||
pass
|
||||
|
||||
|
||||
class ActiveListTransformation(ABC):
|
||||
@abstractmethod
|
||||
def transform(self, value):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.transform(*args, **kwargs)
|
||||
|
||||
def monitor(self, member, callback: callable):
|
||||
pass
|
||||
|
||||
def unmonitor(self, member):
|
||||
pass
|
||||
|
||||
|
||||
class ActiveListTransformationListener(ActiveListListener):
|
||||
def __init__(self, transformation: callable, target: "ActiveList"):
|
||||
def __init__(self, transformation: callable, source: "ActiveList", target: "ActiveList"):
|
||||
self.transformation = transformation
|
||||
self.source = source
|
||||
self.target = target
|
||||
if isinstance(transformation, ActiveListTransformation):
|
||||
for idx, v in enumerate(self.source):
|
||||
transformation.monitor(v, partial(self._onMonitor, idx))
|
||||
|
||||
def onListChange(self, source: "ActiveList", changes: list[ActiveListChange]):
|
||||
for change in changes:
|
||||
|
|
@ -57,6 +78,9 @@ class ActiveListTransformationListener(ActiveListListener):
|
|||
elif isinstance(change, ActiveListIndexDeleted):
|
||||
del self.target[change.index]
|
||||
|
||||
def _onMonitor(self, idx):
|
||||
self.target[idx] = self.transformation(self.source[idx])
|
||||
|
||||
|
||||
class ActiveListFilterListener(ActiveListListener):
|
||||
def __init__(self, filter: callable, keyMap: list, target: "ActiveList"):
|
||||
|
|
@ -91,21 +115,39 @@ class ActiveListFlattenListener(ActiveListListener):
|
|||
def __init__(self, source: "ActiveList", target: "ActiveList"):
|
||||
self.source = source
|
||||
self.target = target
|
||||
self.source.addListener(self)
|
||||
for member in self.source:
|
||||
member.addListener(self)
|
||||
|
||||
def getOffsetFor(self, source: "ActiveList"):
|
||||
idx = self.source.index(source)
|
||||
return self.getOffsetForIndex(idx)
|
||||
|
||||
def getOffsetForIndex(self, idx: int):
|
||||
return sum(len(s) for s in self.source[0:idx])
|
||||
|
||||
def onListChange(self, source: "ActiveList", changes: list[ActiveListChange]):
|
||||
for change in changes:
|
||||
if isinstance(change, ActiveListIndexAdded):
|
||||
self.target.insert(self.getOffsetFor(source) + change.index, change.newValue)
|
||||
elif isinstance(change, ActiveListIndexUpdated):
|
||||
self.target[self.getOffsetFor(source) + change.index] = change.newValue
|
||||
elif isinstance(change, ActiveListIndexDeleted):
|
||||
del self.target[self.getOffsetFor(source) + change.index]
|
||||
if source is self.source:
|
||||
if isinstance(change, ActiveListIndexAdded):
|
||||
idx = self.getOffsetForIndex(change.index)
|
||||
for n, v in enumerate(change.newValue):
|
||||
self.target.insert(idx + n, v)
|
||||
elif isinstance(change, ActiveListIndexUpdated):
|
||||
idx = self.getOffsetForIndex(change.index)
|
||||
del self.target[idx, idx + len(change.oldValue)]
|
||||
for n, v in enumerate(change.newValue):
|
||||
self.target.insert(idx + n, v)
|
||||
elif isinstance(change, ActiveListIndexDeleted):
|
||||
idx = self.getOffsetForIndex(change.index)
|
||||
del self.target[idx, idx + len(change.oldValue)]
|
||||
else:
|
||||
if isinstance(change, ActiveListIndexAdded):
|
||||
self.target.insert(self.getOffsetFor(source) + change.index, change.newValue)
|
||||
elif isinstance(change, ActiveListIndexUpdated):
|
||||
self.target[self.getOffsetFor(source) + change.index] = change.newValue
|
||||
elif isinstance(change, ActiveListIndexDeleted):
|
||||
del self.target[self.getOffsetFor(source) + change.index]
|
||||
|
||||
|
||||
class ActiveList:
|
||||
|
|
@ -144,9 +186,9 @@ class ActiveList:
|
|||
def index(self, value):
|
||||
return self.delegate.index(value)
|
||||
|
||||
def map(self, transform: callable):
|
||||
def map(self, transform: Union[callable, ActiveListTransformation]):
|
||||
res = ActiveList([transform(v) for v in self])
|
||||
self.addListener(ActiveListTransformationListener(transform, res))
|
||||
self.addListener(ActiveListTransformationListener(transform, self, res))
|
||||
return res
|
||||
|
||||
def filter(self, filter: callable):
|
||||
|
|
@ -172,9 +214,15 @@ class ActiveList:
|
|||
self.__fireChanges([ActiveListIndexUpdated(key, oldValue, value)])
|
||||
|
||||
def __delitem__(self, key):
|
||||
oldValue = self.delegate[key]
|
||||
del self.delegate[key]
|
||||
self.__fireChanges([ActiveListIndexDeleted(key, oldValue)])
|
||||
if isinstance(key, tuple):
|
||||
start, stop = key
|
||||
changes = [ActiveListIndexDeleted(start + idx, v) for idx, v in enumerate(self.delegate[start:stop])]
|
||||
del self.delegate[start:stop]
|
||||
self.__fireChanges(changes)
|
||||
else:
|
||||
oldValue = self.delegate[key]
|
||||
del self.delegate[key]
|
||||
self.__fireChanges([ActiveListIndexDeleted(key, oldValue)])
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.delegate[key]
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class ActiveListTest(TestCase):
|
|||
self.assertEqual(flattenedList[2], 3)
|
||||
self.assertEqual(flattenedList[3], 4)
|
||||
|
||||
def testActiveFlattenAdd(self):
|
||||
def testActiveFlattenMemberAppend(self):
|
||||
sublist = ActiveList([3, 4])
|
||||
list = ActiveList([ActiveList([1, 2]), sublist, ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
|
|
@ -199,7 +199,7 @@ class ActiveListTest(TestCase):
|
|||
self.assertEqual(len(flattenedList), 7)
|
||||
self.assertEqual(flattenedList[4], 5)
|
||||
|
||||
def testActiveFlattenInsert(self):
|
||||
def testActiveFlattenMemberInsert(self):
|
||||
sublist = ActiveList([3, 5])
|
||||
list = ActiveList([ActiveList([1, 2]), sublist, ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
|
|
@ -207,7 +207,23 @@ class ActiveListTest(TestCase):
|
|||
self.assertEqual(len(flattenedList), 7)
|
||||
self.assertEqual(flattenedList[3], 4)
|
||||
|
||||
def testActiveFlattenUpdate(self):
|
||||
def testActiveFlattenListInsert(self):
|
||||
list = ActiveList([ActiveList([1, 2]), ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
sublist = ActiveList([3, 4])
|
||||
list.insert(1, sublist)
|
||||
self.assertEqual(len(flattenedList), 6)
|
||||
self.assertEqual(flattenedList[2], 3)
|
||||
|
||||
def testActiveFlattenListUpdate(self):
|
||||
sublist = ActiveList([3, 9, 5])
|
||||
list = ActiveList([ActiveList([1, 2]), sublist, ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
sublist = ActiveList([3, 4, 5])
|
||||
list[1] = sublist
|
||||
self.assertEqual(flattenedList[3], 4)
|
||||
|
||||
def testActiveFlattenMemberUpdate(self):
|
||||
sublist = ActiveList([3, 9, 5])
|
||||
list = ActiveList([ActiveList([1, 2]), sublist, ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
|
|
@ -215,10 +231,17 @@ class ActiveListTest(TestCase):
|
|||
self.assertEqual(len(flattenedList), 7)
|
||||
self.assertEqual(flattenedList[3], 4)
|
||||
|
||||
def testActiveFlattenDelete(self):
|
||||
def testActiveFlattenMemberDelete(self):
|
||||
sublist = ActiveList([3, 4, 9, 5])
|
||||
list = ActiveList([ActiveList([1, 2]), sublist, ActiveList([6, 7])])
|
||||
flattenedList = list.flatten()
|
||||
del sublist[2]
|
||||
self.assertEqual(len(flattenedList), 7)
|
||||
self.assertEqual(flattenedList[4], 5)
|
||||
|
||||
def testActiveFlattenListDelete(self):
|
||||
list = ActiveList([ActiveList([1, 2]), ActiveList([9]), ActiveList([3, 4]), ActiveList([5, 6])])
|
||||
flattenedList = list.flatten()
|
||||
del list[1]
|
||||
self.assertEqual(len(flattenedList), 6)
|
||||
self.assertEqual(flattenedList[2], 3)
|
||||
|
|
|
|||
34
test/owrx/active/list/test_advanced_transformation.py
Normal file
34
test/owrx/active/list/test_advanced_transformation.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from owrx.active.list import ActiveList, ActiveListTransformation
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class TestTranformation(ActiveListTransformation):
|
||||
def __init__(self):
|
||||
self.callback = None
|
||||
self.prefix = "value"
|
||||
|
||||
def transform(self, value):
|
||||
return "{}{}".format(self.prefix, value)
|
||||
|
||||
def monitor(self, member, callback: callable):
|
||||
self.callback = callback
|
||||
|
||||
def trigger(self, newPrefix: str):
|
||||
self.prefix = newPrefix
|
||||
self.callback()
|
||||
|
||||
|
||||
class AdvancedTransformationTest(TestCase):
|
||||
def testListAdvancedTransformation(self):
|
||||
list = ActiveList([1, 2])
|
||||
transformedList = list.map(TestTranformation())
|
||||
self.assertEqual(len(transformedList), 2)
|
||||
self.assertEqual(transformedList[0], "value1")
|
||||
self.assertEqual(transformedList[1], "value2")
|
||||
|
||||
def testListMonitor(self):
|
||||
list = ActiveList([1, 2])
|
||||
transformation = TestTranformation()
|
||||
transformedList = list.map(transformation)
|
||||
transformation.trigger("foobar")
|
||||
self.assertEqual(transformedList[1], "foobar2")
|
||||
Loading…
Reference in a new issue