-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
can't narrow a union of type[None] #16279
Comments
I agree this is a bug in mypy, but there were a few bugs in the sample code. Here's an updated sample that should pass type checking. import types
import typing_extensions as t
NoneType = type(None)
def type_map(cls: type[None | int | str]) -> None:
if issubclass(cls, int):
t.assert_type(cls, "type[int]")
return
else:
t.assert_type(cls, type[None | str])
if issubclass(cls, str):
t.assert_type(cls, "type[str]")
return
else:
t.assert_type(cls, type[None])
t.assert_type(cls, "type[None]")
if issubclass(cls, str):
t.assert_never(cls)
else:
t.assert_type(cls, type[None])
if cls is None:
t.assert_never(cls)
else:
t.assert_type(cls, type[None])
if issubclass(cls, type(None)):
t.assert_type(cls, type[None])
else:
t.assert_never(cls)
if issubclass(cls, NoneType):
t.assert_type(cls, type[None])
else:
t.assert_never(cls)
if issubclass(cls, types.NoneType):
t.assert_type(cls, type[None])
else:
t.assert_never(cls) Incidentally, pyright had the same bug as mypy here. It will be fixed in the next release of pyright. |
Thanks for the detailed test case. It helped me to discover three scenarios where Mypy currently fails due to different limitations: from typing import Type, Union
def f(cls: Type[Union[None, int]]) -> None:
if issubclass(cls, int):
reveal_type(cls) # note: Revealed type is "Type[builtins.int]" (right)
else:
reveal_type(cls) # note: Revealed type is "Union[Type[None], Type[builtins.int]]" (wrong) from typing import Type, Union
def f(cls: Type[Union[None, int]]) -> None:
if issubclass(cls, type(None)):
reveal_type(cls) # note: Revealed type is "Union[Type[None], Type[builtins.int]]" (wrong)
else:
reveal_type(cls) # note: Revealed type is "Union[Type[None], Type[builtins.int]]" (wrong) from typing import Type, Union
NoneType_ = type(None)
def f(cls: Type[Union[None, int]]) -> None:
if issubclass(cls, NoneType_): # error: Parameterized generics cannot be used with class or instance checks [misc] (wrong)
# error: Argument 2 to "issubclass" has incompatible type "<typing special form>"; expected "_ClassInfo" [arg-type] (wrong)
reveal_type(cls) # note: Revealed type is "Union[Type[None], Type[builtins.int]]" (wrong)
else:
reveal_type(cls) # note: Revealed type is "Union[Type[None], Type[builtins.int]]" (wrong) I provided pull request #16315. If accepted by the maintainers, these limitations should be fixed in the next Mypy release, too. |
Thanks, all! |
Fixes #16279 See my comment in the referenced issue.
Bug Report
There's something about
type[None]
that (understandably) confuses mypy and makes it start producing nonsense results.While defining a function that takes arguments of
type[None | A | B]
, mypy is able to narrow totype[None|A]
(ortype[None|B]
) but any attempt to narrow beyond that causes no change in type. This makes it impossible to produce an exhaustiveif/elif/else
that can assert_never in the else case.To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=7b278f392c623c63fd5b576c483a0e3c
Expected Behavior
I should be able to write an
elif
clause that canassert_type(cls, type[None])
.Actual Behavior
Currently there's no way to narrow a type
Union[type[None], T]
type. (That I found.)Your Environment
https://mypy-play.net
The text was updated successfully, but these errors were encountered: