python / python/mypy

Type narrowing on TypedDict with match expresion produces an unexpected error

Aperta
#16,834 3 commenti 2 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Bug Report

When you try to narrow down the type of a TypedDict by checking with a match expression, it produces an error when it shouldn't. But when you try an equivalent code but instead of using match, using if/else it works as expected.

To Reproduce

from typing import TypedDict, Literal, Union

class EmptyTaskPayload(TypedDict):
    pass

class CheckPendingTaskSystemRebootResponse(TypedDict):
    type: Literal["SYSTEM/REBOOT"]
    payload: EmptyTaskPayload
    
class SystemVersionTaskPayload(TypedDict):
    version: str
    
class CheckPendingTaskSystemVersionResponse(TypedDict):
    type: Literal["SYSTEM/VERSION"]
    payload: SystemVersionTaskPayload

CheckPendingTaskResponse = Union[
    CheckPendingTaskSystemRebootResponse,
    CheckPendingTaskSystemVersionResponse
]

def test_match(pending_task: CheckPendingTaskResponse) -> None:
    match pending_task["type"]:
        case "SYSTEM/REBOOT":
            pass
        case "SYSTEM/VERSION":
            payload = pending_task["payload"]
            version = payload["version"]
#                                      ^ Error produced here
# main.py:28: error: TypedDict "EmptyTaskPayload" has no key "version"  [typeddict-item]

def test_if(pending_task: CheckPendingTaskResponse) -> None:
    if pending_task["type"] == "SYSTEM/REBOOT":
        pass
    elif pending_task["type"] == "SYSTEM/VERSION":
        payload = pending_task["payload"]
        version = payload["version"]

Code with inlay hints
Error given in the local editor
Playground and Gist

Expected Behavior

Expected the code to be absent of errors since it's correct.

Actual Behavior

Produces an error in the index of payload with the key "version" saying that the other type (EmptyTaskPayload) does not have that key. Which is strange as the type system givs payload the correct type (SystemVersionTaskPayload) and in the alternative version with if/else it works.

Your Environment

  • Mypy version used: 1.8.0
  • Python version used: 3.10.12

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Esegui la riproduzione TypedDict fornita con la versione di mypy indicata, confrontando i casi match e if/else. Traccia il comportamento del restringimento dei tipi basato su match e aggiungi un test di regressione per l'esempio; il lavoro è completato quando il ramo match restringe payload a SystemVersionTaskPayload senza un TypedDict key error.

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
38/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.