validator should take resolution into account
also changed names: according to the meeting in 2019-01-16 we decided to use absolute_resolution/relative_resolution instead of _precision Change-Id: I4a49bb745901b87c2aa2bc2728fd7a44026421e0 Reviewed-on: https://forge.frm2.tum.de/review/20321 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
parent
bc33f263ec
commit
0eb68e54be
@ -108,24 +108,24 @@ class FloatRange(DataType):
|
||||
"""Restricted float type"""
|
||||
|
||||
def __init__(self, minval=None, maxval=None, unit=None, fmtstr=None,
|
||||
absolute_precision=None, relative_precision=None,):
|
||||
absolute_resolution=None, relative_resolution=None,):
|
||||
self._defaults = {}
|
||||
self.setprop('min', minval, float(u'-inf'), float)
|
||||
self.setprop('max', maxval, float(u'+inf'), float)
|
||||
self.setprop('unit', unit, u'', unicode)
|
||||
self.setprop('fmtstr', fmtstr, u'%g', unicode)
|
||||
self.setprop('absolute_precision', absolute_precision, 0.0, float)
|
||||
self.setprop('relative_precision', relative_precision, 1.2e-7, float)
|
||||
self.setprop('absolute_resolution', absolute_resolution, 0.0, float)
|
||||
self.setprop('relative_resolution', relative_resolution, 1.2e-7, float)
|
||||
|
||||
# check values
|
||||
if self.min > self.max:
|
||||
raise ValueError(u'Max must be larger then min!')
|
||||
raise ValueError(u'max must be larger then min!')
|
||||
if '%' not in self.fmtstr:
|
||||
raise ValueError(u'Invalid fmtstr!')
|
||||
if self.absolute_precision < 0:
|
||||
raise ValueError(u'absolute_precision MUST be >=0')
|
||||
if self.relative_precision < 0:
|
||||
raise ValueError(u'relative_precision MUST be >=0')
|
||||
if self.absolute_resolution < 0:
|
||||
raise ValueError(u'absolute_resolution MUST be >=0')
|
||||
if self.relative_resolution < 0:
|
||||
raise ValueError(u'relative_resolution MUST be >=0')
|
||||
|
||||
@property
|
||||
def as_json(self):
|
||||
@ -137,17 +137,10 @@ class FloatRange(DataType):
|
||||
value = float(value)
|
||||
except Exception:
|
||||
raise ValueError(u'Can not validate %r to float' % value)
|
||||
if self.min is not None and value < self.min:
|
||||
raise ValueError(u'%r should not be less then %s' %
|
||||
(value, self.min))
|
||||
if self.max is not None and value > self.max:
|
||||
raise ValueError(u'%r should not be greater than %s' %
|
||||
(value, self.max))
|
||||
if None in (self.min, self.max):
|
||||
return value
|
||||
if self.min <= value <= self.max:
|
||||
return value
|
||||
raise ValueError(u'%r should be an float between %.3f and %.3f' %
|
||||
prec = max(abs(value * self.relative_resolution), self.absolute_resolution)
|
||||
if self.min - prec <= value <= self.max + prec:
|
||||
return min(max(value, self.min), self.max)
|
||||
raise ValueError(u'%g should be a float between %g and %g' %
|
||||
(value, self.min, self.max))
|
||||
|
||||
def __repr__(self):
|
||||
@ -228,15 +221,15 @@ class ScaledInteger(DataType):
|
||||
the scale is only used for calculating to/from transport serialisation"""
|
||||
|
||||
def __init__(self, scale, minval=None, maxval=None, unit=None, fmtstr=None,
|
||||
absolute_precision=None, relative_precision=None,):
|
||||
absolute_resolution=None, relative_resolution=None,):
|
||||
self._defaults = {}
|
||||
self.scale = float(scale)
|
||||
if not self.scale > 0:
|
||||
raise ValueError(u'Scale MUST be positive!')
|
||||
self.setprop('unit', unit, u'', unicode)
|
||||
self.setprop('fmtstr', fmtstr, u'%g', unicode)
|
||||
self.setprop('absolute_precision', absolute_precision, self.scale, float)
|
||||
self.setprop('relative_precision', relative_precision, 1.2e-7, float)
|
||||
self.setprop('absolute_resolution', absolute_resolution, self.scale, float)
|
||||
self.setprop('relative_resolution', relative_resolution, 1.2e-7, float)
|
||||
|
||||
self.min = DEFAULT_MIN_INT * self.scale if minval is None else float(minval)
|
||||
self.max = DEFAULT_MAX_INT * self.scale if maxval is None else float(maxval)
|
||||
@ -246,10 +239,10 @@ class ScaledInteger(DataType):
|
||||
raise ValueError(u'Max must be larger then min!')
|
||||
if '%' not in self.fmtstr:
|
||||
raise ValueError(u'Invalid fmtstr!')
|
||||
if self.absolute_precision < 0:
|
||||
raise ValueError(u'absolute_precision MUST be >=0')
|
||||
if self.relative_precision < 0:
|
||||
raise ValueError(u'relative_precision MUST be >=0')
|
||||
if self.absolute_resolution < 0:
|
||||
raise ValueError(u'absolute_resolution MUST be >=0')
|
||||
if self.relative_resolution < 0:
|
||||
raise ValueError(u'relative_resolution MUST be >=0')
|
||||
|
||||
@property
|
||||
def as_json(self):
|
||||
@ -265,11 +258,12 @@ class ScaledInteger(DataType):
|
||||
value = float(value)
|
||||
except Exception:
|
||||
raise ValueError(u'Can not validate %r to float' % value)
|
||||
if value < self.min:
|
||||
raise ValueError(u'%r should be a float between %d and %d' %
|
||||
(value, self.min, self.max))
|
||||
if value > self.max:
|
||||
raise ValueError(u'%r should be a float between %d and %d' %
|
||||
prec = max(self.scale, abs(value * self.relative_resolution),
|
||||
self.absolute_resolution)
|
||||
if self.min - prec <= value <= self.max + prec:
|
||||
value = min(max(value, self.min), self.max)
|
||||
else:
|
||||
raise ValueError(u'%g should be a float between %g and %g' %
|
||||
(value, self.min, self.max))
|
||||
intval = int((value + self.scale * 0.5) // self.scale)
|
||||
value = float(intval * self.scale)
|
||||
|
@ -56,6 +56,7 @@ def test_FloatRange():
|
||||
dt.validate([19, u'X'])
|
||||
dt.validate(1)
|
||||
dt.validate(0)
|
||||
dt.validate(13.14 - 10) # raises an error, if resolution is not handled correctly
|
||||
assert dt.export_value(-2.718) == -2.718
|
||||
assert dt.import_value(-2.718) == -2.718
|
||||
with pytest.raises(ValueError):
|
||||
@ -64,11 +65,11 @@ def test_FloatRange():
|
||||
dt = FloatRange()
|
||||
assert dt.as_json == [u'double', {}]
|
||||
|
||||
dt = FloatRange(unit=u'X', fmtstr=u'%r', absolute_precision=1,
|
||||
relative_precision=0.1)
|
||||
dt = FloatRange(unit=u'X', fmtstr=u'%r', absolute_resolution=1,
|
||||
relative_resolution=0.1)
|
||||
assert dt.as_json == [u'double', {u'unit':u'X', u'fmtstr':u'%r',
|
||||
u'absolute_precision':1,
|
||||
u'relative_precision':0.1}]
|
||||
u'absolute_resolution':1,
|
||||
u'relative_resolution':0.1}]
|
||||
assert dt.validate(4) == 4
|
||||
assert dt.format_value(3.14) == u'3.14 X'
|
||||
assert dt.format_value(3.14, u'') == u'3.14'
|
||||
@ -126,15 +127,18 @@ def test_ScaledInteger():
|
||||
assert dt.import_value(272) == 2.72
|
||||
|
||||
dt = ScaledInteger(0.003, 0, 1, unit=u'X', fmtstr=u'%r',
|
||||
absolute_precision=1, relative_precision=0.1)
|
||||
absolute_resolution=0.001, relative_resolution=1e-5)
|
||||
assert dt.as_json == [u'scaled', {u'scale':0.003,u'min':0,u'max':333,
|
||||
u'unit':u'X', u'fmtstr':u'%r',
|
||||
u'absolute_precision':1,
|
||||
u'relative_precision':0.1}]
|
||||
u'absolute_resolution':0.001,
|
||||
u'relative_resolution':1e-5}]
|
||||
assert dt.validate(0.4) == 0.399
|
||||
assert dt.format_value(0.4) == u'0.4 X'
|
||||
assert dt.format_value(0.4, u'') == u'0.4'
|
||||
assert dt.format_value(0.4, u'Z') == u'0.4 Z'
|
||||
assert dt.validate(1.0029) == 0.999
|
||||
with pytest.raises(ValueError):
|
||||
dt.validate(1.004)
|
||||
|
||||
|
||||
def test_EnumType():
|
||||
|
Loading…
x
Reference in New Issue
Block a user