python / python/mypy

Can't match a TypedDict with a Protocol

Abierto
#17,074 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

bug
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug Report

I was trying to use a Protocol to fish out the value type from a TypedDict type corresponding to a key Literal passed to a function, so I could bind it to a TypeVar. That didn't work, but in trying to debug that I noticed that it's just straight up not possible to get a TypedDict to match a simple Protocol that we can see at type-checking time it does in fact match.

To Reproduce

See https://mypy-play.net/?mypy=latest&python=3.12&gist=928611fe3fcf77630451b8ca6b26dfca

from typing import Literal, TypedDict, Protocol, Optional

class Foo(TypedDict):
    bar: int

concrete_var: Foo = Foo(bar=5)

# This typechecks (though it has to be optional for some reason even if the key
# is Required in the TypedDict):
int_var: Optional[int] = concrete_var.get("bar")

class Gettable(Protocol):
    def get(self, key: Literal["bar"]) -> Optional[int]: ...

# But we don't use that to know that the protocol matches. This fails:
test_var: Gettable = concrete_var 

Actual Behavior

main.py:16: error: Incompatible types in assignment (expression has type "Foo", variable has type "Gettable")  [assignment]
main.py:16: note: Following member(s) of "Foo" have conflicts:
main.py:16: note:     Expected:
main.py:16: note:         def get(self, key: Literal['bar']) -> int | None
main.py:16: note:     Got:
main.py:16: note:         @overload
main.py:16: note:         def get(self, str, /) -> object
main.py:16: note:         @overload
main.py:16: note:         def [_T] get(self, str, /, default: object) -> object
Found 1 error in 1 file (checked 1 source file)

MyPy appears to have forgotten everything it ever knew about the types of the things in the TypedDict when it tries to match the get() method to the protocol.

Your Environment

  • Mypy version used: 1.9.0
  • Python version used: 3.10 and 3.12

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

Empieza ejecutando la reproducción enlazada de mypy-play con las definiciones de TypedDict y Protocol proporcionadas. Rastrea cómo se comparan TypedDict get overloads con Protocol methods; se considera terminado cuando la asignación indicada se acepta correctamente y existe cobertura de regresión en el área de pruebas existente pertinente.

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

Evaluación

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

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.