create filtering that prevents overwriting the device name

This commit is contained in:
Jakob Ketterl 2021-02-24 00:09:57 +01:00
parent 4199a583f8
commit f69d78926e
8 changed files with 99 additions and 25 deletions

View File

@ -1,18 +1,21 @@
from owrx.config import Config
from owrx.locator import Locator
from owrx.property import PropertyFilter
from owrx.property.filter import ByPropertyName
class ReceiverDetails(PropertyFilter):
def __init__(self):
super().__init__(
Config.get(),
"receiver_name",
"receiver_location",
"receiver_asl",
"receiver_gps",
"photo_title",
"photo_desc",
ByPropertyName(
"receiver_name",
"receiver_location",
"receiver_asl",
"receiver_gps",
"photo_title",
"photo_desc",
)
)
def __dict__(self):

View File

@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
from owrx.property.validators import Validator
from owrx.property.filter import Filter, ByPropertyName
import logging
logger = logging.getLogger(__name__)
@ -60,7 +61,7 @@ class PropertyManager(ABC):
return self.__dict__().__len__()
def filter(self, *props):
return PropertyFilter(self, *props)
return PropertyFilter(self, ByPropertyName(*props))
def readonly(self):
return PropertyReadOnly(self)
@ -132,41 +133,41 @@ class PropertyLayer(PropertyManager):
class PropertyFilter(PropertyManager):
def __init__(self, pm: PropertyManager, *props: str):
def __init__(self, pm: PropertyManager, filter: Filter):
super().__init__()
self.pm = pm
self.props = props
self._filter = filter
self.pm.wire(self.receiveEvent)
def receiveEvent(self, changes):
changesToForward = {name: value for name, value in changes.items() if name in self.props}
changesToForward = {name: value for name, value in changes.items() if self._filter.apply(name)}
self._fireCallbacks(changesToForward)
def __getitem__(self, item):
if item not in self.props:
if not self._filter.apply(item):
raise KeyError(item)
return self.pm.__getitem__(item)
def __setitem__(self, key, value):
if key not in self.props:
if not self._filter.apply(key):
raise KeyError(key)
return self.pm.__setitem__(key, value)
def __contains__(self, item):
if item not in self.props:
if not self._filter.apply(item):
return False
return self.pm.__contains__(item)
def __dict__(self):
return {k: v for k, v in self.pm.__dict__().items() if k in self.props}
return {k: v for k, v in self.pm.__dict__().items() if self._filter.apply(k)}
def __delitem__(self, key):
if key not in self.props:
if not self._filter.apply(key):
raise KeyError(key)
return self.pm.__delitem__(key)
def keys(self):
return [k for k in self.pm.keys() if k in self.props]
return [k for k in self.pm.keys() if self._filter.apply(k)]
class PropertyDelegator(PropertyManager):

23
owrx/property/filter.py Normal file
View File

@ -0,0 +1,23 @@
from abc import ABC, abstractmethod
class Filter(ABC):
@abstractmethod
def apply(self, prop) -> bool:
pass
class ByPropertyName(Filter):
def __init__(self, *props):
self.props = props
def apply(self, prop) -> bool:
return prop in self.props
class ByLambda(Filter):
def __init__(self, func):
self.func = func
def apply(self, prop) -> bool:
return self.func(prop)

View File

@ -9,7 +9,8 @@ import signal
from abc import ABC, abstractmethod
from owrx.command import CommandMapper
from owrx.socket import getAvailablePort
from owrx.property import PropertyStack, PropertyLayer
from owrx.property import PropertyStack, PropertyLayer, PropertyFilter
from owrx.property.filter import ByLambda
from owrx.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput
from owrx.form.converter import OptionalConverter
from owrx.form.device import GainInput
@ -96,6 +97,9 @@ class SdrSource(ABC):
if self.isAlwaysOn() and self.state is not SdrSourceState.DISABLED:
self.start()
def _loadProfile(self, profile):
self.props.replaceLayer(0, PropertyFilter(profile, ByLambda(lambda x: x != "name")))
def validateProfiles(self):
props = PropertyStack()
props.addLayer(1, self.props)
@ -155,7 +159,7 @@ class SdrSource(ABC):
profile = profiles[profile_id]
self.profile_id = profile_id
self.props.replaceLayer(0, profile)
self._loadProfile(profile)
def getId(self):
return self.id

