From b15e5c47472871c729a7feccb69f3c87d27b3714 Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 21 Jul 2023 07:56:42 -0700 Subject: [PATCH 1/2] Fix inference involving `@functools.lru_cache` decorator (#2259) (cherry picked from commit ec912f9d039457e513b4bc375d85810142ac1edd) --- ChangeLog | 5 +++++ astroid/brain/brain_functools.py | 8 +++++--- tests/test_object_model.py | 28 ++++++++++++++-------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 147a2f9d07..1871794509 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,11 @@ Release date: 2023-07-08 Closes pylint-dev/pylint#8802 +* Fix inference of functions with ``@functools.lru_cache`` decorators without + parentheses. + + Closes pylint-dev/pylint#8868 + What's New in astroid 2.15.6? ============================= diff --git a/astroid/brain/brain_functools.py b/astroid/brain/brain_functools.py index f6a9830d3d..645c54e723 100644 --- a/astroid/brain/brain_functools.py +++ b/astroid/brain/brain_functools.py @@ -129,15 +129,17 @@ def _looks_like_lru_cache(node) -> bool: if not node.decorators: return False for decorator in node.decorators.nodes: - if not isinstance(decorator, Call): + if not isinstance(decorator, (Attribute, Call)): continue if _looks_like_functools_member(decorator, "lru_cache"): return True return False -def _looks_like_functools_member(node, member) -> bool: - """Check if the given Call node is a functools.partial call.""" +def _looks_like_functools_member(node: Attribute | Call, member: str) -> bool: + """Check if the given Call node is the wanted member of functools.""" + if isinstance(node, Attribute): + return node.attrname == member if isinstance(node.func, Name): return node.func.name == member if isinstance(node.func, Attribute): diff --git a/tests/test_object_model.py b/tests/test_object_model.py index 8f41eda543..e578c5643b 100644 --- a/tests/test_object_model.py +++ b/tests/test_object_model.py @@ -809,13 +809,13 @@ def test_str_argument_not_required(self) -> None: assert not args.elts -class LruCacheModelTest(unittest.TestCase): - def test_lru_cache(self) -> None: - ast_nodes = builder.extract_node( - """ +@pytest.mark.parametrize("parentheses", (True, False)) +def test_lru_cache(parentheses) -> None: + ast_nodes = builder.extract_node( + f""" import functools class Foo(object): - @functools.lru_cache() + @functools.lru_cache{"()" if parentheses else ""} def foo(): pass f = Foo() @@ -823,12 +823,12 @@ def foo(): f.foo.__wrapped__ #@ f.foo.cache_info() #@ """ - ) - assert isinstance(ast_nodes, list) - cache_clear = next(ast_nodes[0].infer()) - self.assertIsInstance(cache_clear, astroid.BoundMethod) - wrapped = next(ast_nodes[1].infer()) - self.assertIsInstance(wrapped, astroid.FunctionDef) - self.assertEqual(wrapped.name, "foo") - cache_info = next(ast_nodes[2].infer()) - self.assertIsInstance(cache_info, astroid.Instance) + ) + assert isinstance(ast_nodes, list) + cache_clear = next(ast_nodes[0].infer()) + assert isinstance(cache_clear, astroid.BoundMethod) + wrapped = next(ast_nodes[1].infer()) + assert isinstance(wrapped, astroid.FunctionDef) + assert wrapped.name == "foo" + cache_info = next(ast_nodes[2].infer()) + assert isinstance(cache_info, astroid.Instance) From 921ff5e04621fdddef85c21583587c453d906eba Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Fri, 21 Jul 2023 10:01:46 -0700 Subject: [PATCH 2/2] Update ChangeLog --- ChangeLog | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1871794509..1cfba953a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,12 +16,6 @@ What's New in astroid 2.15.7? ============================= Release date: TBA - - -What's New in astroid 2.15.7? -============================= -Release date: 2023-07-08 - * Fix a crash when inferring a ``typing.TypeVar`` call. Closes pylint-dev/pylint#8802