Mypy does not correctly narrow indexing operations when using Literal or Final keys
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 20.6k
- Forks
- 3.3k
- Métriques de merge des PR
- Métriques de PR en attente
Description
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.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par la reproduction dans l’issue, puis examinez mypy/literals.py autour de literal() et mypy/checker.py autour de la logique de narrowing à la ligne 3775. Suivez pourquoi un NameExpr pour KEY produit LITERAL_NO et comparez-le avec l’index de chaîne direct. C’est terminé lorsque le cas KEY réduit d[KEY] à Literal[Key.X] de manière cohérente avec d["key"].
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- devtools
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 48/100