Skip to content

Commit ec912f9

Browse files
Fix inference involving @functools.lru_cache decorator (#2259)
1 parent 4d03bec commit ec912f9

File tree

3 files changed

+24
-17
lines changed

3 files changed

+24
-17
lines changed

ChangeLog

+5
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ Release date: TBA
216216

217217
Closes pylint-dev/pylint#8802
218218

219+
* Fix inference of functions with ``@functools.lru_cache`` decorators without
220+
parentheses.
221+
222+
Closes pylint-dev/pylint#8868
223+
219224

220225
What's New in astroid 2.15.6?
221226
=============================

astroid/brain/brain_functools.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,17 @@ def _looks_like_lru_cache(node) -> bool:
134134
if not node.decorators:
135135
return False
136136
for decorator in node.decorators.nodes:
137-
if not isinstance(decorator, Call):
137+
if not isinstance(decorator, (Attribute, Call)):
138138
continue
139139
if _looks_like_functools_member(decorator, "lru_cache"):
140140
return True
141141
return False
142142

143143

144-
def _looks_like_functools_member(node, member) -> bool:
145-
"""Check if the given Call node is a functools.partial call."""
144+
def _looks_like_functools_member(node: Attribute | Call, member: str) -> bool:
145+
"""Check if the given Call node is the wanted member of functools."""
146+
if isinstance(node, Attribute):
147+
return node.attrname == member
146148
if isinstance(node.func, Name):
147149
return node.func.name == member
148150
if isinstance(node.func, Attribute):

tests/test_object_model.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -833,26 +833,26 @@ def test_str_argument_not_required(self) -> None:
833833
assert not args.elts
834834

835835

836-
class LruCacheModelTest(unittest.TestCase):
837-
def test_lru_cache(self) -> None:
838-
ast_nodes = builder.extract_node(
839-
"""
836+
@pytest.mark.parametrize("parentheses", (True, False))
837+
def test_lru_cache(parentheses) -> None:
838+
ast_nodes = builder.extract_node(
839+
f"""
840840
import functools
841841
class Foo(object):
842-
@functools.lru_cache()
842+
@functools.lru_cache{"()" if parentheses else ""}
843843
def foo():
844844
pass
845845
f = Foo()
846846
f.foo.cache_clear #@
847847
f.foo.__wrapped__ #@
848848
f.foo.cache_info() #@
849849
"""
850-
)
851-
assert isinstance(ast_nodes, list)
852-
cache_clear = next(ast_nodes[0].infer())
853-
self.assertIsInstance(cache_clear, astroid.BoundMethod)
854-
wrapped = next(ast_nodes[1].infer())
855-
self.assertIsInstance(wrapped, astroid.FunctionDef)
856-
self.assertEqual(wrapped.name, "foo")
857-
cache_info = next(ast_nodes[2].infer())
858-
self.assertIsInstance(cache_info, astroid.Instance)
850+
)
851+
assert isinstance(ast_nodes, list)
852+
cache_clear = next(ast_nodes[0].infer())
853+
assert isinstance(cache_clear, astroid.BoundMethod)
854+
wrapped = next(ast_nodes[1].infer())
855+
assert isinstance(wrapped, astroid.FunctionDef)
856+
assert wrapped.name == "foo"
857+
cache_info = next(ast_nodes[2].infer())
858+
assert isinstance(cache_info, astroid.Instance)

0 commit comments

Comments
 (0)