Mypy does not correctly narrow indexing operations when using Literal or Final keys
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 20.6k
- Forks
- 3.3k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Consider the following program:
from typing_extensions import Literal, TypedDict
from enum import Enum
class Key(Enum):
X = 1
Y = 2
Z = 3
class MyDict(TypedDict):
key: Literal[Key.X, Key.Y]
blah: int
KEY: Literal["key"] = "key"
d: MyDict
if d["key"] is Key.X:
reveal_type(d["key"]) # note: Revealed type is 'Literal[Key.X]'
if d[KEY] is Key.X:
reveal_type(d[KEY]) # note: Revealed type is 'Literal[Key.X, Key.Y]'
Mypy is currently capable of narrowing expressions like d["key"], which we can see in the first expression.
So, it's natural to assume that mypy would be able to do the same for the second since the two programs are theoretically identical -- but we can't.
The root cause has to do with the "literal" subsystem (which is not to be confused with the Literal types subsystem) here: https://github.com/python/mypy/blob/master/mypy/literals.py#L65
The index in the second example is a NameExpr, which causes the if statement to evaluate to false and return a LITERAL_NO. This then makes the narrowing logic rule out d[KEY] as a candidate for narrowing in https://github.com/python/mypy/blob/master/mypy/checker.py#L3775.
I'm not really sure what the best way of fixing this would be. The natural solution would be to also pass along the expression type into the literal(...) function, but that seems very annoying to do. I'm also not entirely sure whether this is even a sound narrowing: I'm not very familiar with the "literals" subsystem, or how it's meant to interact with Literal types.
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit der Reproduktion im Issue und untersuche dann mypy/literals.py im Umfeld von literal() sowie mypy/checker.py im Umfeld der Narrowing-Logik bei Zeile 3775. Verfolge, warum ein NameExpr für KEY LITERAL_NO erzeugt, und vergleiche dies mit dem direkten String-Index. Fertig, wenn der KEY-Fall d[KEY] konsistent zu Literal[Key.X] verengt wird, ebenso wie d["key"].
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
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 48/100