From 22b6769d08dcf653068df80c08381217a9a7c297 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 7 Jan 2017 11:07:35 -0800 Subject: [PATCH 1/3] add AsyncGenerator --- src/test_typing.py | 30 ++++++++++++++++++++++++++++++ src/typing.py | 18 +++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/test_typing.py b/src/test_typing.py index 73bcda1e0..97c2401d1 100644 --- a/src/test_typing.py +++ b/src/test_typing.py @@ -1344,6 +1344,7 @@ def blah(): ASYNCIO = sys.version_info[:2] >= (3, 5) +ASYNC_GENERATOR = sys.version_info[:2] >= (3, 6) ASYNCIO_TESTS = """ import asyncio @@ -1731,6 +1732,23 @@ def test_no_generator_instantiation(self): 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): @@ -1800,6 +1818,18 @@ def g(): yield 0 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]): ... + 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) + def test_subclassing_subclasshook(self): class Base(typing.Iterable): diff --git a/src/typing.py b/src/typing.py index b798830f6..9e8eff5f6 100644 --- a/src/typing.py +++ b/src/typing.py @@ -51,7 +51,8 @@ # AsyncIterable, # Coroutine, # Collection, - # ContextManager + # ContextManager, + # AsyncGenerator, # Structural checks, a.k.a. protocols. 'Reversible', @@ -1900,6 +1901,21 @@ def __new__(cls, *args, **kwds): "create a subclass instead") return _generic_new(_G_base, cls, *args, **kwds) +if hasattr(collections_abc, 'AsyncGenerator'): + _AG_base = collections_abc.AsyncGenerator + + class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra], + extra=_AG_base): + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, AsyncGenerator): + raise TypeError("Type AsyncGenerator cannot be instantiated; " + "create a subclass instead") + return _generic_new(_AG_base, cls, *args, **kwds) + + __all__.append('AsyncGenerator') + # Internal type variable used for Type[]. CT_co = TypeVar('CT_co', covariant=True, bound=type) From 3985968607ca329d482ccb6afcdf8915100bf3b1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 8 Jan 2017 16:41:18 -0800 Subject: [PATCH 2/3] AsyncGenerator: remove redundant __new__, add test case for instantiation --- src/test_typing.py | 14 +++++++++++++- src/typing.py | 6 ------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test_typing.py b/src/test_typing.py index 97c2401d1..39d35a843 100644 --- a/src/test_typing.py +++ b/src/test_typing.py @@ -1820,7 +1820,12 @@ def g(): yield 0 @skipUnless(PY36, 'Python 3.6 required') def test_subclassing_async_generator(self): - class G(typing.AsyncGenerator[int, int]): ... + 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'] @@ -1830,6 +1835,13 @@ class G(typing.AsyncGenerator[int, int]): ... 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) + def test_subclassing_subclasshook(self): class Base(typing.Iterable): diff --git a/src/typing.py b/src/typing.py index 9e8eff5f6..244b7d70d 100644 --- a/src/typing.py +++ b/src/typing.py @@ -1908,12 +1908,6 @@ class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra], extra=_AG_base): __slots__ = () - def __new__(cls, *args, **kwds): - if _geqv(cls, AsyncGenerator): - raise TypeError("Type AsyncGenerator cannot be instantiated; " - "create a subclass instead") - return _generic_new(_AG_base, cls, *args, **kwds) - __all__.append('AsyncGenerator') From f4bd52f267f2056b620da0234268530e449a031e Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 17 Jan 2017 20:43:49 -0800 Subject: [PATCH 3/3] remove redundant line --- src/test_typing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test_typing.py b/src/test_typing.py index 39d35a843..086be2bb6 100644 --- a/src/test_typing.py +++ b/src/test_typing.py @@ -1344,7 +1344,6 @@ def blah(): ASYNCIO = sys.version_info[:2] >= (3, 5) -ASYNC_GENERATOR = sys.version_info[:2] >= (3, 6) ASYNCIO_TESTS = """ import asyncio