Skip to content

Add functools.lru_cache plugin support Fixes #16261 #19432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

machin0r
Copy link

Add support for functools.lru_cache decorator, Fixes #16261

Description

Problem: Functions decorated with @lru_cache lose their original type signatures, preventing mypy from validating function calls properly.

Solution:

  • Added functools_lru_cache_callback to preserve function signatures for @lru_cache
  • Added lru_cache_wrapper_call_callback to validate calls to cached functions
  • Registered callbacks in DefaultPlugin for both decorator creation and wrapper calls
  • Added tests for different lru_cache patterns

Supported patterns:

  • @lru_cache - bare decorator
  • @lru_cache() - empty parentheses
  • @lru_cache(maxsize=128) - parameters

Example

Before:

from functools import lru_cache
@lru_cache()
def f(x: int) -> str:
    return str(x)

f()  # No error, mypy can't validate arguments
f("str")  # No error, mypy can't check types

After:
from functools import lru_cache
@lru_cache()
def f(x: int) -> str:
    return str(x)

f()  # error: Missing positional argument "x" in call to "f"  [call-arg]
f("str")  # error: Argument 1 to "f" has incompatible type "str"; expected "int"  [arg-type]

Files changed:

  • mypy/plugins/functools.py - Implementation
  • mypy/plugins/default.py - Plugin registration
  • test-data/unit/check-functools.test - Test cases
  • test-data/unit/lib-stub/functools.pyi - Type stub updates

@machin0r machin0r marked this pull request as draft July 13, 2025 17:14
@machin0r machin0r marked this pull request as ready for review July 13, 2025 17:47

This comment has been minimized.

@machin0r machin0r force-pushed the implement-lru-cache-support branch from 9aa3d9f to a4372e8 Compare July 13, 2025 18:35
@machin0r machin0r marked this pull request as draft July 13, 2025 18:46
 - Add lru_cache callback to functools plugin for type validation
 - Register callbacks in default plugin for decorator and wrapper calls
 - Support different lru_cache patterns: @lru_cache, @lru_cache(), @lru_cache(maxsize=N)

Fixes issue python#16261
@machin0r machin0r force-pushed the implement-lru-cache-support branch from a4372e8 to d9d5d00 Compare July 13, 2025 18:49
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

psycopg (https://github.com/psycopg/psycopg)
+ psycopg/psycopg/rows.py:136: error: Argument 2 to "_make_nt" has incompatible type "*Generator[bytes | None, None, None]"; expected "bytes"  [arg-type]

archinstall (https://github.com/archlinux/archinstall)
+ archinstall/lib/interactions/general_conf.py:160: error: Argument 1 to "list_available_packages" has incompatible type "tuple[Repository, ...]"; expected "tuple[Repository]"  [arg-type]

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/tools/console/common.py:808: error: Argument "request_timestamp" to "format_dns_flow" has incompatible type "float | None"; expected "float"  [arg-type]
+ mitmproxy/tools/console/common.py:816: error: Argument "error_message" to "format_dns_flow" has incompatible type "str | None"; expected "str"  [arg-type]

core (https://github.com/home-assistant/core)
+ homeassistant/components/xiaomi_aqara/config_flow.py:216: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/mqtt_room/sensor.py:199: error: Argument 1 to "_slugify_upper" has incompatible type "Any | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/manager.py:468: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/light.py:182: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:191: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:202: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:211: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:212: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:217: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:229: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:246: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:251: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:265: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:346: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/config_flow.py:541: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/config_flow.py:591: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: error: Argument 2 to "make_response_filter" has incompatible type "tuple[Any, ...]"; expected "Iterator[str]"  [arg-type]
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: note: "tuple" is missing following "Iterator" protocol member:
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: note:     __next__

ibis (https://github.com/ibis-project/ibis)
+ ibis/backends/tests/test_temporal.py:2227: error: Argument "exclude" to "_get_backend_names" has incompatible type "tuple[str, str]"; expected "tuple[str]"  [arg-type]
+ ibis/backends/tests/test_temporal.py:2245: error: Argument "exclude" to "_get_backend_names" has incompatible type "tuple[str, str, str, str, str, str]"; expected "tuple[str]"  [arg-type]

@machin0r machin0r marked this pull request as ready for review July 13, 2025 19:46
@cdce8p cdce8p added the topic-plugins The plugin API and ideas for new plugins label Jul 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-plugins The plugin API and ideas for new plugins
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parameters for a call to a function wrapped in a lru_cache are not checked
2 participants