Skip to content

Commit

Permalink
Allow typing.TypeGuard to be used in type stubs.
Browse files Browse the repository at this point in the history
For #916.

PiperOrigin-RevId: 373679585
  • Loading branch information
rchen152 committed May 13, 2021
1 parent cea2616 commit b684d03
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
14 changes: 10 additions & 4 deletions pytype/pyi/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
_TYPING_SETS = ("typing.Intersection", "typing.Optional", "typing.Union")

# Aliases for some typing.X types
_TUPLE_TYPES = ("tuple", "builtins.tuple", "typing.Tuple")
_ANNOTATED_TYPES = ("typing.Annotated", "typing_extensions.Annotated")
_CALLABLE_TYPES = ("typing.Callable", "collections.abc.Callable")
_CONCATENATE_TYPES = ("typing.Concatenate", "typing_extensions.Concatenate")
_LITERAL_TYPES = ("typing.Literal", "typing_extensions.Literal")
_ANNOTATED_TYPES = ("typing.Annotated", "typing_extensions.Annotated")
_TUPLE_TYPES = ("tuple", "builtins.tuple", "typing.Tuple")
_TYPEGUARD_TYPES = ("typing.TypeGuard", "typing_extensions.TypeGuard")


def _split_definitions(defs: List[Any]):
Expand Down Expand Up @@ -432,6 +434,10 @@ def _parameterized_type(self, base_type, parameters):
return types.pytd_literal(parameters)
elif self._matches_named_type(base_type, _ANNOTATED_TYPES):
return types.pytd_annotated(parameters)
elif self._matches_named_type(base_type, _TYPEGUARD_TYPES):
# We do not yet support PEP 647, User-Defined Type Guards. To avoid
# blocking typeshed, convert type guards to plain bools.
return pytd.NamedType("bool")
elif any(isinstance(p, types.Constant) for p in parameters):
parameters = ", ".join(
p.repr_str() if isinstance(p, types.Constant) else "_"
Expand All @@ -458,8 +464,8 @@ def _parameterized_type(self, base_type, parameters):
# To avoid blocking typeshed from adopting this PEP, we convert new
# features to Any.
if p in self.param_specs or (
isinstance(p, pytd.GenericType) and self._matches_full_name(
p, ("typing.Concatenate", "typing_extensions.Concatenate"))):
isinstance(p, pytd.GenericType) and
self._matches_full_name(p, _CONCATENATE_TYPES)):
callable_parameters.append(pytd.AnythingType())
else:
callable_parameters.append(p)
Expand Down
29 changes: 29 additions & 0 deletions pytype/pyi/parser_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2925,5 +2925,34 @@ def f(x: Callable[..., R]) -> Callable[..., R]: ...
""")


class TypeGuardTest(_ParserTestBase):

def test_typing_extensions(self):
self.check("""
from typing import List
from typing_extensions import TypeGuard
def f(x: List[object]) -> TypeGuard[List[str]]: ...
""", """
from typing import List
from typing_extensions import TypeGuard
def f(x: List[object]) -> bool: ...
""")

def test_typing(self):
self.check("""
from typing import List, TypeGuard
def f(x: List[object]) -> TypeGuard[List[str]]: ...
""", """
from typing import List
def f(x: List[object]) -> bool: ...
""")


if __name__ == "__main__":
unittest.main()

0 comments on commit b684d03

Please sign in to comment.