Bug Report
Mypy does not exclude types from earlier match cases in subsequent cases. This makes it difficult to work with values that could match multiple cases.
I'm specifically running into this when trying to handle types from the OpenAI and Anthropic Python SDKs. The type annotations in those libraries frequently have patterns like content: Union[str, Iterable[ContentArrayOfContentPart], None]. Applying a match/case statement to the content causes issues in the case Iterable(): case, because Mypy thinks that the value could still be a string (even though that was handled in a previous case).
To Reproduce
Playground URL
import random
from collections.abc import Iterable
from typing import assert_never
x: str | list[int]
if random.random() < 0.5:
x = "a"
else:
x = [1, 2, 3]
match x:
case str():
reveal_type(x)
case Iterable():
reveal_type(x)
case _:
assert_never(x)
Expected Behavior
I would expect Mypy to show a revealed type of only builtins.list[builtins.int] for x on line 17, like:
main.py:15: note: Revealed type is "builtins.str"
main.py:17: note: Revealed type is "builtins.list[builtins.int]"
Success: no issues found in 1 source file
Actual Behavior
Even though a string would never make it to the second case, x on line 17 is still considered to possibly be a string:
main.py:15: note: Revealed type is "builtins.str"
main.py:17: note: Revealed type is "builtins.str | builtins.list[builtins.int]"
Success: no issues found in 1 source file
Your Environment
- Mypy version used: 1.18.2
- Mypy command-line flags: N/A
- Mypy configuration options from
mypy.ini (and other config files): N/A
- Python version used: 3.12
Bug Report
Mypy does not exclude types from earlier match cases in subsequent cases. This makes it difficult to work with values that could match multiple cases.
I'm specifically running into this when trying to handle types from the OpenAI and Anthropic Python SDKs. The type annotations in those libraries frequently have patterns like
content: Union[str, Iterable[ContentArrayOfContentPart], None]. Applying amatch/casestatement to thecontentcauses issues in thecase Iterable():case, because Mypy thinks that the value could still be a string (even though that was handled in a previous case).To Reproduce
Playground URL
Expected Behavior
I would expect Mypy to show a revealed type of only
builtins.list[builtins.int]forxon line 17, like:Actual Behavior
Even though a string would never make it to the second case,
xon line 17 is still considered to possibly be a string:Your Environment
mypy.ini(and other config files): N/A