python / python/mypy

Binding of Generic decorators on Union variables

Offen
#11,037 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

Bug Report

Mypy seems to bind the TypeVar of a Generic decorator incorrectly when a variable is annotated as a Union.

To Reproduce
This example is based on this untyped cython code.

from typing import Callable, Generic, Optional, TypeVar, Union, overload

F = TypeVar("F")
G = TypeVar("G")


class cache_readonly(Generic[F, G]):
    def __init__(self, func: Callable[[F], G]) -> None:
        self.func = func
        self.name = func.__name__
        self.__doc__ = getattr(func, "__doc__", None)

    @overload
    def __get__(self, obj: F, typ) -> G:
        ...

    @overload
    def __get__(self, obj: None, typ) -> "cache_readonly[F, G]":
        ...

    def __get__(self, obj: Optional[F], typ) -> Union[G, "cache_readonly[F, G]"]:
        if obj is None:
            # accessed on the class, not the instance
            return self

        # Get the cache or set a default one if needed
        cache = getattr(obj, "_cache", None)
        if cache is None:
            cache = obj._cache = {}  # type: ignore

        if self.name in cache:
            val = cache[self.name]
        else:
            val = self.func(obj)
            cache[self.name] = val
        return val

    def __set__(self, obj: F, value: G) -> None:
        raise AttributeError("Can't set attribute")


class TestA:
    @cache_readonly
    def x(self) -> str:
        return "A"


class TestB:
    @cache_readonly
    def x(self) -> str:
        return "B"


def test(obj: Union[TestA, TestB]) -> str:
    return obj.x

Expected Behavior
Mypy and pyright are happy with the code :)

Actual Behavior
mypy

test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestA"
test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestB"

Pyright doesn't complain (except for the __doc__ line).

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: -
  • Mypy configuration options from mypy.ini (and other config files): -
  • Python version used: 3.9.6
  • Operating system and version: CentOS 3.10.0-693.5.2.el7.x86_64

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

Reproduziere den Bericht mit dem test.py-Beispiel unter Verwendung von mypy 0.910 und vergleiche seine Diagnosen mit dem erwarteten Verhalten und dem pyright-Ergebnis. Erledigt ist die Aufgabe, wenn der Zugriff auf Union[TestA, TestB] keine Fehler wegen inkompatibler get-Argumente mehr erzeugt und dabei das gezeigte Dekoratorverhalten erhalten bleibt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
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.