From bc9ccb5c87ebbc0034d999ba70486f1bce4698e3 Mon Sep 17 00:00:00 2001 From: rechen Date: Tue, 23 Feb 2021 11:44:12 -0800 Subject: [PATCH] Support using collections.abc.Callable in type stubs. See https://github.com/python/typeshed/pull/5055. typeshed is moving toward using types from builtins and collections.abc rather than typing (PEP 585). Mostly, this should just work with pytype, since we rewrite typing.X to builtins.x anyway, and the collections.abc types are represented as aliases of the typing ones. However, typing.Callable has its own pytd node type, so we need to special-case collections.abc.Callable in the parser. Since Tuple also has a special node type, I added a test for Tuple as well - that appears to already be working. PiperOrigin-RevId: 359096397 --- pytype/pyi/typed_ast/definitions.py | 3 ++- pytype/tests/py3/test_pyi.py | 19 +++++++++++++++++++ pytype/tests/test_pyi.py | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/pytype/pyi/typed_ast/definitions.py b/pytype/pyi/typed_ast/definitions.py index db9f9c15a..d448f59ab 100644 --- a/pytype/pyi/typed_ast/definitions.py +++ b/pytype/pyi/typed_ast/definitions.py @@ -413,7 +413,8 @@ def _is_heterogeneous_tuple(self, t): def _is_callable_base_type(self, t): return (isinstance(t, pytd.NamedType) and - self._matches_full_name(t, "typing.Callable")) + (self._matches_full_name(t, "typing.Callable") or + self._matches_full_name(t, "collections.abc.Callable"))) def _is_literal_base_type(self, t): return isinstance(t, pytd.NamedType) and ( diff --git a/pytype/tests/py3/test_pyi.py b/pytype/tests/py3/test_pyi.py index c23b6d8bb..24663cbce 100644 --- a/pytype/tests/py3/test_pyi.py +++ b/pytype/tests/py3/test_pyi.py @@ -67,5 +67,24 @@ def f() -> bytes: ... x = ... # type: bytes """) + def test_collections_abc_callable(self): + with file_utils.Tempdir() as d: + d.create_file("foo.pyi", """ + from collections.abc import Callable + def f() -> Callable[[], float]: ... + """) + ty, _ = self.InferWithErrors(""" + import foo + func = foo.f() + func(0.0) # wrong-arg-count + x = func() + """, pythonpath=[d.path]) + self.assertTypesMatchPytd(ty, """ + from typing import Callable + foo: module + func: Callable[[], float] + x: float + """) + test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_pyi.py b/pytype/tests/test_pyi.py index c5b664efa..46fcad8d0 100644 --- a/pytype/tests/test_pyi.py +++ b/pytype/tests/test_pyi.py @@ -836,5 +836,21 @@ def f(x: _typing.Tuple[str, str]) -> None: ... """) self.Check("import foo", pythonpath=[d.path]) + def test_parameterize_builtin_tuple(self): + with file_utils.Tempdir() as d: + d.create_file("foo.pyi", """ + def f(x: tuple[int]) -> tuple[int, int]: ... + """) + ty, _ = self.InferWithErrors(""" + import foo + foo.f((0, 0)) # wrong-arg-types + x = foo.f((0,)) + """, pythonpath=[d.path]) + self.assertTypesMatchPytd(ty, """ + from typing import Tuple + foo: module + x: Tuple[int, int] + """) + test_base.main(globals(), __name__ == "__main__")