-
-
Notifications
You must be signed in to change notification settings - Fork 62
Description
Synopsys
beartype.door.is_bearable
cannot be used for type narrowing with mypy
or pyright
as described in the documentation, due to an incorrect type annotation.
To Reproduce
Both mypy
and pyright
show type errors with this example from the Beartype documentation:
from beartype.door import is_bearable
def narrow_types_like_a_boss_with_beartype(lst: list[int | str]):
if is_bearable(lst, list[int]):
munch_on_list_of_integers(lst)
elif is_bearable(lst, list[str]):
munch_on_list_of_strings(lst)
def munch_on_list_of_strings(lst: list[str]): ...
def munch_on_list_of_integers(lst: list[int]): ...
Result from mypy
:
$ mypy ./bug.py
bug.py:5: error: Argument 1 to "munch_on_list_of_integers" has incompatible type "Type[List[Any]]"; expected "List[int]" [arg-type]
bug.py:7: error: Argument 1 to "munch_on_list_of_strings" has incompatible type "Type[List[Any]]"; expected "List[str]" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
Result from pyright
:
$ pyright ./bug.py
[elided]/bug.py
[elided]/bug.py:5:35 - error: Argument of type "type[list[int]]" cannot be assigned to parameter "lst" of type "list[int]" in function "munch_on_list_of_integers"
"type[type]" is incompatible with "type[list[int]]" (reportGeneralTypeIssues)
[elided]/bug.py:7:34 - error: Argument of type "type[list[str]]" cannot be assigned to parameter "lst" of type "list[str]" in function "munch_on_list_of_strings"
"type[type]" is incompatible with "type[list[str]]" (reportGeneralTypeIssues)
2 errors, 0 warnings, 0 informations
Expected behavior
mypy
and pyright
should show no errors when type-checking the code.
Extra notes
The type signature of is_bearable
is as follows from the source code:
def is_bearable(
obj: object,
hint: T,
*,
conf: BeartypeConf = BEARTYPE_CONF_DEFAULT,
) -> TypeGuard[T]:
...
For example, if the user calls is_bearable(some_variable, int)
, then T
is bound as type[int]
instead of int
, since T
has to be the type of whatever argument was passed in (which was int
). Thus, static type checkers now believe that some_variable
has the type type[int]
instead of the correct int
.
This can can be fixed by a simple change to the type signature:
def is_bearable(
obj: object,
hint: type[T],
*,
conf: BeartypeConf = BEARTYPE_CONF_DEFAULT,
) -> TypeGuard[T]:
...
Now, when is_bearable(some_variable, int)
is called, T
will be assigned to int
, and so some_variable
will be correctly identified as having type int
instead of type[int]
.
Unfortunately, this change seems to break type checking on other parts of the code (namely beartype.door._cls.super.TypeHint
). I'm not sure how these other type hints should be corrected, which is why I submitted an issue instead of a PR. If anyone reviewing this issue has any guidance on how any other type annotations should be modified, I would be happy to attempt a PR again to fix this issue.