python / python/mypy

Type narrowing on TypedDict with match expresion produces an unexpected error

Offen
#16,834 3 Kommentare 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Führen Sie die bereitgestellte TypedDict-Reproduktion mit der gemeldeten mypy-Version aus und vergleichen Sie dabei die Fälle match und if/else. Verfolgen Sie das auf match basierende Verhalten der Typeneingrenzung und fügen Sie für das Beispiel einen Regressionstest hinzu; als abgeschlossen gilt dies, wenn der match-Zweig payload auf SystemVersionTaskPayload eingrenzt, ohne einen TypedDict key error zu verursachen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.