-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Add type signatures to lru_cache
using overloads (not ready to merge)
#13033
base: main
Are you sure you want to change the base?
Conversation
(I'm guessing this follows from #12952 for context) |
This comment has been minimized.
This comment has been minimized.
Yup, this is (another) attempt, but quite a bit simpler than the previous approaches, it feels like it's fixable (and this caused me a few bugs). The previous approach I used was to basically make the cache object a descriptor that (in the type system only) mirrored the behaviour of This approach instead defines an overload with and without the Not sure how common this pattern is for others, it works like SFINAE, overloads are enabled depending on the template parameters to the |
Looking at primer output: I think
Not sure why
Other errors look to be mostly good. |
This solution appears to depend on methods/classmethods following the convention of naming the first parameter As soon as you stop relying on the parameter name you can no longer write a |
class _Function(Protocol[_P, _R]): # type: ignore[misc] # pyright: ignore reportInvalidTypeVarUse | ||
def __call__(self, *args: _P.args, **kwds: _P.kwargs) -> _R: ... | ||
|
||
class _Method(Protocol[_T, _P, _R]): # type: ignore[misc] # pyright: ignore reportInvalidTypeVarUse | ||
def __call__(_self, self: _T, *args: _P.args, **kwds: _P.kwargs) -> _R: ... | ||
|
||
class _Classmethod(Protocol[_T, _P, _R]): # type: ignore[misc] # pyright: ignore reportInvalidTypeVarUse | ||
def __call__(_self, cls: type[_T], *args: _P.args, **kwds: _P.kwargs) -> _R: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think combine these and use Concatenate
instead, avoid needing to explicitly name a parameter, partially fix issue mentioned by @Daverball
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's pretty much what the closest to working earlier approach did, yes. But it still had its edge cases where it didn't work unfortunately. Maybe things are a little bit more forgiving now.
If I'm not mistaken what you're doing in addition to earlier approaches is to always accept both signatures for methods/classmethods (i.e. the one where you have to explicitly provide self
/cls
and the one where you don't), so you give up some type safety on instance.method()
vs. Cls.method()
since it would not be able to detect that you're missing a required parameter.
That might be a reasonable trade-off for the overall better type safety, although I fear that language servers will not know what to do with these overloads, so instead of no parameter hints you may get confusing/difficult to read hints, which could be seen as a regression in ergonomics.
I'm hoping that shouldn't be a problem because overloads are only usable if it's possible to substitute in all parameters and if Thankyou for the feedback. |
That wouldn't be the case for metaclasses or instances of classes that define a It might be worth just reducing this to the core of your idea and use |
lru_cache
lru_cache
using overload (not ready to merge)
Edit: broke something...
I've also been doing some work to refine the descriptor approach on another branch, that is probably more robust from a typing perspective. Will create another PR to run primer for comparison (apologies for the PR noise, it's all well intentioned if a bit rushed sometimes). I've created #13043 for comparison |
This comment has been minimized.
This comment has been minimized.
323bc58
to
03e550f
Compare
Diff from mypy_primer, showing the effect of this PR on open source code: dacite (https://github.com/konradhalas/dacite)
+ dacite/types.py:19: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], type[Any]]"; expected "Never" [arg-type]
+ dacite/types.py:27: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:29: error: "Never" not callable [misc]
+ dacite/types.py:32: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[T] | type[None]], T]"; expected "Never" [arg-type]
+ dacite/types.py:34: error: "Never" not callable [misc]
+ dacite/types.py:41: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:46: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:48: error: "Never" not callable [misc]
+ dacite/types.py:59: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:61: error: "Never" not callable [misc]
+ dacite/types.py:64: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:69: error: "Never" not callable [misc]
+ dacite/types.py:74: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:79: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], type[Any]]"; expected "Never" [arg-type]
+ dacite/types.py:84: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:89: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], type[Any] | Any]"; expected "Never" [arg-type]
+ dacite/types.py:106: error: "Never" not callable [misc]
+ dacite/types.py:107: error: "Never" not callable [misc]
+ dacite/types.py:108: error: "Never" not callable [misc]
+ dacite/types.py:109: error: "Never" not callable [misc]
+ dacite/types.py:112: error: "Never" not callable [misc]
+ dacite/types.py:114: error: "Never" not callable [misc]
+ dacite/types.py:115: error: "Never" not callable [misc]
+ dacite/types.py:125: error: "Never" not callable [misc]
+ dacite/types.py:130: error: "Never" not callable [misc]
+ dacite/types.py:131: error: "Never" not callable [misc]
+ dacite/types.py:132: error: "Never" not callable [misc]
+ dacite/types.py:133: error: "Never" not callable [misc]
+ dacite/types.py:134: error: "Never" not callable [misc]
+ dacite/types.py:135: error: "Never" not callable [misc]
+ dacite/types.py:136: error: "Never" not callable [misc]
+ dacite/types.py:137: error: "Never" not callable [misc]
+ dacite/types.py:138: error: "Never" not callable [misc]
+ dacite/types.py:143: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:145: error: "Never" not callable [misc]
+ dacite/types.py:147: error: "Never" not callable [misc]
+ dacite/types.py:154: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any], tuple[Any, ...]], tuple[Any, ...]]"; expected "Never" [arg-type]
+ dacite/types.py:166: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any], type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/types.py:168: error: "Never" not callable [misc]
+ dacite/types.py:169: error: "Never" not callable [misc]
+ dacite/types.py:176: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[Any]], bool]"; expected "Never" [arg-type]
+ dacite/exceptions.py:6: error: "Never" not callable [misc]
+ dacite/dataclasses.py:19: error: "Never" not callable [misc]
+ dacite/dataclasses.py:24: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[T]], list[Field[Any]]]"; expected "Never" [arg-type]
+ dacite/dataclasses.py:30: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[type[T]], bool]"; expected "Never" [arg-type]
+ dacite/core.py:51: error: "Never" not callable [misc]
+ dacite/core.py:51: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Callable[[object | Callable[..., Any] | FunctionType | BuiltinFunctionType | MethodType | Module | WrapperDescriptorType | MethodWrapperType | MethodDescriptorType, dict[str, Any] | None, Mapping[str, Any] | None, bool], dict[str, Any]]"; expected "Never" [arg-type]
+ dacite/core.py:54: error: "Never" not callable [misc]
+ dacite/core.py:79: error: "Never" not callable [misc]
+ dacite/core.py:88: error: "Never" not callable [misc]
+ dacite/core.py:89: error: "Never" not callable [misc]
+ dacite/core.py:92: error: "Never" not callable [misc]
+ dacite/core.py:94: error: "Never" not callable [misc]
+ dacite/core.py:96: error: "Never" not callable [misc]
+ dacite/core.py:98: error: "Never" not callable [misc]
+ dacite/core.py:98: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type overloaded function; expected "Never" [arg-type]
+ dacite/core.py:101: error: "Never" not callable [misc]
+ dacite/core.py:102: error: "Never" not callable [misc]
+ dacite/core.py:103: error: "Never" not callable [misc]
+ dacite/core.py:111: error: "Never" not callable [misc]
+ dacite/core.py:112: error: "Never" not callable [misc]
+ dacite/core.py:140: error: "Never" not callable [misc]
+ dacite/core.py:141: error: "Never" not callable [misc]
+ dacite/core.py:143: error: "Never" not callable [misc]
+ dacite/core.py:146: error: "Never" not callable [misc]
+ dacite/core.py:152: error: "Never" not callable [misc]
+ dacite/core.py:153: error: "Never" not callable [misc]
prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/settings/legacy.py:105: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[PrefectBaseSettings]"; expected "Hashable" [arg-type]
- src/prefect/settings/legacy.py:105: note: Following member(s) of "PrefectBaseSettings" have conflicts:
- src/prefect/settings/legacy.py:105: note: Expected:
- src/prefect/settings/legacy.py:105: note: def __hash__() -> int
- src/prefect/settings/legacy.py:105: note: Got:
- src/prefect/settings/legacy.py:105: note: def __hash__(self: object) -> int
- src/prefect/settings/legacy.py:105: note: Expected:
- src/prefect/settings/legacy.py:105: note: def __hash__() -> int
- src/prefect/settings/legacy.py:105: note: Got:
- src/prefect/settings/legacy.py:105: note: def __hash__(self: object) -> int
- src/prefect/settings/legacy.py:136: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[PrefectBaseSettings]"; expected "Hashable" [arg-type]
- src/prefect/settings/legacy.py:136: note: Following member(s) of "PrefectBaseSettings" have conflicts:
- src/prefect/settings/legacy.py:136: note: Expected:
- src/prefect/settings/legacy.py:136: note: def __hash__() -> int
- src/prefect/settings/legacy.py:136: note: Got:
- src/prefect/settings/legacy.py:136: note: def __hash__(self: object) -> int
- src/prefect/settings/legacy.py:136: note: Expected:
- src/prefect/settings/legacy.py:136: note: def __hash__() -> int
- src/prefect/settings/legacy.py:136: note: Got:
- src/prefect/settings/legacy.py:136: note: def __hash__(self: object) -> int
psycopg (https://github.com/psycopg/psycopg)
+ psycopg/psycopg/rows.py:143: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "*Generator[bytes | None, None, None]"; expected "bytes" [arg-type]
+ psycopg/psycopg/types/enum.py:153: error: Need type annotation for "loader" [var-annotated]
+ psycopg/psycopg/types/enum.py:153: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "str"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:153: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[E]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:153: error: Argument 3 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[tuple[bytes, E], ...]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:156: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "str"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:156: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[E]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:156: error: Argument 3 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[tuple[bytes, E], ...]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:161: error: Need type annotation for "dumper" [var-annotated]
+ psycopg/psycopg/types/enum.py:161: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[E]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:161: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "int"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:161: error: Argument 3 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[tuple[E, bytes], ...]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:164: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[E]"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:164: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "int"; expected "Never" [arg-type]
+ psycopg/psycopg/types/enum.py:164: error: Argument 3 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[tuple[E, bytes], ...]"; expected "Never" [arg-type]
ibis (https://github.com/ibis-project/ibis)
+ ibis/backends/tests/test_temporal.py:2162: error: Argument "exclude" to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[str, str]"; expected "tuple[str]" [arg-type]
+ ibis/backends/tests/test_temporal.py:2180: error: Argument "exclude" to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[str, str, str, str, str, str]"; expected "tuple[str]" [arg-type]
pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/dtypes/cast.py:591: error: Unused "type: ignore" comment [unused-ignore]
+ pandas/core/apply.py:1004: error: Unused "type: ignore" comment [unused-ignore]
twine (https://github.com/pypa/twine)
- Warning: unused section(s) in mypy.ini: [mypy-tests.*]
+ twine/auth.py:93: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
+ https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
+ Please report a bug at https://github.com/python/mypy/issues
+ version: 1.13.0
+ twine/auth.py:93: : note: use --pdb to drop into pdb
+ twine/auth.py:93: error: Invalid self argument "Resolver" to attribute function "username" with type "Callable[[VarArg(Never), KwArg(Never)], Never]" [misc]
+ Traceback (most recent call last):
+ File "mypy/checkexpr.py", line 5848, in accept
+ File "mypy/nodes.py", line 1893, in accept
+ File "mypy/checkexpr.py", line 3269, in visit_member_expr
+ File "mypy/checkexpr.py", line 3292, in analyze_ordinary_member_access
+ File "mypy/checkmember.py", line 206, in analyze_member_access
+ File "mypy/checkmember.py", line 225, in _analyze_member_access
+ File "mypy/checkmember.py", line 353, in analyze_instance_member_access
+ File "mypy/checkmember.py", line 532, in analyze_member_var_access
+ File "mypy/checkmember.py", line 818, in analyze_var
+ AssertionError:
jinja (https://github.com/pallets/jinja)
+ src/jinja2/environment.py:1204: error: Unused "type: ignore" comment [unused-ignore]
jax (https://github.com/google/jax)
+ jax/_src/dtypes.py:366: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/dtypes.py:367: error: Unused "type: ignore" comment [unused-ignore]
mkdocs (https://github.com/mkdocs/mkdocs)
+ mkdocs/tests/plugin_tests.py:137: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[_DummyPluginConfig]"; expected "type[Never]" [arg-type]
mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/utils/asyncio_utils.py:62: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Any | str"; expected "tuple[Any, ...] | None" [arg-type]
+ mitmproxy/tools/console/common.py:811: error: Argument "error_message" to "__call__" of "_lru_cache_wrapper" has incompatible type "str | None"; expected "str" [arg-type]
+ mitmproxy/tools/console/common.py:848: error: Incompatible types in assignment (expression has type "_lru_cache_wrapper[Callable[[NamedArg(RenderMode, 'render_mode'), NamedArg(bool, 'focused'), NamedArg(str, 'marked'), NamedArg(str | None, 'is_replay'), NamedArg(str, 'request_method'), NamedArg(str, 'request_scheme'), NamedArg(str, 'request_host'), NamedArg(str, 'request_path'), NamedArg(str, 'request_url'), NamedArg(str, 'request_http_version'), NamedArg(float, 'request_timestamp'), NamedArg(bool, 'request_is_push_promise'), NamedArg(bool, 'intercepted'), NamedArg(int | None, 'response_code'), NamedArg(str | None, 'response_reason'), NamedArg(int | None, 'response_content_length'), NamedArg(str | None, 'response_content_type'), NamedArg(float | None, 'duration'), NamedArg(str | None, 'error_message')], Any]]", variable has type "_lru_cache_wrapper[Callable[[NamedArg(RenderMode, 'render_mode'), NamedArg(bool, 'focused'), NamedArg(str, 'marked'), NamedArg(bool, 'is_replay'), NamedArg(str, 'request_method'), NamedArg(str, 'request_scheme'), NamedArg(str, 'request_host'), NamedArg(str, 'request_path'), NamedArg(str, 'request_url'), NamedArg(str, 'request_http_version'), NamedArg(float, 'request_timestamp'), NamedArg(bool, 'request_is_push_promise'), NamedArg(bool, 'intercepted'), NamedArg(int | None, 'response_code'), NamedArg(str | None, 'response_reason'), NamedArg(int | None, 'response_content_length'), NamedArg(str | None, 'response_content_type'), NamedArg(float | None, 'duration'), NamedArg(str | None, 'error_message')], Any]]") [assignment]
+ mitmproxy/tools/console/common.py:853: error: Argument "is_replay" to "__call__" of "_lru_cache_wrapper" has incompatible type "str | None"; expected "bool" [arg-type]
+ mitmproxy/addons/clientplayback.py:98: error: Need type annotation for "mode" [var-annotated]
+ mitmproxy/master.py:135: error: Need type annotation for "mode" [var-annotated]
rich (https://github.com/Textualize/rich)
+ rich/progress_bar.py:145: error: Argument 3 to "__call__" of "_lru_cache_wrapper" has incompatible type "str | None"; expected "str" [arg-type]
schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/stateful/state_machine.py: note: In class "APIStateMachine":
+ src/schemathesis/stateful/state_machine.py:68: error: Signature of "_to_test_case" incompatible with supertype "RuleBasedStateMachine" [override]
+ src/schemathesis/stateful/state_machine.py:68: note: Superclass:
+ src/schemathesis/stateful/state_machine.py:68: note: _lru_cache_wrapper[Callable[[Type[RuleBasedStateMachine]], Any]]
+ src/schemathesis/stateful/state_machine.py:68: note: Subclass:
+ src/schemathesis/stateful/state_machine.py:68: note: _lru_cache_wrapper[Callable[[Type[APIStateMachine]], type]]
+ src/schemathesis/specs/openapi/stateful/__init__.py: note: In function "create_state_machine":
+ src/schemathesis/specs/openapi/stateful/__init__.py:79: error: Argument 2 to "__call__" of "_lru_cache_wrapper" has incompatible type "Tuple[Any, ...]"; expected "Iterator[str]" [arg-type]
+ src/schemathesis/specs/openapi/stateful/__init__.py:79: note: "tuple" is missing following "Iterator" protocol member:
+ src/schemathesis/specs/openapi/stateful/__init__.py:79: note: __next__
+ src/schemathesis/specs/openapi/stateful/__init__.py: note: At top level:
pip (https://github.com/pypa/pip)
+ src/pip/_internal/index/package_finder.py:902: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "str | None"; expected "str" [arg-type]
pydantic (https://github.com/pydantic/pydantic)
+ pydantic/v1/tools.py:37: error: Unused "type: ignore" comment [unused-ignore]
- pydantic/networks.py:107: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[_BaseUrl]"; expected "Hashable" [arg-type]
- pydantic/networks.py:107: note: Following member(s) of "_BaseUrl" have conflicts:
- pydantic/networks.py:107: note: Expected:
- pydantic/networks.py:107: note: def __hash__() -> int
- pydantic/networks.py:107: note: Got:
- pydantic/networks.py:107: note: def __hash__(self: object) -> int
- pydantic/networks.py:291: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "type[_BaseMultiHostUrl]"; expected "Hashable" [arg-type]
- pydantic/networks.py:291: note: Following member(s) of "_BaseMultiHostUrl" have conflicts:
- pydantic/networks.py:291: note: Expected:
- pydantic/networks.py:291: note: def __hash__() -> int
- pydantic/networks.py:291: note: Got:
- pydantic/networks.py:291: note: def __hash__(self: object) -> int
core (https://github.com/home-assistant/core)
+ homeassistant/util/unit_conversion.py:387: error: Signature of "converter_factory" incompatible with supertype "BaseUnitConverter" [override]
+ homeassistant/util/unit_conversion.py:387: note: Superclass:
+ homeassistant/util/unit_conversion.py:387: note: _lru_cache_wrapper[Callable[[type[BaseUnitConverter], str | None, str | None], Callable[[float], float]]]
+ homeassistant/util/unit_conversion.py:387: note: Subclass:
+ homeassistant/util/unit_conversion.py:387: note: _lru_cache_wrapper[Callable[[type[SpeedConverter], str | None, str | None], Callable[[float], float]]]
+ homeassistant/util/unit_conversion.py:401: error: Signature of "converter_factory_allow_none" incompatible with supertype "BaseUnitConverter" [override]
+ homeassistant/util/unit_conversion.py:401: note: Superclass:
+ homeassistant/util/unit_conversion.py:401: note: _lru_cache_wrapper[Callable[[type[BaseUnitConverter], str | None, str | None], Callable[[float | None], float | None]]]
+ homeassistant/util/unit_conversion.py:401: note: Subclass:
+ homeassistant/util/unit_conversion.py:401: note: _lru_cache_wrapper[Callable[[type[SpeedConverter], str | None, str | None], Callable[[float | None], float | None]]]
+ homeassistant/util/unit_conversion.py:467: error: Signature of "converter_factory" incompatible with supertype "BaseUnitConverter" [override]
+ homeassistant/util/unit_conversion.py:467: note: Superclass:
+ homeassistant/util/unit_conversion.py:467: note: _lru_cache_wrapper[Callable[[type[BaseUnitConverter], str | None, str | None], Callable[[float], float]]]
+ homeassistant/util/unit_conversion.py:467: note: Subclass:
+ homeassistant/util/unit_conversion.py:467: note: _lru_cache_wrapper[Callable[[type[TemperatureConverter], str | None, str | None], Callable[[float], float]]]
+ homeassistant/util/unit_conversion.py:481: error: Signature of "converter_factory_allow_none" incompatible with supertype "BaseUnitConverter" [override]
+ homeassistant/util/unit_conversion.py:481: note: Superclass:
+ homeassistant/util/unit_conversion.py:481: note: _lru_cache_wrapper[Callable[[type[BaseUnitConverter], str | None, str | None], Callable[[float | None], float | None]]]
+ homeassistant/util/unit_conversion.py:481: note: Subclass:
+ homeassistant/util/unit_conversion.py:481: note: _lru_cache_wrapper[Callable[[type[TemperatureConverter], str | None, str | None], Callable[[float | None], float | None]]]
+ homeassistant/core.py:1511: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "EventType[_DataT] | str"; expected "Never" [arg-type]
+ homeassistant/core.py:1529: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "EventType[_DataT] | str"; expected "Never" [arg-type]
+ homeassistant/auth/__init__.py:655: error: Invalid self argument "_lru_cache_wrapper[partial[dict[str, Any]]]" to attribute function "__call__" with type "Callable[[_lru_cache_wrapper[_Method[_T, _P, _R]], **_P], _R]" [misc]
+ homeassistant/components/xiaomi_aqara/config_flow.py:216: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "str | None"; expected "str" [arg-type]
+ homeassistant/helpers/llm.py:408: error: Invalid self argument "_lru_cache_wrapper[partial[str]]" to attribute function "__call__" with type "Callable[[_lru_cache_wrapper[_Method[_T, _P, _R]], **_P], _R]" [misc]
+ homeassistant/components/mqtt_room/sensor.py:199: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "Any | None"; expected "str" [arg-type]
+ homeassistant/components/esphome/update.py:63: error: "Never" has no attribute "get_entry_data" [attr-defined]
+ homeassistant/components/esphome/light.py:178: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:187: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:198: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:207: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:208: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:213: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:225: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:242: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:247: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:261: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/light.py:342: error: Argument 1 to "__call__" of "_lru_cache_wrapper" has incompatible type "tuple[int, ...]"; expected "list[int]" [arg-type]
+ homeassistant/components/esphome/__init__.py:61: error: Need type annotation for "domain_data" [var-annotated]
+ homeassistant/components/esphome/__init__.py:89: error: "Never" has no attribute "get_or_create_store" [attr-defined]
|
lru_cache
using overload (not ready to merge)lru_cache
using overloads (not ready to merge)
Undecided if this is a good way to go, but marked as for review to see what others say. I've added some notes on output of
mypy_primer
at the end, there are a couple of unexpected errors but mostly good.Change
lru_cache
callable signature to useParamSpec
. This has previously been tried unsuccessfully (#11662) due to compatibility with theclassmethod
decorator. I've attempted to solve that compatibility by using overloads that do/don't include the necessarycls
andself
parameter when it appearrs that a method/classmethod is being cached.This removes the
Hashable
constraint on parameters.Instead, this uses the function signatures (almost) correctly (methods and class methods have 2 overloads, one with and without
cls
andself
, but I think this would be less error prone than currently, could possibly be refined).As a trivial example, the below type checks correctly
There is a more comprehensive example that I've been using to test in #12952 which (with 2 minor exceptions) type checks perfectly.