python / python/mypy

`@overload` breaks with named tuple and some overloaded functions

Aperta
#10,470 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug topic-overloads
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Bug Report

Mypy incorrectly reports Any as the resolved type (quite possibly due this https://github.com/python/typing/issues/253#issuecomment-235358878 )

To Reproduce

from collections import namedtuple
from typing import Any, Callable, cast, Dict, List, NamedTuple, overload, TypeVar, Union

F = TypeVar("F", bound=Callable[..., Any])
Arg: NamedTuple = namedtuple("Arg", ["arg"])


class Test:
    @overload
    def __call__(self, fn: F) -> F:
        ...

    @overload
    def __call__(self, *args: Any, **kwargs: Any) -> "Test":
        ...

    def __call__(self, *args: Any, **kwargs: Any) -> Union[F, "Test"]:
        if len(args) == 1:
            return cast(F, args[0])

        return self

reveal_type(Test()(Test))



def broken(arg: Arg) -> Arg:
    return arg

reveal_type(broken)
reveal_type(Test()(broken))



def working(arg: int) -> int:
    return arg

reveal_type(Test()(working))



@overload
def overloaded_broken(arg: F) -> F:
    ...

@overload
def overloaded_broken(*args: Any, **kwargs: Any) -> Dict[str, int]:
    ...

def overloaded_broken(*args: Any, **kwargs: Any) -> Union[F, Dict[str, int]]:
    if len(args) == 1:
        return cast(F, args[0])

    return dict(args=len(args), kwargs=len(kwargs))


reveal_type(overloaded_broken)
reveal_type(Test()(overloaded_broken))


@overload
def overloaded_working(arg: str) -> str:
    ...

@overload
def overloaded_working(arg: bytes) -> bytes:
    ...

def overloaded_working(arg: Union[bytes, str]) -> Union[bytes, str]:
    return arg


reveal_type(Test()(overloaded_working))

Expected Behavior

All revealed types are printed as non Any

Actual Behavior

# a class is OK
test.py:23:13: note: Revealed type is 'def () -> test.Test'

# this is what is expected when using a named tuple, but it resolves as any
test.py:30:13: note: Revealed type is 'def (arg: Tuple[Any, fallback=test.Arg]) -> Tuple[Any, fallback=test.Arg]'
test.py:31:13: note: Revealed type is 'Any'

# this is not using a named tuple and it works as expected
test.py:38:13: note: Revealed type is 'def (arg: builtins.int) -> builtins.int'

# this is what is expected for a complex overloaded function, but it resolves as any
test.py:57:13: note: Revealed type is 'Overload(def [F <: def (*Any, **Any) -> Any] (arg: F`-1) -> F`-1, def (*args: Any, **kwargs: Any) -> builtins.dict[builtins.str, builtins.int])'
test.py:58:13: note: Revealed type is 'Any'

# passing a simpler overloaded function
test.py:73:13: note: Revealed type is 'Overload(def (arg: builtins.str) -> builtins.str, def (arg: builtins.bytes) -> builtins.bytes)'

Your Environment

mypy --version: mypy 0.812 (default config)
python --version: Python 3.8.9

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia eseguendo la riproduzione in test.py con mypy 0.812 e confronta i revealed types per i casi named-tuple e overloaded-function. Traccia la risoluzione degli overload e la gestione dei tipi named-tuple, quindi verifica che i reveals interessati vengano risolti nei rispettivi tipi callable attesi invece che in Any.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
compilers
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.