Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit e9ed560

Browse files
committed
Issue python#29198: add AsyncGenerator (Jelle Zijlstra)
1 parent 3c268be commit e9ed560

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

Lib/test/test_typing.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,23 @@ def test_no_generator_instantiation(self):
17351735
with self.assertRaises(TypeError):
17361736
typing.Generator[int, int, int]()
17371737

1738+
@skipUnless(PY36, 'Python 3.6 required')
1739+
def test_async_generator(self):
1740+
ns = {}
1741+
exec("async def f():\n"
1742+
" yield 42\n", globals(), ns)
1743+
g = ns['f']()
1744+
self.assertIsSubclass(type(g), typing.AsyncGenerator)
1745+
1746+
@skipUnless(PY36, 'Python 3.6 required')
1747+
def test_no_async_generator_instantiation(self):
1748+
with self.assertRaises(TypeError):
1749+
typing.AsyncGenerator()
1750+
with self.assertRaises(TypeError):
1751+
typing.AsyncGenerator[T, T]()
1752+
with self.assertRaises(TypeError):
1753+
typing.AsyncGenerator[int, int]()
1754+
17381755
def test_subclassing(self):
17391756

17401757
class MMA(typing.MutableMapping):
@@ -1804,6 +1821,31 @@ def g(): yield 0
18041821
self.assertIsSubclass(G, collections.Iterable)
18051822
self.assertNotIsSubclass(type(g), G)
18061823

1824+
@skipUnless(PY36, 'Python 3.6 required')
1825+
def test_subclassing_async_generator(self):
1826+
class G(typing.AsyncGenerator[int, int]):
1827+
def asend(self, value):
1828+
pass
1829+
def athrow(self, typ, val=None, tb=None):
1830+
pass
1831+
1832+
ns = {}
1833+
exec('async def g(): yield 0', globals(), ns)
1834+
g = ns['g']
1835+
self.assertIsSubclass(G, typing.AsyncGenerator)
1836+
self.assertIsSubclass(G, typing.AsyncIterable)
1837+
self.assertIsSubclass(G, collections.AsyncGenerator)
1838+
self.assertIsSubclass(G, collections.AsyncIterable)
1839+
self.assertNotIsSubclass(type(g), G)
1840+
1841+
instance = G()
1842+
self.assertIsInstance(instance, typing.AsyncGenerator)
1843+
self.assertIsInstance(instance, typing.AsyncIterable)
1844+
self.assertIsInstance(instance, collections.AsyncGenerator)
1845+
self.assertIsInstance(instance, collections.AsyncIterable)
1846+
self.assertNotIsInstance(type(g), G)
1847+
self.assertNotIsInstance(g, G)
1848+
18071849
def test_subclassing_subclasshook(self):
18081850

18091851
class Base(typing.Iterable):

Lib/typing.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
# AsyncIterable,
5252
# Coroutine,
5353
# Collection,
54-
# ContextManager
54+
# ContextManager,
55+
# AsyncGenerator,
5556

5657
# Structural checks, a.k.a. protocols.
5758
'Reversible',
@@ -1900,6 +1901,13 @@ def __new__(cls, *args, **kwds):
19001901
"create a subclass instead")
19011902
return _generic_new(_G_base, cls, *args, **kwds)
19021903

1904+
if hasattr(collections_abc, 'AsyncGenerator'):
1905+
class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra],
1906+
extra=collections_abc.AsyncGenerator):
1907+
__slots__ = ()
1908+
1909+
__all__.append('AsyncGenerator')
1910+
19031911

19041912
# Internal type variable used for Type[].
19051913
CT_co = TypeVar('CT_co', covariant=True, bound=type)

0 commit comments

Comments
 (0)