Overloaded `__getattr__` resolves attributes to the 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
Bug Report
If __getattr__ is overloaded, all attribute accesses resolves as if they were getting __getattr__ itself. This is most obvious if you expect it to return a callable - mypy will complain that the args to the callable don't match the signatures of __getattr__. This does not happen if you call __getattr__ manually, only via regular attribute access.
To Reproduce
class A:
@overload
def __getattr__(self, name: str) -> Callable[..., Any]: ...
@overload
def __getattr__(self, name: int) -> int: ...
def __getattr__(self, name: Any) -> Any:
pass
reveal_type(A().__getattr__)
reveal_type(A().xyz)
reveal_type(A().__getattr__("xyz"))
reveal_type(A().__getattr__(1))
A().xyz(1, 2, 3)
main.py:7: error: Invalid signature "Callable[[A, int], int]" for "__getattr__" [misc]
main.py:11: note: Revealed type is "Overload(def (builtins.str) -> def (*Any, **Any) -> Any, def (builtins.int) -> builtins.int)"
main.py:12: note: Revealed type is "Overload(def (builtins.str) -> def (*Any, **Any) -> Any, def (builtins.int) -> builtins.int)"
main.py:13: note: Revealed type is "def (*Any, **Any) -> Any"
main.py:14: note: Revealed type is "builtins.int"
main.py:16: error: No overload variant of "__getattr__" of "A" matches argument types "int", "int", "int" [call-overload]
main.py:16: note: Possible overload variants:
main.py:16: note: def __getattr__(self, str, /) -> Callable[..., Any]
main.py:16: note: def __getattr__(self, int, /) -> int
The first error is expected - __getattr__ doesn't normally take ints, I'm just using them to make types clear. In practice, subclasses of str, or literals as in #8203 might make more sense, though they currently all error the same way.
This behavior is the same as accessing, but not calling, an overloaded function elsewhere.
class B:
@overload
def overloaded(self, name: str) -> Callable[..., Any]: ...
@overload
def overloaded(self, name: int) -> int: ...
def overloaded(self, name: Any) -> Any:
pass
reveal_type(B().overloaded)
main.py:26: note: Revealed type is "Overload(def (name: builtins.str) -> def (*Any, **Any) -> Any, def (name: builtins.int) -> builtins.int)"
Expected Behavior
The second revealed type, of A().xyz, should worst case resolve to Callable[..., Any] | int - i.e. when overloaded, attribute access should resolve to the union of the overloads' return values, in the same way other overloads with unknown args do.
x: str | int
reveal_type(B().overloaded(x))
main.py:29: note: Revealed type is "Union[def (*Any, **Any) -> Any, builtins.int]"
Additionally, I think it should be possible to deduce that __getattr__ gets called with a string in normal attribute access, meaning the type of the result can be narrowed, down to just Callable[..., Any] in this case.
Your Environment
Python 3.11, Mypy 1.4.1, default settings
https://mypy-play.net/?mypy=1.4.1&python=3.11&gist=0e629e0ec4d8a4a4a69f8ed979bdd04d
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 gli snippet Python forniti con mypy e confronta i tipi rivelati per un getattr sovraccaricato e per i normali metodi sovraccaricati. Traccia il percorso del controllo dei tipi per l’accesso agli attributi e la risoluzione dei sovraccarichi. Il lavoro è completato quando l’accesso ordinario restituisce il risultato del sovraccarico appropriato, idealmente ristretto per un nome di attributo di tipo string, senza l’erronea diagnostica di call-overload.
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à
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100