Generic Callable return type inferred as first overload from overloaded function
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 20.6k
- Forks
- 3.3k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Apologies in advance if this duplicates an existing issue. I reviewed a bunch, but none seemed like an exact match. #15015 and #15737 were the closest.
https://mypy-play.net/?mypy=latest&python=3.13&gist=24cbdbfe356ffc9d12b75d5960dc2c4c
from collections.abc import Callable
from typing import Any, TypeVar, overload
T = TypeVar('T')
def call(func: Callable[..., T], *args, **kwargs) -> T:
return func(*args, **kwargs)
@overload
def f(x: int) -> int:
...
@overload
def f(x: str) -> str:
...
def f(x):
return x
reveal_type(call(f, 1))
reveal_type(call(f, "a"))
Expected result: I expected that mypy would either:
- evaluate the overload for each call and reveal
intfor the first call,strfor the second; or - raise an error that
Tcan't be resolved. - (or maybe reveal
int | str? or evenAny? would prefer one of the first two though.)
Actual result: mypy silently uses the return type from the first overload, does not raise any error.
main.py:19: note: Revealed type is "int"
main.py:20: note: Revealed type is "int"
Success: no issues found in 1 source file
My actual use case is that I wanted to write:
# requires: boto3, boto3-stubs[logs]
import functools
import boto3
get_client = functools.cache(boto3.Session().client)
reveal_type(get_client('logs'))
# expected: Revealed type is "mypy_boto3_logs.client.CloudWatchLogsClient"
# actual: Revealed type is "mypy_boto3_accessanalyzer.client.AccessAnalyzerClient" if mypy-boto3-accessanalyzer is installed, "Any" otherwise
boto3.Session.client is an overloaded method. As above, mypy didn't raise any error, but just took the first overload.
The relevant declaration of functools.cache: https://github.com/python/typeshed/blob/1d3abc42077c2ea47985363a4fab387357f3aa77/stdlib/functools.pyi#L263
def cache(user_function: Callable[..., _T], /) -> _lru_cache_wrapper[_T]: ...
If the entire Callable is used (with or without ParamSpec), mypy is able to see the overloads. I don't need the other methods of _lru_cache_wrapper, so this workaround works for me:
from collections.abc import Callable
import functools
from typing import Any, TypeVar, cast
import boto3
T = TypeVar('T', bound=Callable[..., Any])
def cache(func: T) -> T:
return cast(T, functools.cache(func))
get_client = cache(boto3.Session().client)
reveal_type(get_client('logs'))
# Revealed type is "mypy_boto3_logs.client.CloudWatchLogsClient"
Thank you for maintaining mypy!
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne damit, den verknüpften mypy-play-Reproduzierer auszuführen und den Fall Callable[..., T] mit dem whole-Callable-Workaround zu vergleichen. Lies anschließend den Pfad für die generische Callable-Inferenz im Zusammenhang mit der _T-Deklaration von functools.cache und füge dann Tests hinzu, die zeigen, dass überladene Aufrufe nicht stillschweigend die erste Überladung verwenden, sondern stattdessen eines der erwarteten Ergebnisse liefern.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- compilers, tooling
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 48/100