[Python-checkins] cpython: Issue 24184: Add AsyncIterator and AsyncIterable to collections.abc.

yury.selivanov python-checkins at python.org
Thu May 14 18:19:24 CEST 2015


https://hg.python.org/cpython/rev/4347ce7acd84
changeset:   96049:4347ce7acd84
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Thu May 14 12:19:16 2015 -0400
summary:
  Issue 24184: Add AsyncIterator and AsyncIterable to collections.abc.

files:
  Lib/_collections_abc.py      |  39 +++++++++++++++++++++++-
  Lib/test/test_collections.py |  36 +++++++++++++++++++++-
  Misc/NEWS                    |   3 +
  3 files changed, 76 insertions(+), 2 deletions(-)


diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -9,7 +9,7 @@
 from abc import ABCMeta, abstractmethod
 import sys
 
-__all__ = ["Awaitable", "Coroutine",
+__all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator",
            "Hashable", "Iterable", "Iterator", "Generator",
            "Sized", "Container", "Callable",
            "Set", "MutableSet",
@@ -148,6 +148,43 @@
 Awaitable.register(Coroutine)
 
 
+class AsyncIterable(metaclass=ABCMeta):
+
+    __slots__ = ()
+
+    @abstractmethod
+    async def __aiter__(self):
+        return AsyncIterator()
+
+    @classmethod
+    def __subclasshook__(cls, C):
+        if cls is AsyncIterable:
+            if any("__aiter__" in B.__dict__ for B in C.__mro__):
+                return True
+        return NotImplemented
+
+
+class AsyncIterator(AsyncIterable):
+
+    __slots__ = ()
+
+    @abstractmethod
+    async def __anext__(self):
+        """Return the next item or raise StopAsyncIteration when exhausted."""
+        raise StopAsyncIteration
+
+    async def __aiter__(self):
+        return self
+
+    @classmethod
+    def __subclasshook__(cls, C):
+        if cls is AsyncIterator:
+            if (any("__anext__" in B.__dict__ for B in C.__mro__) and
+                any("__aiter__" in B.__dict__ for B in C.__mro__)):
+                return True
+        return NotImplemented
+
+
 class Iterable(metaclass=ABCMeta):
 
     __slots__ = ()
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -15,7 +15,7 @@
 from collections import UserDict
 from collections import ChainMap
 from collections import deque
-from collections.abc import Awaitable, Coroutine
+from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable
 from collections.abc import Hashable, Iterable, Iterator, Generator
 from collections.abc import Sized, Container, Callable
 from collections.abc import Set, MutableSet
@@ -573,6 +573,40 @@
         self.validate_abstract_methods(Hashable, '__hash__')
         self.validate_isinstance(Hashable, '__hash__')
 
+    def test_AsyncIterable(self):
+        class AI:
+            async def __aiter__(self):
+                return self
+        self.assertTrue(isinstance(AI(), AsyncIterable))
+        self.assertTrue(issubclass(AI, AsyncIterable))
+        # Check some non-iterables
+        non_samples = [None, object, []]
+        for x in non_samples:
+            self.assertNotIsInstance(x, AsyncIterable)
+            self.assertFalse(issubclass(type(x), AsyncIterable), repr(type(x)))
+        self.validate_abstract_methods(AsyncIterable, '__aiter__')
+        self.validate_isinstance(AsyncIterable, '__aiter__')
+
+    def test_AsyncIterator(self):
+        class AI:
+            async def __aiter__(self):
+                return self
+            async def __anext__(self):
+                raise StopAsyncIteration
+        self.assertTrue(isinstance(AI(), AsyncIterator))
+        self.assertTrue(issubclass(AI, AsyncIterator))
+        non_samples = [None, object, []]
+        # Check some non-iterables
+        for x in non_samples:
+            self.assertNotIsInstance(x, AsyncIterator)
+            self.assertFalse(issubclass(type(x), AsyncIterator), repr(type(x)))
+        # Similarly to regular iterators (see issue 10565)
+        class AnextOnly:
+            async def __anext__(self):
+                raise StopAsyncIteration
+        self.assertNotIsInstance(AnextOnly(), AsyncIterator)
+        self.validate_abstract_methods(AsyncIterator, '__anext__', '__aiter__')
+
     def test_Iterable(self):
         # Check some non-iterables
         non_samples = [None, 42, 3.14, 1j]
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -122,6 +122,9 @@
 - Issue 24179: Support 'async for' for asyncio.StreamReader.
   Contributed by Yury Selivanov.
 
+- Issue 24184: Add AsyncIterator and AsyncIterable ABCs to
+  collections.abc.  Contributed by Yury Selivanov.
+
 Tests
 -----
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list