Irregularities in populating new dict from a source dict with a narrower key type
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 20.6k
- Fork
- 3.3k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
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
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia eseguendo il riproduttore fornito con mypy e confronta le diagnosi per l'unpacking di dict, il costruttore dict e update(). Traccia quindi i percorsi del controllo dei tipi per queste operazioni e conferma che i casi sicuri non segnalino più errori, mentre i casi clone_dict() e copy() mantengano il comportamento previsto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- devtools
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 45/100