Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate range #725

Merged
merged 10 commits into from
Aug 2, 2023
26 changes: 26 additions & 0 deletions param/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2378,6 +2378,32 @@ def __init__(self, default=Undefined, bounds=Undefined, softbounds=Undefined,
def _validate(self, val):
super(Range, self)._validate(val)
self._validate_bounds(val, self.bounds, self.inclusive_bounds)
self._validate_step(val, self.step)
self._validate_order(val, self.step, allow_None=self.allow_None)

def _validate_step(self, val, step):
if step is not None:
if not _is_number(step):
raise ValueError("Step can only be None or a "
"numeric value, not type %r." % type(step))
elif step == 0:
raise ValueError("Step cannot be 0.")

def _validate_order(self, val, step, allow_None):
if val is None and allow_None:
return
elif val is not None and (val[0] is None or val[1] is None):
return

start, end = val
if step is not None and step > 0 and not start <= end:
name = "" if self.name is None else " %rs" % self.name
raise ValueError("Range parameter%s end %s is less than its start %s with positive step %s."
% (name, end, start, step))
elif step is not None and step < 0 and not start >= end:
name = "" if self.name is None else " %rs" % self.name
raise ValueError("Range parameter%s start %s is less than its end %s with negative step %s."
% (name, start, end, step))

def _validate_bounds(self, val, bounds, inclusive_bounds):
if bounds is None or (val is None and self.allow_None):
Expand Down
30 changes: 30 additions & 0 deletions tests/testrangeparameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,33 @@ def test_get_soft_bounds(self):
q = param.Range((1,3), bounds=(0, 10), softbounds=(1, 9))
self.assertEqual(q.get_soft_bounds(), (1, 9))

def test_validate_step(self):
msg = r"Step can only be None or a numeric value, not type <class 'str'>."

p = param.Range((1, 2), bounds=(0, 10), step=1)
with self.assertRaisesRegex(ValueError, msg):
q = param.Range((1, 2), bounds=(0, 10), step="1")

def test_validate_order_on_val_with_positive_step(self):
msg = r"Range parameter 'q's end 1 is less than its start 2 with positive step 1."

class Q(param.Parameterized):
q = param.Range(bounds=(0, 10), step=1)

with self.assertRaisesRegex(ValueError, msg):
Q.q = (2, 1)

def test_validate_order_on_val_with_negative_step(self):
msg = r"Range parameter 'q's start -4 is less than its end -2 with negative step -1."

class Q(param.Parameterized):
q = param.Range(bounds=(-5, -1), step=-1)

with self.assertRaisesRegex(ValueError, msg):
Q.q = (-4, -2)

def test_validate_step_order_cannot_be_0(self):
msg = r"Step cannot be 0."

with self.assertRaisesRegex(ValueError, msg):
q = param.Range(bounds=(0, 10), step=0)