Skip to content

Commit

Permalink
Stop exposing fake builtins generator, asyncgenerator, coroutine
Browse files Browse the repository at this point in the history
Update type annotations for the `throw` method of `Generator` and others.
Previously these type annotations happened to be unused, so it was not noticeable that they are incomplete. So, make them more similar to typeshed/typing.pyi.

PiperOrigin-RevId: 683766929
  • Loading branch information
oprypin authored and copybara-github committed Oct 10, 2024
1 parent 65ad8fb commit ed39d83
Show file tree
Hide file tree
Showing 12 changed files with 35 additions and 64 deletions.
4 changes: 2 additions & 2 deletions pytype/abstract/_interpreter_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ def _matches_generator_helper(type_obj, allowed_types):


def _matches_generator(type_obj):
allowed_types = ("generator", "Iterable", "Iterator")
allowed_types = ("Generator", "Iterable", "Iterator")
return _matches_generator_helper(type_obj, allowed_types)


def _matches_async_generator(type_obj):
allowed_types = ("asyncgenerator", "AsyncIterable", "AsyncIterator")
allowed_types = ("AsyncGenerator", "AsyncIterable", "AsyncIterator")
return _matches_generator_helper(type_obj, allowed_types)


Expand Down
6 changes: 4 additions & 2 deletions pytype/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,13 @@ def _type_to_name(self, t):
elif t is IteratorType:
return "builtins", "object"
elif t is CoroutineType:
return "builtins", "coroutine"
return "typing", "Coroutine"
elif t is AwaitableType:
return "typing", "Awaitable"
elif t is AsyncGeneratorType:
return "builtins", "asyncgenerator"
return "typing", "AsyncGenerator"
elif t is types.GeneratorType:
return "typing", "Generator"
else:
return "builtins", t.__name__

Expand Down
2 changes: 1 addition & 1 deletion pytype/pyi/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def _extract_function_properties(self, node):
abstract = True
elif self.defs.matches_type(
d.name,
("builtins.coroutine", "asyncio.coroutine", "coroutines.coroutine"),
("typing.Coroutine", "asyncio.coroutine", "coroutines.coroutine"),
):
coroutine = True
elif self.defs.matches_type(d.name, "typing.final"):
Expand Down
13 changes: 1 addition & 12 deletions pytype/pytd/pep484.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,6 @@
]


# These lowercase names are used inside pytype as if they're builtins, but they
# are actually not real at all. In fact, pytype accepts literally writing
# `generator[int,...]` in type annotations even though there's no such type.
# TODO(b/372205529): Remove this implementation detail.
PYTYPE_SPECIFIC_FAKE_BUILTINS = {
"generator": "Generator",
"coroutine": "Coroutine",
"asyncgenerator": "AsyncGenerator",
}


# The PEP 484 definition of built-in types.
# E.g. "typing.List" is used to represent the "list" type.
BUILTIN_TO_TYPING = {
Expand All @@ -81,7 +70,7 @@
"FrozenSet",
"Type",
]
} | PYTYPE_SPECIFIC_FAKE_BUILTINS
}

TYPING_TO_BUILTIN = {v: k for k, v in BUILTIN_TO_TYPING.items()}

Expand Down
16 changes: 2 additions & 14 deletions pytype/pytd/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,13 +754,6 @@ def VisitParamSpecKwargs(self, node):
def VisitModule(self, node):
return "module"

def MaybeCapitalize(self, name):
"""Capitalize a generic type, if necessary."""
if name in pep484.PYTYPE_SPECIFIC_FAKE_BUILTINS:
return self._FromTyping(pep484.PYTYPE_SPECIFIC_FAKE_BUILTINS[name])
else:
return name

def VisitGenericType(self, node):
"""Convert a generic type to a string."""
parameters = node.parameters
Expand All @@ -776,15 +769,10 @@ def VisitGenericType(self, node):
else:
assert isinstance(param, (pytd.NothingType, pytd.TypeParameter)), param
parameters = ("...",) + parameters[1:]
return (
self.MaybeCapitalize(node.base_type)
+ "["
+ ", ".join(str(p) for p in parameters)
+ "]"
)
return node.base_type + "[" + ", ".join(str(p) for p in parameters) + "]"

