Generic Callable return type inferred as first overload from overloaded function
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 20.6k
- Fork
- 3.3k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
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!
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia eseguendo il reproducer mypy-play collegato e confronta il caso Callable[..., T] con il workaround whole-Callable. Leggi il percorso di inferenza generica di Callable relativo alla dichiarazione di _T di functools.cache, quindi aggiungi test che mostrino che le chiamate sovraccariche non usano silenziosamente il primo overload, ma producono uno dei risultati attesi.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- compilers, tooling
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 48/100