Commit e0104ae1 authored by Yury Selivanov's avatar Yury Selivanov

Issue 24184: Add AsyncIterator and AsyncIterable to collections.abc.

parent 7d0d6ee5
......@@ -9,7 +9,7 @@ Unit tests are in test_collections.
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 @@ class Awaitable(metaclass=_CoroutineMeta):
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__ = ()
......
......@@ -15,7 +15,7 @@ import types
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 @@ class TestOneTrickPonyABCs(ABCTestCase):
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]
......
......@@ -122,6 +122,9 @@ Library
- 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
-----
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment