8000 [Feature Request] Resuscitate `typing.TypeGuard[T]` type narrowing on `beartype.door.is_bearable()` · Issue #255 · beartype/beartype · GitHub
[go: up one dir, main page]

Skip to content
[Feature Request] Resuscitate typing.TypeGuard[T] type narrowing on beartype.door.is_bearable() #255
@alexander-c-b

Description

@alexander-c-b

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0