From e0d335a94c90fafce4d02af9bc1166227a47a54c Mon Sep 17 00:00:00 2001 From: a <@> Date: Wed, 4 Oct 2023 18:46:53 -0400 Subject: [PATCH 1/3] fix range checker throwing error with 3 params --- python_ta/checkers/invalid_range_index_checker.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/python_ta/checkers/invalid_range_index_checker.py b/python_ta/checkers/invalid_range_index_checker.py index 83e1ac6cb..28c2652d0 100644 --- a/python_ta/checkers/invalid_range_index_checker.py +++ b/python_ta/checkers/invalid_range_index_checker.py @@ -26,7 +26,12 @@ def visit_call(self, node): if not (name in node.frame() or name in node.root()) and name == "range": arg = node.args # the arguments of 'range' call # guard nodes (e.g. Name) not properly handled by literal_eval. - if any([not isinstance(item, nodes.Const) for item in arg]): + if any( + [ + not isinstance(item, nodes.Const) and not isinstance(item, nodes.UnaryOp) + for item in arg + ] + ): return eval_parm = list(map(lambda z: literal_eval(z.as_string()), arg)) @@ -44,8 +49,8 @@ def visit_call(self, node): if ( abs(eval_parm[2]) >= abs(eval_parm[0] - eval_parm[1]) or eval_parm[2] == 0 - or (eval_parm[0] > eval_parm[1] and eval_parm[2] < 0) - or (eval_parm[0] < eval_parm[1] and eval_parm[2] > 0) + or (eval_parm[0] > eval_parm[1] and eval_parm[2] > 0) + or (eval_parm[0] < eval_parm[1] and eval_parm[2] < 0) ): args = "{}".format(node.lineno) self.add_message("invalid-range-index", node=node, args=args) From 40e1b9d235c663bac526a1afe589a5a8ea9c453c Mon Sep 17 00:00:00 2001 From: a <@> Date: Wed, 4 Oct 2023 18:47:11 -0400 Subject: [PATCH 2/3] add test cases --- .../test_invalid_range_checker.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/test_custom_checkers/test_invalid_range_checker.py diff --git a/tests/test_custom_checkers/test_invalid_range_checker.py b/tests/test_custom_checkers/test_invalid_range_checker.py new file mode 100644 index 000000000..5ca27d6ce --- /dev/null +++ b/tests/test_custom_checkers/test_invalid_range_checker.py @@ -0,0 +1,85 @@ +"""Test suite for testing the InvalidRangeIndexChecker.""" +import astroid +import pylint.testutils + +from python_ta.checkers.invalid_range_index_checker import InvalidRangeIndexChecker + + +class TestInvalidNameChecker(pylint.testutils.CheckerTestCase): + CHECKER_CLASS = InvalidRangeIndexChecker + + def _test_invalid(self, src): + mod = astroid.parse(src) + node, *_ = mod.nodes_of_class(astroid.nodes.Call) + + with self.assertAddsMessages( + pylint.testutils.MessageTest(msg_id="invalid-range-index", node=node, line=1, args="1"), + ignore_position=True, + ): + self.checker.visit_call(node) + + def _test_valid(self, src): + mod = astroid.parse(src) + node, *_ = mod.nodes_of_class(astroid.nodes.Call) + + with self.assertNoMessages(): + self.checker.visit_call(node) + + def test_zero_param(self) -> None: + """Tests range()""" + + self._test_invalid("range()") + + def test_one_param(self) -> None: + """Tests range(x) where x >= 2""" + + self._test_valid("range(5)") + + def test_invalid_one_param(self) -> None: + """Tests range(x) where x < 2""" + + self._test_invalid("range(1)") + self._test_invalid("range(0)") + self._test_invalid("range(-1)") + + def test_two_param(self) -> None: + """Tests range(x, y) where y - x >= 2""" + + self._test_valid("range(2, 5)") + + def test_invalid_two_param(self) -> None: + """Tests range(x, y) where y - x < 2""" + + self._test_invalid("range(2, 3)") + self._test_invalid("range(2, 2)") + self._test_invalid("range(2, 1)") + + def test_non_int_param(self) -> None: + """Tests range(x) where x is not int""" + + self._test_invalid("range(5.5)") + + def test_three_param(self) -> None: + """Tests range(x, y, z) where y - x < 2""" + + self._test_valid("range(1, 5, 3)") + self._test_valid("range(5, 1, -3)") + + def test_three_param_big_inc(self) -> None: + """Tests range(x, y, z) where abs(z) > abs(x - y)""" + + self._test_invalid("range(1, 5, 12)") + self._test_invalid("range(1, 5, -12)") + self._test_invalid("range(1, -5, 12)") + self._test_invalid("range(-1, -5, 12)") + + def test_three_param_zero_inc(self) -> None: + """Tests range(x, y, z) where z = 0""" + + self._test_invalid("range(1, 5, 0)") + + def test_three_param_opposite_inc(self) -> None: + """Tests range(x, y, z) where z is going in the wrong direction""" + + self._test_invalid("range(1, 5, -2)") + self._test_invalid("range(5, 1, 2)") From 2206a2ef7a70088935ff565671ee44c9f355f4d8 Mon Sep 17 00:00:00 2001 From: a <@> Date: Wed, 4 Oct 2023 18:51:13 -0400 Subject: [PATCH 3/3] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61177e0e5..afaf7bd53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Fix `naming-convention-violation` bug where `_` was considered an invalid variable name. - Fix `naming-convention-violation` bug where top-level constants were being checked as regular variable names. +- Fix `invalid-range-index` bug where `range(1, 5, 3)` would not pass the check ### Enhancements