def VisitCallableType(self, node):
typ = self.MaybeCapitalize(node.base_type)
typ = node.base_type
if len(node.args) == 1 and node.args[0] in self._paramspec_names:
return f"{typ}[{node.args[0]}, {node.ret}]"
elif node.args and "Concatenate" in node.args[0]:
Expand Down
19 changes: 0 additions & 19 deletions pytype/stubs/builtins/builtins.pytd
Original file line number Diff line number Diff line change
Expand Up @@ -953,25 +953,6 @@ class complex(SupportsAbs, SupportsInt, SupportsFloat, SupportsComplex):
def __truediv__(self, y: Union[int, float, complex]) -> complex: ...
def conjugate(self) -> complex: ...

class generator(Generator[_T, _T2, _V]):
__slots__ = []
def __iter__(self) -> generator[_T, _T2, _V]: ...
def __next__(self) -> _T: ...
def send(self, value: _T2) -> _T: ...
def close(self) -> NoneType: ...

class coroutine(Coroutine[_T, _T2, _V]):
__slots__ = []
def close(self) -> NoneType: ...
def send(self, value: _T2) -> _T: ...

class asyncgenerator(AsyncGenerator[_T, _T2]):
__slots__ = []
def __aiter__(self) -> asyncgenerator[_T, _T2]: ...
def __anext__(self) -> coroutine[Any, Any, _T]: ...
def asend(self, value: _T2) -> coroutine[Any, Any, _T]: ...
def aclose(self) -> coroutine[Any, Any, None]: ...

class instancemethod(object):
__slots__ = []
def __init__(self, function: Union[Callable, instancemethod], instance, cls) -> NoneType: ...
Expand Down
17 changes: 14 additions & 3 deletions pytype/stubs/builtins/typing.pytd
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,10 @@ class Generator(Iterator[_T], Generic[_T, _T2, _V]):
gi_yieldfrom: Optional[Generator[Any, Any, Any]]
def __next__(self) -> _T: ...
def send(self, value: _T2) -> _T: ...
def throw(self, typ: BaseException, val = ..., tb = ...) -> _T: ...
@overload
def throw(self, typ: type[BaseException], val: BaseException | object = None, tb = None) -> _T: ...
@overload
def throw(self, typ: BaseException, val: None = None, tb = None) -> _T: ...
def close(self) -> None: ...


Expand Down Expand Up @@ -539,8 +542,12 @@ class Coroutine(Awaitable[_V], Generic[_T, _T2, _V]):
__slots__ = []
@abstractmethod
def send(self, value: _T2) -> _T: ...
@overload
@abstractmethod
def throw(self, typ: type[BaseException], val: BaseException | object = None, tb = None) -> _T: ...
@overload
@abstractmethod
def throw(self, typ: Type[BaseException], val = ..., tb = ...) -> _T: ...
def throw(self, typ: BaseException, val: None = None, tb = None) -> _T: ...
@abstractmethod
def close(self) -> None: ...

Expand All @@ -559,8 +566,12 @@ class AsyncGenerator(AsyncIterator[_T], Generic[_T, _T2]):
def __anext__(self) -> Coroutine[Any, Any, _T]: ...
@abstractmethod
def asend(self, value: _T2) -> Coroutine[Any, Any, _T]: ...
@overload
@abstractmethod
def athrow(self, typ: type[BaseException], val: BaseException | object = None, tb = None) -> Coroutine[Any, Any, _T]: ...
@overload
@abstractmethod
def athrow(self, typ: Type[BaseException], val = ..., tb = ...) -> Coroutine[Any, Any, _T]: ...
def athrow(self, typ: BaseException, val: None = None, tb = None) -> Coroutine[Any, Any, _T]: ...
@abstractmethod
def aclose(self) -> Coroutine[Any, Any, None]: ...

