python / python/mypy

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

Offen
#10,470 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug topic-overloads
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginnen Sie damit, die Reproduktion in test.py mit mypy 0.812 auszuführen und die revealed types für die Fälle named-tuple und overloaded-function zu vergleichen. Verfolgen Sie die Overload-Auflösung und die Behandlung von named-tuple-Typen. Überprüfen Sie anschließend, dass die betroffenen reveals in ihre erwarteten callable-Typen statt in Any aufgelöst werden.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.