diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 44712b699bb..9ab42a3f6e2 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1735,6 +1735,23 @@ class CollectionsAbcTests(BaseTestCase): with self.assertRaises(TypeError): typing.Generator[int, int, int]() + @skipUnless(PY36, 'Python 3.6 required') + def test_async_generator(self): + ns = {} + exec("async def f():\n" + " yield 42\n", globals(), ns) + g = ns['f']() + self.assertIsSubclass(type(g), typing.AsyncGenerator) + + @skipUnless(PY36, 'Python 3.6 required') + def test_no_async_generator_instantiation(self): + with self.assertRaises(TypeError): + typing.AsyncGenerator() + with self.assertRaises(TypeError): + typing.AsyncGenerator[T, T]() + with self.assertRaises(TypeError): + typing.AsyncGenerator[int, int]() + def test_subclassing(self): class MMA(typing.MutableMapping): @@ -1804,6 +1821,31 @@ class CollectionsAbcTests(BaseTestCase): self.assertIsSubclass(G, collections.Iterable) self.assertNotIsSubclass(type(g), G) + @skipUnless(PY36, 'Python 3.6 required') + def test_subclassing_async_generator(self): + class G(typing.AsyncGenerator[int, int]): + def asend(self, value): + pass + def athrow(self, typ, val=None, tb=None): + pass + + ns = {} + exec('async def g(): yield 0', globals(), ns) + g = ns['g'] + self.assertIsSubclass(G, typing.AsyncGenerator) + self.assertIsSubclass(G, typing.AsyncIterable) + self.assertIsSubclass(G, collections.AsyncGenerator) + self.assertIsSubclass(G, collections.AsyncIterable) + self.assertNotIsSubclass(type(g), G) + + instance = G() + self.assertIsInstance(instance, typing.AsyncGenerator) + self.assertIsInstance(instance, typing.AsyncIterable) + self.assertIsInstance(instance, collections.AsyncGenerator) + self.assertIsInstance(instance, collections.AsyncIterable) + self.assertNotIsInstance(type(g), G) + self.assertNotIsInstance(g, G) + def test_subclassing_subclasshook(self): class Base(typing.Iterable): diff --git a/Lib/typing.py b/Lib/typing.py index 0aeb089d5d6..00ef440101f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -51,7 +51,8 @@ __all__ = [ # AsyncIterable, # Coroutine, # Collection, - # ContextManager + # ContextManager, + # AsyncGenerator, # Structural checks, a.k.a. protocols. 'Reversible', @@ -1900,6 +1901,13 @@ class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co], "create a subclass instead") return _generic_new(_G_base, cls, *args, **kwds) +if hasattr(collections_abc, 'AsyncGenerator'): + class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra], + extra=collections_abc.AsyncGenerator): + __slots__ = () + + __all__.append('AsyncGenerator') + # Internal type variable used for Type[]. CT_co = TypeVar('CT_co', covariant=True, bound=type)