Expand Down
2 changes: 1 addition & 1 deletion pytype/tests/test_coroutine.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ async def main():
"""
import asyncio
from typing import Any, Coroutine
def worker(queue) -> coroutine: ...
def worker(queue) -> Coroutine: ...
def main() -> Coroutine[Any, Any, None]: ...
""",
)
Expand Down
4 changes: 2 additions & 2 deletions pytype/tests/test_generators1.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ def bar(self):
for x in __any_object__:
return x
def __iter__(self):
return generator()
return (i for i in range(5))
""")
self.assertTypesMatchPytd(
ty,
"""
from typing import Any, Generator
class Foo:
def bar(self) -> Any: ...
def __iter__(self) -> Generator[nothing, nothing, nothing]: ...
def __iter__(self) -> Generator[int, Any, None]: ...
""",
)

Expand Down
8 changes: 4 additions & 4 deletions pytype/tests/test_generators2.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class GeneratorBasicTest(test_base.BaseTest):
def test_return_before_yield(self):
self.Check("""
from typing import Generator
def f() -> generator:
def f() -> Generator:
if __random__:
return
yield 5
Expand Down Expand Up @@ -116,16 +116,16 @@ def func3() -> Generator[int]: # invalid-annotation[e2]
self.assertErrorSequences(
errors,
{
"e1": ["generator[int, int]", "generator[_T, _T2, _V]", "3", "2"],
"e2": ["generator[int]", "generator[_T, _T2, _V]", "3", "1"],
"e1": ["Generator[int, int]", "Generator[_T, _T2, _V]", "3", "2"],
"e2": ["Generator[int]", "Generator[_T, _T2, _V]", "3", "1"],
},
)

def test_hidden_fields(self):
self.Check("""
from typing import Generator
from types import GeneratorType
a: generator = __any_object__
a: Generator = __any_object__
a.gi_code
a.gi_frame
a.gi_running
Expand Down
2 changes: 1 addition & 1 deletion pytype/tests/test_stdlib2.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def test_collections_collection(self):

def test_collections_generator(self):
self._testCollectionsObject(
"Generator", "i for i in range(42)", "42", r"generator.*int"
"Generator", "i for i in range(42)", "42", r"Generator.*int"
)

def test_collections_reversible(self):
Expand Down
6 changes: 3 additions & 3 deletions pytype/vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3107,7 +3107,7 @@ def byte_GET_YIELD_FROM_ITER(self, state, op):
unchanged = self.ctx.program.NewVariable()
state, tos = state.pop()
for b in tos.bindings:
if b.data.full_name in ("builtins.generator", "builtins.coroutine"):
if b.data.full_name in ("typing.Generator", "typing.Coroutine"):
unchanged.PasteBinding(b)
else:
get_iter.PasteBinding(b)
Expand Down Expand Up @@ -3250,7 +3250,7 @@ def byte_GET_AWAITABLE(self, state, op):
def _get_generator_yield(self, node, generator_var):
yield_var = self.frame.yield_variable.AssignToNewVariable(node)
for generator in generator_var.data:
if generator.full_name == "builtins.generator":
if generator.full_name == "typing.Generator":
yield_value = generator.get_instance_type_parameter(abstract_utils.T)
yield_var.PasteVariable(yield_value, node)
return yield_var
Expand All @@ -3272,7 +3272,7 @@ def _get_generator_return(self, node, generator_var):
generator.cls, (abstract.ParameterizedClass, abstract.PyTDClass)
)
and generator.cls.full_name
in ("typing.Awaitable", "builtins.coroutine", "builtins.generator")
in ("typing.Awaitable", "typing.Coroutine", "typing.Generator")
):
if generator.cls.full_name == "typing.Awaitable":
ret = generator.get_instance_type_parameter(abstract_utils.T)
Expand Down

0 comments on commit ed39d83

Please sign in to comment.