Irregularities in populating new dict from a source dict with a narrower key type
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Python
- Estrellas
- 20.6k
- Forks
- 3.3k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
Bug Report
When creating or updating a new dict with items from another dict with a narrower key type, Mypy complains about some methods which are actually perfectly valid.
To Reproduce
from typing import TypeVar
_KT = TypeVar("_KT")
_VT = TypeVar("_VT")
def clone_dict(source_dict: dict[_KT, _VT]) -> dict[_KT, _VT]:
return dict(source_dict)
def test(source_dict: dict[str, None]) -> list[dict[str | int, None]]:
a: dict[str | int, None] = {"a": None, "b": None}
b: dict[str | int, None] = {k: v for k, v in source_dict.items()}
c: dict[str | int, None] = {k: None for k in source_dict.keys()}
d: dict[str | int, None] = {**source_dict}
e: dict[str | int, None] = dict(source_dict.items())
f: dict[str | int, None] = dict(source_dict)
g: dict[str | int, None] = source_dict.copy()
h: dict[str | int, None] = clone_dict(source_dict)
i: dict[str | int, None] = {}
i.update(source_dict.items())
j: dict[str | int, None] = {}
j.update(source_dict)
return [a, b, c, d, e, f, g, h, i, j]
Expected Behavior
The above code shows 10 ways of creating the new dictionary:
adoesn't actually clone the source dict; it just creates a new dict from a dict literal that just happens to only contain string keysbcopies the source dict using a dict comprehension and.items()cuses a dict comprehension and.keys()(possible in this case because the dict value type isNone, which is a singleton)duses a dict comprehension and star-star-expansioneuses thedict()constructor and.items()fuses thedict()constructor and the source dict directlyguses the built-in.copy()methodhuses a user-created dict copying methodicreates an empty dict and then.update()s it using.items()jcreates an empty dict and then.update()s it using the source dict directly
Of these:
- Mypy should complain about
h; Mypy has no way of knowing that the function in question is returning a fresh dict which is used nowhere else (and thus can safely be implicitly cast to a wider type) - Mypy might complain about
g; since that is a built-in method, it could be special-cased into Mypy that this is safe, but absent such a special case it would have the same semantics asclone_dict() - All the other option are safe and should not raise any error
Actual Behavior
Mypy correctly warns about g and h, but also issues spurious warnings about d, f, and j:
$ mypy test.py
test.py:15: error: Unpacked dict entry 0 has incompatible type "dict[str, None]"; expected "SupportsKeysAndGetItem[str | int, None]" [dict-item]
test.py:17: error: Incompatible types in assignment (expression has type "dict[str, None]", variable has type "dict[str | int, None]") [assignment]
test.py:18: error: Incompatible types in assignment (expression has type "dict[str, None]", variable has type "dict[str | int, None]") [assignment]
test.py:19: error: Argument 1 to "clone_dict" has incompatible type "dict[str, None]"; expected "dict[str | int, None]" [arg-type]
test.py:23: error: Argument 1 to "update" of "MutableMapping" has incompatible type "dict[str, None]"; expected "SupportsKeysAndGetItem[str | int, None]" [arg-type]
Found 5 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used:
mypy 1.5.1 (compiled: yes) - Mypy command-line flags: None
- Mypy configuration options from
mypy.ini(and other config files): None - Python version used:
Python 3.11.2
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Comienza ejecutando el reproductor proporcionado con mypy y compara los diagnósticos para el desempaquetado de dict, el constructor de dict y update(). Sigue después las rutas de comprobación de tipos para esas operaciones y confirma que los casos seguros ya no informan de errores, mientras que los casos con clone_dict() y copy() conservan su comportamiento esperado.
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
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 45/100