From 7091f278e619afd7c3fbb7ad2bf66c17f1774284 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 11 Sep 2022 08:08:19 -0400 Subject: [PATCH 1/2] Fix ``unhashable-member`` crash when ``lambda`` used as a dict key --- doc/whatsnew/fragments/7453.bugfix | 3 +++ pylint/checkers/utils.py | 13 ++++++++++++- tests/functional/u/unhashable_member.py | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/7453.bugfix diff --git a/doc/whatsnew/fragments/7453.bugfix b/doc/whatsnew/fragments/7453.bugfix new file mode 100644 index 0000000000..94b5240dd4 --- /dev/null +++ b/doc/whatsnew/fragments/7453.bugfix @@ -0,0 +1,3 @@ +Fixed a crash in the ``unhashable-member`` checker when using a ``lambda`` as a dict key. + +Closes #7453 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 1c66de6878..780806c770 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -19,7 +19,7 @@ import _string import astroid.objects -from astroid import TooManyLevelsError, nodes +from astroid import TooManyLevelsError, bases, nodes from astroid.context import InferenceContext from astroid.exceptions import AstroidError from astroid.nodes._base_nodes import ImportNode @@ -38,6 +38,15 @@ nodes.DictComp, nodes.GeneratorExp, ) +WITH_IGETATTR = ( + nodes.Module, + nodes.ClassDef, + nodes.FunctionDef, + astroid.objects.Super, + nodes.Slice, + bases.UnboundMethod, + bases.BaseInstance, +) EXCEPTIONS_MODULE = "builtins" ABC_MODULES = {"abc", "_py_abc"} ABC_METHODS = { @@ -1950,6 +1959,8 @@ def is_hashable(node: nodes.NodeNG) -> bool: for inferred in node.infer(): if inferred is astroid.Uninferable: return True + if not isinstance(inferred, WITH_IGETATTR): + return True hash_fn = next(inferred.igetattr("__hash__")) if hash_fn.parent is inferred: return True diff --git a/tests/functional/u/unhashable_member.py b/tests/functional/u/unhashable_member.py index 1225543756..a9100b9058 100644 --- a/tests/functional/u/unhashable_member.py +++ b/tests/functional/u/unhashable_member.py @@ -21,3 +21,4 @@ class Unhashable: {[1, 2, 3]} # [unhashable-member] {"tomato": "tomahto"} {dict: {}} +{lambda x: x: "tomato"} # pylint: disable=unnecessary-lambda From a2450c6f4e2532bd3846a3e12872db3b1f896008 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 11 Sep 2022 16:47:07 -0400 Subject: [PATCH 2/2] fixup! Fix ``unhashable-member`` crash --- pylint/checkers/utils.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 780806c770..f0b0de75ca 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -19,7 +19,7 @@ import _string import astroid.objects -from astroid import TooManyLevelsError, bases, nodes +from astroid import TooManyLevelsError, nodes from astroid.context import InferenceContext from astroid.exceptions import AstroidError from astroid.nodes._base_nodes import ImportNode @@ -38,15 +38,6 @@ nodes.DictComp, nodes.GeneratorExp, ) -WITH_IGETATTR = ( - nodes.Module, - nodes.ClassDef, - nodes.FunctionDef, - astroid.objects.Super, - nodes.Slice, - bases.UnboundMethod, - bases.BaseInstance, -) EXCEPTIONS_MODULE = "builtins" ABC_MODULES = {"abc", "_py_abc"} ABC_METHODS = { @@ -1959,7 +1950,7 @@ def is_hashable(node: nodes.NodeNG) -> bool: for inferred in node.infer(): if inferred is astroid.Uninferable: return True - if not isinstance(inferred, WITH_IGETATTR): + if not hasattr(inferred, "igetattr"): return True hash_fn = next(inferred.igetattr("__hash__")) if hash_fn.parent is inferred: