mypy
mypy copied to clipboard
`possibly-undefined` false positive when assigning variable for every case in match statement for all possible values
# mypy: enable-error-code=possibly-undefined
from typing import Literal
value: Literal[1, 2]
match value:
case 1:
result = 1
case 2:
result = 2
result # error: possibly-undefined
similar issue: #15958 (seems it was only fixed when using assert_never at the end)
Interesting that adding case _ kind of resolves the issue though mypy does detect that case _ code is unreachable.
# mypy: enable-error-code=possibly-undefined
from typing import Literal
value: Literal[1, 2]
match value:
case 1:
result = 1
case 2:
result = 2
case _:
# error: Statement is unreachable [unreachable]
result = 3
result
I've also met the similar issue with if isinstance checks. In the last case adding redudant else block makes the case false negative.
# mypy: enable-error-code="possibly-undefined"
class A: ...
class B: ...
# False positive: Name "new_name" may be undefined [possibly-undefined]
def test_1(obj: A | B) -> None:
if isinstance(obj, A):
new_name = "test"
elif isinstance(obj, B):
new_name = "test"
a = new_name
# + adding "else: reveal_type(obj)" somehow resolves it
def test_1b(obj: A | B) -> None:
if isinstance(obj, A):
new_name = "test"
elif isinstance(obj, B):
new_name = "test"
else:
reveal_type(obj)
a = new_name
# False positive: Name "new_name" may be undefined [possibly-undefined]
def get_obj() -> A | B: ...
def test_2() -> None:
obj = get_obj()
if isinstance(obj, A):
new_name = "test"
elif isinstance(obj, B):
new_name = "test"
a = new_name
# but adding "else: reveal_type(obj)" somehow resolves it
def test_2b() -> None:
obj = get_obj()
if isinstance(obj, A):
new_name = "test"
elif isinstance(obj, B):
new_name = "test"
else:
reveal_type(obj)
a = new_name
# Name "new_name" may be undefined [possibly-undefined]
# and it's correct
def test_3(obj: str | float) -> None:
if isinstance(obj, str):
new_name = "test"
elif isinstance(obj, float):
new_name = "test"
a = new_name
# but adding "else: reveal_type(obj)" makes it false negative
def test_3b(obj: str | float) -> None:
if isinstance(obj, str):
new_name = "test"
elif isinstance(obj, float):
new_name = "test"
else:
reveal_type(obj)
a = new_name