make return value 'Done' unneccessary

'Done' was introduced in order to suppress unneccessary
duplicate updates. However, since super calls on access methods are
allowed, it is not nice when such a method returns Done, as this
is not automagically replaced by the current parameter value.
As a consequence:

- using Done is discouraged, but not (yet) removed in all code
- the 'omit_unchanged_within' property is moved from Module to an
  internal Parameter property 'update_unchanged'
- its default is moved from a SEC node property to generalConfig
- the 'update_unchanged' parameter property may be set to
  'never' for parameters where duplicate updates make no sense
- this property might be set to 'always', for measurements, where
  even unchanged values taken from HW should be transmitted

Change-Id: I2847c983ca09c2c4098e402edd08d0c96c3913f4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30672
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
2023-03-13 17:16:07 +01:00
parent 9cab6670b9
commit 0d265b9752
22 changed files with 188 additions and 119 deletions

View File

@@ -23,7 +23,8 @@
from frappy.rwhandler import ReadHandler, WriteHandler, \
CommonReadHandler, CommonWriteHandler, nopoll
from frappy.core import Module, Parameter, FloatRange, Done
from frappy.core import Module, Parameter, FloatRange
from frappy.lib import generalConfig
class DispatcherStub:
@@ -31,9 +32,9 @@ class DispatcherStub:
# initial value from the timestamp. However, in the test below
# the second update happens after the updates dict is cleared
# -> we have to inhibit the 'omit unchanged update' feature
omit_unchanged_within = 0
def __init__(self, updates):
generalConfig.testinit(omit_unchanged_within=0)
self.updates = updates
def announce_update(self, modulename, pname, pobj):
@@ -104,7 +105,7 @@ def test_handler():
assert m.b == 7
assert data.pop() == 'b'
data.append(Done)
data.append(m.b)
assert m.read_b() == 7
assert data.pop() == 'b'

View File

@@ -31,6 +31,7 @@ from frappy.errors import ProgrammingError, ConfigError
from frappy.modules import Communicator, Drivable, Readable, Module
from frappy.params import Command, Parameter
from frappy.rwhandler import ReadHandler, WriteHandler, nopoll
from frappy.lib import generalConfig
class DispatcherStub:
@@ -38,9 +39,9 @@ class DispatcherStub:
# initial value from the timestamp. However, in the test below
# the second update happens after the updates dict is cleared
# -> we have to inhibit the 'omit unchanged update' feature
omit_unchanged_within = 0
def __init__(self, updates):
generalConfig.testinit(omit_unchanged_within=0)
self.updates = updates
def announce_update(self, modulename, pname, pobj):
@@ -239,12 +240,12 @@ def test_ModuleMagic():
'export', 'group', 'description', 'features',
'meaning', 'visibility', 'implementation', 'interface_classes', 'target', 'stop',
'status', 'param1', 'param2', 'cmd', 'a2', 'pollinterval', 'slowinterval', 'b2',
'cmd2', 'value', 'a1'}
'cmd2', 'value', 'a1', 'omit_unchanged_within'}
assert set(cfg['value'].keys()) == {
'group', 'export', 'relative_resolution',
'visibility', 'unit', 'default', 'value', 'datatype', 'fmtstr',
'absolute_resolution', 'max', 'min', 'readonly', 'constant',
'description', 'needscfg'}
'description', 'needscfg', 'update_unchanged'}
# check on the level of classes
# this checks Newclass1 too, as it is inherited by Newclass2
@@ -739,3 +740,46 @@ def test_write_method_returns_none():
mod = Mod('mod', LoggerStub(), {'description': ''}, ServerStub({}))
mod.write_a(1.5)
assert mod.a == 1.5
@pytest.mark.parametrize('arg, value', [
('always', 0),
(0, 0),
('never', 999999999),
(999999999, 999999999),
('default', 0.25),
(1, 1),
])
def test_update_unchanged_ok(arg, value):
srv = ServerStub({})
generalConfig.testinit(omit_unchanged_within=0.25) # override value from DispatcherStub
class Mod1(Module):
a = Parameter('', FloatRange(), default=0, update_unchanged=arg)
mod1 = Mod1('mod1', LoggerStub(), {'description': ''}, srv)
par = mod1.parameters['a']
assert par.omit_unchanged_within == value
assert Mod1.a.omit_unchanged_within == 0
class Mod2(Module):
a = Parameter('', FloatRange(), default=0)
mod2 = Mod2('mod2', LoggerStub(), {'description': '', 'a': {'update_unchanged': arg}}, srv)
par = mod2.parameters['a']
assert par.omit_unchanged_within == value
assert Mod2.a.omit_unchanged_within == 0
def test_omit_unchanged_within():
srv = ServerStub({})
generalConfig.testinit(omit_unchanged_within=0.25) # override call from DispatcherStub
class Mod(Module):
a = Parameter('', FloatRange())
mod1 = Mod('mod1', LoggerStub(), {'description': ''}, srv)
assert mod1.parameters['a'].omit_unchanged_within == 0.25
mod2 = Mod('mod2', LoggerStub(), {'description': '', 'omit_unchanged_within': 0.125}, srv)
assert mod2.parameters['a'].omit_unchanged_within == 0.125

View File

@@ -109,3 +109,21 @@ def test_Export():
class Mod(HasAccessibles):
param = Parameter('description1', datatype=BoolType, default=False)
assert Mod.param.export == '_param'
@pytest.mark.parametrize('arg, value', [
('always', 0),
(0, 0),
('never', 999999999),
(999999999, 999999999),
(1, 1),
])
def test_update_unchanged_ok(arg, value):
par = Parameter('', datatype=FloatRange(), default=0, update_unchanged=arg)
assert par.update_unchanged == value
@pytest.mark.parametrize('arg', ['alws', '', -2, -0.1, None])
def test_update_unchanged_fail(arg):
with pytest.raises(ProgrammingError):
Parameter('', datatype=FloatRange(), default=0, update_unchanged=arg)

View File

@@ -31,6 +31,7 @@ import pytest
from frappy.core import Module, Parameter, FloatRange, Readable, ReadHandler, nopoll
from frappy.lib.multievent import MultiEvent
from frappy.lib import generalConfig
class Time:
@@ -66,13 +67,14 @@ class DispatcherStub:
class ServerStub:
def __init__(self):
generalConfig.testinit()
self.dispatcher = DispatcherStub()
class Base(Module):
def __init__(self):
srv = ServerStub()
super().__init__('mod', logging.getLogger('dummy'), dict(description=''), srv)
super().__init__('mod', logging.getLogger('dummy'), {'description': ''}, srv)
self.dispatcher = srv.dispatcher
def run(self, maxcycles):

View File

@@ -24,6 +24,7 @@
from frappy.core import Drivable, Parameter
from frappy.datatypes import StatusType, Enum
from frappy.states import StateMachine, Stop, Retry, Finish, Start, HasStates, status_code
from frappy.lib import generalConfig
class LoggerStub:
@@ -189,9 +190,9 @@ class DispatcherStub:
# initial value from the timestamp. However, in the test below
# the second update happens after the updates dict is cleared
# -> we have to inhibit the 'omit unchanged update' feature
omit_unchanged_within = 0
def __init__(self, updates):
generalConfig.testinit(omit_unchanged_within=0)
self.updates = updates
def announce_update(self, modulename, pname, pobj):