frappy/test/test_callbacks.py
Markus Zolliker 6e7be6b4c7 simplify callbacks
on Module, use one single callback list 'paramsCallback' instead of
'valueCallbacks', 'errorCallbacks'. Redesign the mechanism to
avoid most of the closures.

Change-Id: Ie7f68f6bf97ab3f3cd961faa20b0e77730e5b37d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33118
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-03-08 15:33:52 +01:00

156 lines
3.8 KiB
Python

# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""test parameter callbacks"""
from test.test_modules import LoggerStub, ServerStub
import pytest
from frappy.core import Module, Parameter, FloatRange
from frappy.errors import WrongTypeError
WRONG_TYPE = WrongTypeError()
class Mod(Module):
a = Parameter('', FloatRange())
b = Parameter('', FloatRange())
c = Parameter('', FloatRange())
def read_a(self):
raise WRONG_TYPE
def read_b(self):
raise WRONG_TYPE
def read_c(self):
raise WRONG_TYPE
class Dbl(Module):
a = Parameter('', FloatRange())
b = Parameter('', FloatRange())
c = Parameter('', FloatRange())
_error_a = None
_value_b = None
_error_c = None
def update_a(self, value, err=None):
# treat error updates
try:
self.a = value * 2
except TypeError: # value is None -> err
self.announceUpdate('a', None, err)
def update_b(self, value):
self._value_b = value
# error updates are ignored
self.b = value * 2
def make(cls):
logger = LoggerStub()
srv = ServerStub({})
return cls('mod1', logger, {'description': ''}, srv)
def test_simple_callback():
mod1 = make(Mod)
result = []
def cbfunc(arg1, arg2, value):
result[:] = arg1, arg2, value
mod1.addCallback('a', cbfunc, 'ARG1', 'arg2')
mod1.a = 1.5
assert result == ['ARG1', 'arg2', 1.5]
result.clear()
with pytest.raises(WrongTypeError):
mod1.read_a()
assert not result # callback function is NOT called
def test_combi_callback():
mod1 = make(Mod)
result = []
def cbfunc(arg1, arg2, value, err=None):
result[:] = arg1, arg2, value, err
mod1.addCallback('a', cbfunc, 'ARG1', 'arg2')
mod1.a = 1.5
assert result == ['ARG1', 'arg2', 1.5, None]
result.clear()
with pytest.raises(WrongTypeError):
mod1.read_a()
assert result[:3] == ['ARG1', 'arg2', None] # callback function called with value None
assert isinstance(result[3], WrongTypeError)
def test_autoupdate():
mod1 = make(Mod)
mod2 = make(Dbl)
mod1.registerCallbacks(mod2, autoupdate=['c'])
result = {}
def cbfunc(pname, *args):
result[pname] = args
for param in 'a', 'b', 'c':
mod2.addCallback(param, cbfunc, param)
# test update_a without error
mod1.a = 5
assert mod2.a == 10
assert result.pop('a') == (10,)
# test update_a with error
with pytest.raises(WrongTypeError):
mod1.read_a()
assert result.pop('a') == (None, WRONG_TYPE)
# test that update_b is ignored in case of error
mod1.b = 3
assert mod2.b == 6 # no error
assert result.pop('b') == (6,)
with pytest.raises(WrongTypeError):
mod1.read_b()
assert 'b' not in result
# test autoupdate
mod1.c = 3
assert mod2.c == 3
assert result['c'] == (3,)
with pytest.raises(WrongTypeError):
mod1.read_c()
assert result['c'] == (None, WRONG_TYPE)