python / python/mypy

Mypy does not correctly narrow indexing operations when using Literal or Final keys

Abierto
#7,905 5 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

priority-2-low topic-final topic-literal-types topic-type-narrowing topic-typed-dict
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

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.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con la reproducción del issue y luego inspecciona mypy/literals.py alrededor de literal() y mypy/checker.py alrededor de la lógica de narrowing en la línea 3775. Sigue el motivo por el que un NameExpr para KEY produce LITERAL_NO y compáralo con el índice de cadena directo. Terminado cuando el caso KEY reduzca d[KEY] a Literal[Key.X] de forma consistente con d["key"].

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
devtools
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Tranquilo
Claridad
Bastante claro
Aptitud para principiantes
48/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.