I noticed this behavior when investigating a similar issue in pyright.
Mypy isn't correctly narrowing tuples in some cases.
fromtyping_extensionsimportTypeIsdefis_tuple_of_strings(v: tuple[int|str, ...]) ->TypeIs[tuple[str, ...]]:
returnall(isinstance(x, str) forxinv)
deftest1(t: tuple[int]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be Never ✅ else:
reveal_type(t) # Should be tuple[int] ✅ deftest2(t: tuple[str, int]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be Never ✅ else:
reveal_type(t) # Should be tuple[str, int] ✅ deftest3(t: tuple[int|str]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be tuple[str] ✅ else:
reveal_type(t) # Should be tuple[int] or tuple[int | str] ❌ (mypy: Never)deftest4(t: tuple[int|str, int|str]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be tuple[str, str] ✅ else:
reveal_type(t) # Should be tuple[int | str, int | str] or tuple[int, int | str] | tuple[str, int] ❌ (mypy: Never)deftest5(t: tuple[int|str, ...]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be tuple[str, ...] ✅ else:
reveal_type(t) # Should be tuple[int | str, ...] ❌ (mypy: Never)deftest6(t: tuple[str, *tuple[int|str, ...], str]) ->None:
ifis_tuple_of_strings(t):
reveal_type(t) # Should be tuple[str, *tuple[str, ...], str] ❌ (mypy: tuple[str, Never, str])else:
reveal_type(t) # Should be tuple[str, *tuple[int | str, ...], str] ❌ (mypy: Never)
I noticed this behavior when investigating a similar issue in pyright.
Mypy isn't correctly narrowing tuples in some cases.