From f1925f46ff4c93e7d191d24746b601cfeb0b4e3c Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 11 Aug 2024 10:37:42 -0400 Subject: [PATCH] Fix crash in refactoring checker when calling bound lambda (#9867) Fixes: ``` File "sources/pylint/pylint/checkers/refactoring/refactoring_checker.py", line 2094, in _is_function_def_never_returning and node.returns ^^^^^^^^^^^^ File "sources/pylint/.venv/lib/python3.11/site-packages/astroid/bases.py", line 138, in __getattr__ return getattr(self._proxied, name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'Lambda' object has no attribute 'returns' ``` Crash is reproducible if you have something like this: ```python class C: eq = lambda self, y: self == y ``` As a workaround, use a normal function instead of a lambda. Closes #9865 (cherry picked from commit b78deb6140799549ae5f2afc9cb5bc8c1afda5cc) Co-authored-by: Hashem Nasarat --- doc/whatsnew/fragments/9865.bugfix | 3 +++ .../refactoring/refactoring_checker.py | 19 ++++++++++++------- .../regression_9865_calling_bound_lambda.py | 8 ++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 doc/whatsnew/fragments/9865.bugfix create mode 100644 tests/functional/r/regression/regression_9865_calling_bound_lambda.py diff --git a/doc/whatsnew/fragments/9865.bugfix b/doc/whatsnew/fragments/9865.bugfix new file mode 100644 index 0000000000..04da90412a --- /dev/null +++ b/doc/whatsnew/fragments/9865.bugfix @@ -0,0 +1,3 @@ +Fix crash in refactoring checker when calling a lambda bound as a method. + +Closes #9865 diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 8e3dc4919b..459e28f184 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -2083,13 +2083,18 @@ def _is_function_def_never_returning( Returns: bool: True if the function never returns, False otherwise. """ - if isinstance(node, (nodes.FunctionDef, astroid.BoundMethod)) and node.returns: - return ( - isinstance(node.returns, nodes.Attribute) - and node.returns.attrname == "NoReturn" - or isinstance(node.returns, nodes.Name) - and node.returns.name == "NoReturn" - ) + if isinstance(node, (nodes.FunctionDef, astroid.BoundMethod)): + try: + returns: nodes.NodeNG | None = node.returns + except AttributeError: + return False # the BoundMethod proxy may be a lambda without a returns + if returns is not None: + return ( + isinstance(returns, nodes.Attribute) + and returns.attrname == "NoReturn" + or isinstance(returns, nodes.Name) + and returns.name == "NoReturn" + ) try: return node.qname() in self._never_returning_functions except (TypeError, AttributeError): diff --git a/tests/functional/r/regression/regression_9865_calling_bound_lambda.py b/tests/functional/r/regression/regression_9865_calling_bound_lambda.py new file mode 100644 index 0000000000..2a8dae1b0b --- /dev/null +++ b/tests/functional/r/regression/regression_9865_calling_bound_lambda.py @@ -0,0 +1,8 @@ +"""Regression for https://github.com/pylint-dev/pylint/issues/9865.""" +# pylint: disable=missing-docstring,too-few-public-methods,unnecessary-lambda-assignment +class C: + eq = lambda self, y: self == y + +def test_lambda_method(): + ret = C().eq(1) + return ret