Skip to content

Commit

Permalink
Fix inference involving @functools.lru_cache decorator (#2259)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobtylerwalls committed Jul 21, 2023
1 parent 4d03bec commit ec912f9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 17 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ Release date: TBA

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?
=============================
Expand Down
8 changes: 5 additions & 3 deletions astroid/brain/brain_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,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):
Expand Down
28 changes: 14 additions & 14 deletions tests/test_object_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,26 +833,26 @@ 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()
f.foo.cache_clear #@
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)

0 comments on commit ec912f9

Please sign in to comment.