python / python/mypy

Mypy emits two conflicting results for reveal_type

Offen
#10,739 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug topic-reveal-type topic-union-types
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug Report

My colleague @ahuhn and I encountered a situation where mypy emits two different outputs for one reveal_type call:

from decimal import Decimal
from typing import Union

def f(elem: Union[int, str, Decimal]) -> None:
    if isinstance(elem, int):
        return

    for _ in range(3):
        if isinstance(elem, (Decimal, int)) and elem > 10:
            continue
        reveal_type(elem)

    return None

Running mypy emits two lines for the reveal_type call, one correct and the other incorrect. In the incorrect reveal statement, the type narrowing at the top of the function is lost:

$ mypy example.py
example.py:11: note: Revealed type is "Union[builtins.str, decimal.Decimal]"   # expected
example.py:11: note: Revealed type is "Union[builtins.int, builtins.str, decimal.Decimal]"   # wrong

Expected Behavior
Expected only one piece of output for one reveal_type, and for that output to maintain the type narrowing from the top of the function.

Your Environment

We encountered this on mypy 0.812, but it also repros on latest master (currently 416f57b) using python 3.8.6.

A variation of interest: if you add a line of code after the reveal_type, then the second reveal_type output broadens to include Any:

from decimal import Decimal
from typing import Union

def f(elem: Union[int, str, Decimal]) -> None:
    if isinstance(elem, int):
        return

    for _ in range(3):
        if isinstance(elem, (Decimal, int)) and elem > 10:
            continue
        reveal_type(elem)
        elem += 1   # new compared to the example above

    return None

mypy:

$ mypy example.py
example.py:11: note: Revealed type is "Union[builtins.str, decimal.Decimal]"  # correct
example.py:11: note: Revealed type is "Union[builtins.int, Any, builtins.str, decimal.Decimal]"  # even wider, now including Any
example.py:12: error: Unsupported operand types for + ("str" and "int")   # expected and correct
example.py:12: note: Left operand is of type "Union[str, Decimal]"
example.py:12: note: Left operand is of type "Union[int, Any, str, Decimal]"
Found 1 error in 1 file (checked 1 source file)

(In this example, it's trivial to get around the problem by removing the redundant isinstance(int) check, but in our actual code, it wasn't so straightforward.)

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 bereitgestellten Python-Reproduktionen mit mypy auszuführen, einschließlich der Variante mit elem += 1, und vergleiche die doppelten reveal_type-Ausgaben. Die Behebung ist abgeschlossen, wenn jeder reveal_type-Aufruf ein Ergebnis ausgibt, das die anfängliche Typverengung beibehält, und die zugehörigen Diagnosen der Typprüfung weiterhin korrekt sind.

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
38/100

Neue Issues direkt in Ihr Postfach

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