View File

View File

@ -0,0 +1,17 @@
from owrx.property.filter import ByLambda
from unittest import TestCase
from unittest.mock import Mock
class TestByLambda(TestCase):
def testPositive(self):
mock = Mock(return_value=True)
filter = ByLambda(mock)
self.assertTrue(filter.apply("test_key"))
mock.assert_called_with("test_key")
def testNegateive(self):
mock = Mock(return_value=False)
filter = ByLambda(mock)
self.assertFalse(filter.apply("test_key"))
mock.assert_called_with("test_key")

View File

@ -0,0 +1,12 @@
from owrx.property.filter import ByPropertyName
from unittest import TestCase
class ByPropertyNameTest(TestCase):
def testNameIsInList(self):
filter = ByPropertyName("test_key")
self.assertTrue(filter.apply("test_key"))
def testNameNotInList(self):
filter = ByPropertyName("test_key")
self.assertFalse(filter.apply("other_key"))

View File

@ -7,20 +7,26 @@ class PropertyFilterTest(TestCase):
def testPassesProperty(self):
pm = PropertyLayer()
pm["testkey"] = "testvalue"
pf = PropertyFilter(pm, "testkey")
mock = Mock()
mock.apply.return_value = True
pf = PropertyFilter(pm, mock)
self.assertEqual(pf["testkey"], "testvalue")
def testMissesProperty(self):
pm = PropertyLayer()
pm["testkey"] = "testvalue"
pf = PropertyFilter(pm, "other_key")
mock = Mock()
mock.apply.return_value = False
pf = PropertyFilter(pm, mock)
self.assertFalse("testkey" in pf)
with self.assertRaises(KeyError):
x = pf["testkey"]
def testForwardsEvent(self):
pm = PropertyLayer()
pf = PropertyFilter(pm, "testkey")
mock = Mock()
mock.apply.return_value = True
pf = PropertyFilter(pm, mock)
mock = Mock()
pf.wire(mock.method)
pm["testkey"] = "testvalue"
@ -28,7 +34,9 @@ class PropertyFilterTest(TestCase):
def testForwardsPropertyEvent(self):
pm = PropertyLayer()
pf = PropertyFilter(pm, "testkey")
mock = Mock()
mock.apply.return_value = True
pf = PropertyFilter(pm, mock)
mock = Mock()
pf.wireProperty("testkey", mock.method)
pm["testkey"] = "testvalue"
@ -36,7 +44,9 @@ class PropertyFilterTest(TestCase):
def testForwardsWrite(self):
pm = PropertyLayer()
pf = PropertyFilter(pm, "testkey")
mock = Mock()
mock.apply.return_value = True
pf = PropertyFilter(pm, mock)
pf["testkey"] = "testvalue"
self.assertTrue("testkey" in pm)
self.assertEqual(pm["testkey"], "testvalue")
@ -44,7 +54,9 @@ class PropertyFilterTest(TestCase):
def testOverwrite(self):
pm = PropertyLayer()
pm["testkey"] = "old value"
pf = PropertyFilter(pm, "testkey")
mock = Mock()
mock.apply.return_value = True
pf = PropertyFilter(pm, mock)
pf["testkey"] = "new value"
self.assertEqual(pm["testkey"], "new value")
self.assertEqual(pf["testkey"], "new value")
@ -52,7 +64,9 @@ class PropertyFilterTest(TestCase):
def testRejectsWrite(self):
pm = PropertyLayer()
pm["testkey"] = "old value"
pf = PropertyFilter(pm, "otherkey")
mock = Mock()
mock.apply.return_value = False
pf = PropertyFilter(pm, mock)
with self.assertRaises(KeyError):
pf["testkey"] = "new value"
self.assertEqual(pm["testkey"], "old value")