From 485d2a9d5bb4ae53260a1cd6d776f41894efabc0 Mon Sep 17 00:00:00 2001 From: minimav <6566948+minimav@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:37:23 +0100 Subject: [PATCH 1/6] Add validation for step parameter of Range param --- param/__init__.py | 6 ++++++ tests/API0/testrangeparameter.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/param/__init__.py b/param/__init__.py index 9db272f47..90952470a 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -2125,6 +2125,12 @@ def __init__(self,default=None, bounds=None, softbounds=None, def _validate(self, val): super(Range, self)._validate(val) self._validate_bounds(val, self.bounds, self.inclusive_bounds) + self._validate_step(val, self.step) + + def _validate_step(self, val, step): + if step is not None and not _is_number(step): + raise ValueError("Step can only be None or a " + "numeric value, not type %r." % type(step)) def _validate_bounds(self, val, bounds, inclusive_bounds): if bounds is None or (val is None and self.allow_None): diff --git a/tests/API0/testrangeparameter.py b/tests/API0/testrangeparameter.py index 408919c05..dab59a149 100644 --- a/tests/API0/testrangeparameter.py +++ b/tests/API0/testrangeparameter.py @@ -51,3 +51,9 @@ 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 ." + + 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") From debb8769ad977901412ecfcc8cb05c7b10ac7e16 Mon Sep 17 00:00:00 2001 From: minimav <6566948+minimav@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:59:47 +0100 Subject: [PATCH 2/6] Add order validation to Range param --- param/__init__.py | 14 ++++++++++++++ tests/API0/testrangeparameter.py | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/param/__init__.py b/param/__init__.py index 90952470a..32e4ccd92 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -2126,12 +2126,26 @@ 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(self.bounds, allow_None=True) + self._validate_order(val, allow_None=self.allow_None) def _validate_step(self, val, step): if step is not None and not _is_number(step): raise ValueError("Step can only be None or a " "numeric value, not type %r." % type(step)) + def _validate_order(self, val, 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 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." + % (name, end, start)) + def _validate_bounds(self, val, bounds, inclusive_bounds): if bounds is None or (val is None and self.allow_None): return diff --git a/tests/API0/testrangeparameter.py b/tests/API0/testrangeparameter.py index dab59a149..f6c937ce0 100644 --- a/tests/API0/testrangeparameter.py +++ b/tests/API0/testrangeparameter.py @@ -57,3 +57,19 @@ def test_validate_step(self): 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_bounds(self): + msg = r"Range parameter end 0 is less than its start 10." + + with self.assertRaisesRegex(ValueError, msg): + class Q(param.Parameterized): + q = param.Range(bounds=(10, 0)) + + def test_validate_order_on_val(self): + msg = r"Range parameter 'q's end 1 is less than its start 2." + + class Q(param.Parameterized): + q = param.Range(bounds=(0, 10)) + + with self.assertRaisesRegex(ValueError, msg): + Q.q = (2, 1) From d8a21a74a737611665cf7ecd8f5ed3de2c976ce5 Mon Sep 17 00:00:00 2001 From: maximlt Date: Mon, 17 Apr 2023 22:02:50 +0200 Subject: [PATCH 3/6] remove bounds order validation --- param/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/param/__init__.py b/param/__init__.py index 30be5f3f3..8d67455b5 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -2379,7 +2379,6 @@ 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(self.bounds, allow_None=True) self._validate_order(val, allow_None=self.allow_None) def _validate_step(self, val, step): From 689a99cd4c51689509948c40e60c2a9d45b962a2 Mon Sep 17 00:00:00 2001 From: maximlt Date: Mon, 17 Apr 2023 22:13:06 +0200 Subject: [PATCH 4/6] fix tests --- tests/testrangeparameter.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/testrangeparameter.py b/tests/testrangeparameter.py index 5c01f4bff..0625b910d 100644 --- a/tests/testrangeparameter.py +++ b/tests/testrangeparameter.py @@ -163,13 +163,6 @@ def test_validate_step(self): with self.assertRaisesRegex(ValueError, msg): q = param.Range((1, 2), bounds=(0, 10), step="1") - def test_validate_order_on_bounds(self): - msg = r"Range parameter end 0 is less than its start 10." - - with self.assertRaisesRegex(ValueError, msg): - class Q(param.Parameterized): - q = param.Range(bounds=(10, 0)) - def test_validate_order_on_val(self): msg = r"Range parameter 'q's end 1 is less than its start 2." From ca1d16232b3b158d35c48eb1c999ae6120ffd2d9 Mon Sep 17 00:00:00 2001 From: minimav <6566948+minimav@users.noreply.github.com> Date: Mon, 3 Jul 2023 20:56:41 +0100 Subject: [PATCH 5/6] Validate bounds ordering based on step --- param/__init__.py | 25 ++++++++++++++++--------- tests/testrangeparameter.py | 21 ++++++++++++++++++--- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/param/__init__.py b/param/__init__.py index 8d67455b5..0116e735d 100644 --- a/param/__init__.py +++ b/param/__init__.py @@ -2379,24 +2379,31 @@ 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, allow_None=self.allow_None) + self._validate_order(val, self.step, allow_None=self.allow_None) def _validate_step(self, val, step): - if step is not None and not _is_number(step): - raise ValueError("Step can only be None or a " - "numeric value, not type %r." % type(step)) - - def _validate_order(self, val, allow_None): + 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 not start <= end: + 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 end %s is less than its start %s." - % (name, end, start)) + 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): diff --git a/tests/testrangeparameter.py b/tests/testrangeparameter.py index 0625b910d..dfad4d2b1 100644 --- a/tests/testrangeparameter.py +++ b/tests/testrangeparameter.py @@ -163,11 +163,26 @@ def test_validate_step(self): with self.assertRaisesRegex(ValueError, msg): q = param.Range((1, 2), bounds=(0, 10), step="1") - def test_validate_order_on_val(self): - msg = r"Range parameter 'q's end 1 is less than its start 2." + 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)) + 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) From 79bcb9e7ce92a9b60447ee4e2f097e987d8d9b49 Mon Sep 17 00:00:00 2001 From: maximlt Date: Fri, 28 Jul 2023 10:57:41 +0200 Subject: [PATCH 6/6] fix linter --- tests/testrangeparameter.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/testrangeparameter.py b/tests/testrangeparameter.py index 4e691f40a..c01cf3c0a 100644 --- a/tests/testrangeparameter.py +++ b/tests/testrangeparameter.py @@ -160,8 +160,10 @@ def test_validate_step(self): msg = r"Step can only be None or a numeric value, not type ." p = param.Range((1, 2), bounds=(0, 10), step=1) + assert p.step == 1 + with self.assertRaisesRegex(ValueError, msg): - q = param.Range((1, 2), bounds=(0, 10), step="1") + 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." @@ -185,4 +187,4 @@ 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) \ No newline at end of file + param.Range(bounds=(0, 10), step=0)