]> granicus.if.org Git - python/commitdiff
Issue #29198: add AsyncGenerator (Jelle Zijlstra)
authorGuido van Rossum <guido@python.org>
Wed, 18 Jan 2017 21:10:31 +0000 (13:10 -0800)
committerGuido van Rossum <guido@python.org>
Wed, 18 Jan 2017 21:10:31 +0000 (13:10 -0800)
Lib/test/test_typing.py
Lib/typing.py

index 44712b699bb48d7586aa5fede37220f54d1bdd4b..9ab42a3f6e2dfd0bfcf30fd08d29fac2f4e9afd9 100644 (file)
@@ -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):
index 0aeb089d5d61a595832b7826f293aeb9198f55ce..00ef440101fa5477e8c9fb5a9172ec61f90125c1 100644 (file)
@@ -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)