python / python/mypy

erroneous type mismatch with `Union` and `Literal` (false positive)

Offen
#17,151 0 Kommentare 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 does not sufficiently simplify Unions and Literals before some type checks (the reproduction case uses assert_type(), but assignments and calls will also trigger the issue). The result is false positive errors.

To Reproduce

[mypy-play.net]

from __future__ import annotations
from enum import (
        Enum,
        auto,
        )
from typing import (
        Literal,
        Union,
        )
from typing_extensions import (
        assert_type,
        reveal_type,
        )

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

RedKwds = Literal['RED', 'R']
GreenKwds = Literal['GREEN', 'G']
BlueKwds = Literal['BLUE', 'B']
ColorKwds = Union[RedKwds, GreenKwds, BlueKwds]

RedSpec = Union[Literal[Color.RED], RedKwds]
GreenSpec = Union[Literal[Color.GREEN], GreenKwds]
BlueSpec = Union[Literal[Color.BLUE], BlueKwds]

ColorSpec = Union[Color, ColorKwds]             # ⎱ these are entirely
RGBSpec = Union[RedSpec, GreenSpec, BlueSpec]   # ⎰ equivalent types


rgb_spec: RGBSpec
assert_type(rgb_spec, ColorSpec)  # fails; should be silent             # L34
        # Expression is of type...
        #   Union[
        #       Union[Literal[Color.RED], Literal['RED', 'R']],
        #       Union[Literal[Color.GREEN], Literal['GREEN', 'G']],
        #       Union[Literal[Color.BLUE], Literal['BLUE', 'B']]
        #       ]
        # ... not ...
        #   Union[
        #       Color,
        #       Union[
        #           Literal['RED', 'R'],
        #           Literal['GREEN', 'G'],
        #           Literal['BLUE', 'B']
        #           ]
        #       ]
reveal_type(rgb_spec)                                                   # L50
        # Union[
        #       Literal[Color.RED], Literal['RED'], Literal['R'],
        #       Literal[Color.GREEN], Literal['GREEN'], Literal['G'],
        #       Literal[Color.BLUE], Literal['BLUE'], Literal['B']
        #       ]


# "shaking" the variable (where "shaking" is clearly a no-op) causes
# things to work as expected:
rgb_spec_shaken = (
        rgb_spec
        if isinstance(rgb_spec, Color) else
        rgb_spec
        )
assert_type(rgb_spec_shaken, ColorSpec)  # passes!
reveal_type(rgb_spec_shaken)                                            # L66
        # Union[
        #       Color,
        #       Literal['RED'], Literal['R'],
        #       Literal['GREEN'], Literal['G'],
        #       Literal['BLUE'], Literal['B']
        #       ]

Expected Behavior

The types are provably equivalent; no error should be raised.

Actual Behavior

Mypy does not sufficiently simplify the types, resulting in an erroneous "mismatch".

Your Environment

  • Mypy version used: 1.9.0, master 2024-04-22
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.8, 3.12

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

Beginne damit, die mypy-play-Reproduktion des Issues mit den gezeigten assert_type()- und reveal_type()-Fällen auszuführen, insbesondere die Zeilen 34 und 50, und untersuche dann die an diesen Prüfungen beteiligten Pfade zur Typvereinfachung und -kompatibilität. Erledigt ist die Aufgabe, wenn äquivalente Union- und Literal-Typen nicht mehr zu einer Nichtübereinstimmung führen und der angezeigte aufgelöste Typ angemessen vereinfacht ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

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

Neue Issues direkt in Ihr Postfach

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