check for problematic value range
A common problematic practice is, to declare the value parameter with the same FloatRange than the target. Because of measurement errors, a value might be near, but outside the limit. In order to avoid this, we force the programmer to declare a bigger range for the value than for the target, or to explicitly disable this check on a module property. It is also fine to declare the value without limits. This behavior may be disabled via command line option or in the general config file. For simplicity, FloatRanges inside data structures are not considered. + above command line option is also used to disable the error handling on a string to float conversion + log appropriate error message for string to float conversion Change-Id: Ib78ea1fb7c821442bf5847030573c8c27822dea5 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27574 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
@ -29,10 +29,10 @@ from collections import OrderedDict
|
||||
from functools import wraps
|
||||
|
||||
from secop.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \
|
||||
IntRange, StatusType, StringType, TextType, TupleOf
|
||||
IntRange, StatusType, StringType, TextType, TupleOf, DiscouragedConversion
|
||||
from secop.errors import BadValueError, ConfigError, \
|
||||
ProgrammingError, SECoPError, SilentError, secop_error
|
||||
from secop.lib import formatException, mkthread, UniqueObject
|
||||
from secop.lib import formatException, mkthread, UniqueObject, generalConfig
|
||||
from secop.lib.enum import Enum
|
||||
from secop.params import Accessible, Command, Parameter
|
||||
from secop.poller import BasicPoller, Poller
|
||||
@ -40,6 +40,8 @@ from secop.properties import HasProperties, Property
|
||||
from secop.logging import RemoteLogHandler, HasComlog
|
||||
|
||||
|
||||
generalConfig.defaults['disable_value_range_check'] = False # check for problematic value range by default
|
||||
|
||||
Done = UniqueObject('already set')
|
||||
"""a special return value for a read/write function
|
||||
|
||||
@ -475,9 +477,13 @@ class Module(HasAccessibles):
|
||||
changed = pobj.value != value
|
||||
try:
|
||||
# store the value even in case of error
|
||||
# TODO: we should neither check limits nor convert string to float here
|
||||
pobj.value = pobj.datatype(value)
|
||||
except Exception as e:
|
||||
if isinstance(e, DiscouragedConversion):
|
||||
if DiscouragedConversion.log_message:
|
||||
self.log.error(str(e))
|
||||
self.log.error('you may disable this behaviour by running the server with --relaxed')
|
||||
DiscouragedConversion.log_message = False
|
||||
if not err: # do not overwrite given error
|
||||
err = e
|
||||
if err:
|
||||
@ -682,10 +688,30 @@ class Readable(Module):
|
||||
|
||||
class Writable(Readable):
|
||||
"""basic writable module"""
|
||||
|
||||
disable_value_range_check = Property('disable value range check', BoolType(), default=False)
|
||||
target = Parameter('target value of the module',
|
||||
default=0, readonly=False, datatype=FloatRange(unit='$'))
|
||||
|
||||
def __init__(self, name, logger, cfgdict, srv):
|
||||
super().__init__(name, logger, cfgdict, srv)
|
||||
value_dt = self.parameters['value'].datatype
|
||||
target_dt = self.parameters['target'].datatype
|
||||
try:
|
||||
# this handles also the cases where the limits on the value are more
|
||||
# restrictive than on the target
|
||||
target_dt.compatible(value_dt)
|
||||
except Exception:
|
||||
if type(value_dt) == type(target_dt):
|
||||
raise ConfigError('the target range extends beyond the value range') from None
|
||||
raise ProgrammingError('the datatypes of target and value are not compatible') from None
|
||||
if isinstance(value_dt, FloatRange):
|
||||
if (not self.disable_value_range_check and not generalConfig.disable_value_range_check
|
||||
and value_dt.problematic_range(target_dt)):
|
||||
self.log.error('the value range must be bigger than the target range!')
|
||||
self.log.error('you may disable this error message by running the server with --relaxed')
|
||||
self.log.error('or by setting the disable_value_range_check property of the module to True')
|
||||
raise ConfigError('the value range must be bigger than the target range')
|
||||
|
||||
|
||||
class Drivable(Writable):
|
||||
"""basic drivable module"""
|
||||
|
Reference in New Issue
Block a user