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

Log RecursionError out as warning during inference #9614

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/9139.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Log RecursionError out as warning during inference.

Closes #9139
9 changes: 9 additions & 0 deletions pylint/checkers/base/basic_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@
call_inferred = list(inferred.infer_call_result(node))
except astroid.InferenceError:
call_inferred = None
except RecursionError:
utils.warn_on_recursion_error()
call_inferred = None

Check warning on line 379 in pylint/checkers/base/basic_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/base/basic_checker.py#L377-L379

Added lines #L377 - L379 were not covered by tests
if call_inferred:
self.add_message(
"missing-parentheses-for-call-in-test",
Expand Down Expand Up @@ -608,6 +611,9 @@
value = next(default.infer())
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 616 in pylint/checkers/base/basic_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/base/basic_checker.py#L614-L616

Added lines #L614 - L616 were not covered by tests

if (
isinstance(value, astroid.Instance)
Expand Down Expand Up @@ -839,6 +845,9 @@
func = next(node.args[0].func.infer())
except astroid.InferenceError:
return
except RecursionError:
utils.warn_on_recursion_error()
return

Check warning on line 850 in pylint/checkers/base/basic_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/base/basic_checker.py#L848-L850

Added lines #L848 - L850 were not covered by tests
if getattr(
func, "name", None
) == "iter" and utils.is_builtin_object(func):
Expand Down
2 changes: 1 addition & 1 deletion pylint/checkers/base/comparison_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def _is_float_nan(node: nodes.NodeNG) -> bool:
if isinstance(node, nodes.Call) and len(node.args) == 1:
if (
node.args[0].value.lower() == "nan"
and node.inferred()[0].pytype() == "builtins.float"
and utils.safe_infer(node).pytype() == "builtins.float"
):
return True
return False
Expand Down
38 changes: 33 additions & 5 deletions pylint/checkers/classes/class_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,12 @@
if is_same_fn is None:
# If the default value comparison is unhandled, assume the value is different
return True
if not is_same_fn(original_default, overridden_default):
# Two args with same type but different values
return True
try:
if not is_same_fn(original_default, overridden_default):
# Two args with same type but different values
return True
except RecursionError:
utils.warn_on_recursion_error()

Check warning on line 260 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L259-L260

Added lines #L259 - L260 were not covered by tests
return False


Expand Down Expand Up @@ -409,6 +412,9 @@
except astroid.InferenceError:
# Can't infer, avoid emitting a false positive in this case.
return True
except RecursionError:
utils.warn_on_recursion_error()
return True

Check warning on line 417 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L415-L417

Added lines #L415 - L417 were not covered by tests
return False


Expand All @@ -435,6 +441,9 @@
bound = next(call.func.infer())
except (astroid.InferenceError, StopIteration):
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 446 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L444-L446

Added lines #L444 - L446 were not covered by tests
if not isinstance(bound, astroid.BoundMethod):
continue
func_obj = bound._proxied
Expand Down Expand Up @@ -466,6 +475,9 @@
inferred = next(attr.infer())
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 480 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L478-L480

Added lines #L478 - L480 were not covered by tests
if isinstance(inferred, nodes.FunctionDef) and decorated_with_property(
inferred
):
Expand All @@ -483,7 +495,11 @@
def _has_same_layout_slots(
slots: list[nodes.Const | None], assigned_value: nodes.Name
) -> bool:
inferred = next(assigned_value.infer())
try:
inferred = next(assigned_value.infer())
except RecursionError:
utils.warn_on_recursion_error()
return False

Check warning on line 502 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L500-L502

Added lines #L500 - L502 were not covered by tests
if isinstance(inferred, nodes.ClassDef):
other_slots = inferred.slots()
if all(
Expand Down Expand Up @@ -1216,7 +1232,7 @@
"attribute-defined-outside-init", args=attr, node=node
)

# pylint: disable = too-many-branches
# pylint: disable = too-many-branches, too-many-return-statements
def visit_functiondef(self, node: nodes.FunctionDef) -> None:
"""Check method arguments, overriding."""
# ignore actual functions
Expand Down Expand Up @@ -1278,6 +1294,9 @@
inferred = next(inferred.infer_call_result(inferred))
except astroid.InferenceError:
return
except RecursionError:
utils.warn_on_recursion_error()
return

Check warning on line 1299 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L1297-L1299

Added lines #L1297 - L1299 were not covered by tests
try:
if (
isinstance(inferred, (astroid.Instance, nodes.ClassDef))
Expand Down Expand Up @@ -1513,6 +1532,9 @@
self._check_slots_elt(elt, node)
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 1537 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L1535-L1537

Added lines #L1535 - L1537 were not covered by tests
self._check_redefined_slots(node, slots, values)

def _check_redefined_slots(
Expand Down Expand Up @@ -2196,6 +2218,9 @@
)
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 2223 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L2221-L2223

Added lines #L2221 - L2223 were not covered by tests
for klass, method in not_called_yet.items():
# Check if the init of the class that defines this init has already
# been called.
Expand Down Expand Up @@ -2350,4 +2375,7 @@
to_call[base_node] = init_node
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 2380 in pylint/checkers/classes/class_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/class_checker.py#L2378-L2380

Added lines #L2378 - L2380 were not covered by tests
return to_call
7 changes: 7 additions & 0 deletions pylint/checkers/classes/special_methods_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
is_function_body_ellipsis,
only_required_for_messages,
safe_infer,
warn_on_recursion_error,
)
from pylint.lint.pylinter import PyLinter

Expand All @@ -44,13 +45,19 @@
return None # inference failed
except StopIteration:
return None # no values inferred
except RecursionError:
warn_on_recursion_error()
return None

Check warning on line 50 in pylint/checkers/classes/special_methods_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/special_methods_checker.py#L48-L50

Added lines #L48 - L50 were not covered by tests
try:
next(inferit)
return None # there is ambiguity on the inferred node
except astroid.InferenceError:
return None # there is some kind of ambiguity
except StopIteration:
return value
except RecursionError:
warn_on_recursion_error()
return value

Check warning on line 60 in pylint/checkers/classes/special_methods_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/classes/special_methods_checker.py#L58-L60

Added lines #L58 - L60 were not covered by tests


class SpecialMethodsChecker(BaseChecker):
Expand Down
4 changes: 4 additions & 0 deletions pylint/checkers/newstyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
has_known_bases,
node_frame_class,
only_required_for_messages,
warn_on_recursion_error,
)
from pylint.typing import MessageDefinitionTuple

Expand Down Expand Up @@ -107,6 +108,9 @@
supcls = call.args and next(call.args[0].infer(), None)
except astroid.InferenceError:
continue
except RecursionError:
warn_on_recursion_error()
continue

Check warning on line 113 in pylint/checkers/newstyle.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/newstyle.py#L111-L113

Added lines #L111 - L113 were not covered by tests

# If the supcls is in the ancestors of klass super can be used to skip
# a step in the mro() and get a method from a higher parent
Expand Down
3 changes: 3 additions & 0 deletions pylint/checkers/refactoring/implicit_booleaness_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@
except astroid.InferenceError:
# Probably undefined-variable, abort check
return
except RecursionError:
utils.warn_on_recursion_error()
return

Check warning on line 149 in pylint/checkers/refactoring/implicit_booleaness_checker.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/refactoring/implicit_booleaness_checker.py#L147-L149

Added lines #L147 - L149 were not covered by tests
mother_classes = self.base_names_of_instance(instance)
affected_by_pep8 = any(
t in mother_classes for t in ("str", "tuple", "list", "set")
Expand Down
4 changes: 2 additions & 2 deletions pylint/checkers/refactoring/refactoring_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from pylint import checkers
from pylint.checkers import utils
from pylint.checkers.base.basic_error_checker import _loop_exits_early
from pylint.checkers.utils import node_frame_class
from pylint.checkers.utils import node_frame_class, safe_infer
from pylint.interfaces import HIGH, INFERENCE, Confidence

if TYPE_CHECKING:
Expand Down Expand Up @@ -1997,7 +1997,7 @@ def _is_node_return_ended(self, node: nodes.NodeNG) -> bool:
return True
if isinstance(node, nodes.Call):
try:
funcdef_node = node.func.inferred()[0]
funcdef_node = safe_infer(node.func)
if self._is_function_def_never_returning(funcdef_node):
return True
except astroid.InferenceError:
Expand Down
7 changes: 7 additions & 0 deletions pylint/checkers/stdlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@
confidence = INFERENCE
try:
inferred_args = arg.inferred()
except RecursionError:
utils.warn_on_recursion_error()

Check warning on line 596 in pylint/checkers/stdlib.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/stdlib.py#L596

Added line #L596 was not covered by tests
except astroid.InferenceError:
return
for inferred in inferred_args:
Expand Down Expand Up @@ -713,6 +715,8 @@
break
except astroid.InferenceError:
pass
except RecursionError:
utils.warn_on_recursion_error()

Check warning on line 719 in pylint/checkers/stdlib.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/stdlib.py#L718-L719

Added lines #L718 - L719 were not covered by tests
for lru_cache_node in lru_cache_nodes:
self.add_message(
"method-cache-max-size-none",
Expand Down Expand Up @@ -767,6 +771,9 @@
inferred = next(node.infer())
except astroid.InferenceError:
return
except RecursionError:
utils.warn_on_recursion_error()
return

Check warning on line 776 in pylint/checkers/stdlib.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/stdlib.py#L774-L776

Added lines #L774 - L776 were not covered by tests
if isinstance(inferred, astroid.Instance) and inferred.qname() in {
"_pydatetime.time",
"datetime.time",
Expand Down
6 changes: 6 additions & 0 deletions pylint/checkers/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@
strnode = next(func.bound.infer())
except astroid.InferenceError:
return
except RecursionError:
utils.warn_on_recursion_error()
return

Check warning on line 475 in pylint/checkers/strings.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/strings.py#L473-L475

Added lines #L473 - L475 were not covered by tests
if not (isinstance(strnode, nodes.Const) and isinstance(strnode.value, str)):
return
try:
Expand Down Expand Up @@ -634,6 +637,9 @@
except astroid.InferenceError:
# can't check further if we can't infer it
break
except RecursionError:
utils.warn_on_recursion_error()
break

Check warning on line 642 in pylint/checkers/strings.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/strings.py#L640-L642

Added lines #L640 - L642 were not covered by tests


class StringConstantChecker(BaseTokenChecker, BaseRawFileChecker):
Expand Down
40 changes: 27 additions & 13 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
supports_getitem,
supports_membership_test,
supports_setitem,
warn_on_recursion_error,
)
from pylint.constants import PY310_PLUS
from pylint.interfaces import HIGH, INFERENCE
Expand Down Expand Up @@ -793,6 +794,9 @@
inferred = next(func.infer_call_result(func, context), None)
except astroid.InferenceError:
return None
except RecursionError:
utils.warn_on_recursion_error()
return None

Check warning on line 799 in pylint/checkers/typecheck.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/typecheck.py#L797-L799

Added lines #L797 - L799 were not covered by tests
return inferred or None


Expand Down Expand Up @@ -1087,6 +1091,9 @@

try:
inferred = list(node.expr.infer())
except RecursionError:
warn_on_recursion_error()
return

Check warning on line 1096 in pylint/checkers/typecheck.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/typecheck.py#L1095-L1096

Added lines #L1095 - L1096 were not covered by tests
except astroid.InferenceError:
return

Expand Down Expand Up @@ -1359,6 +1366,9 @@
call_results = list(attr.infer_call_result(node))
except astroid.InferenceError:
continue
except RecursionError:
utils.warn_on_recursion_error()
continue

Check warning on line 1371 in pylint/checkers/typecheck.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/typecheck.py#L1369-L1371

Added lines #L1369 - L1371 were not covered by tests

if all(
isinstance(return_node, util.UninferableBase)
Expand Down Expand Up @@ -1651,6 +1661,7 @@
confidence=INFERENCE,
)

# pylint: disable=too-many-try-statements
@staticmethod
def _keyword_argument_is_in_all_decorator_returns(
func: nodes.FunctionDef, keyword: str
Expand All @@ -1673,21 +1684,24 @@
if not isinstance(inferred, nodes.FunctionDef):
return False

for return_value in inferred.infer_call_result(caller=None):
# infer_call_result() returns nodes.Const.None for None return values
# so this also catches non-returning decorators
if not isinstance(return_value, nodes.FunctionDef):
return False

# If the return value uses a kwarg the keyword will be consumed
if return_value.args.kwarg:
continue
try:
for return_value in inferred.infer_call_result(caller=None):
# infer_call_result() returns nodes.Const.None for None return values
# so this also catches non-returning decorators
if not isinstance(return_value, nodes.FunctionDef):
return False

# If the return value uses a kwarg the keyword will be consumed
if return_value.args.kwarg:
continue

# Check if the keyword is another type of argument
if return_value.args.is_argument(keyword):
continue
# Check if the keyword is another type of argument
if return_value.args.is_argument(keyword):
continue

return False
return False
except RecursionError:
utils.warn_on_recursion_error()

Check warning on line 1704 in pylint/checkers/typecheck.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/typecheck.py#L1703-L1704

Added lines #L1703 - L1704 were not covered by tests

return True

Expand Down
Loading
Loading