mirror of
https://github.com/python/cpython.git
synced 2025-11-01 10:45:30 +00:00
Issue 24184: Add AsyncIterator and AsyncIterable to collections.abc.
This commit is contained in:
parent
7d0d6ee525
commit
e0104ae103
3 changed files with 76 additions and 2 deletions
|
|
@ -9,7 +9,7 @@ Unit tests are in test_collections.
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
__all__ = ["Awaitable", "Coroutine",
|
__all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator",
|
||||||
"Hashable", "Iterable", "Iterator", "Generator",
|
"Hashable", "Iterable", "Iterator", "Generator",
|
||||||
"Sized", "Container", "Callable",
|
"Sized", "Container", "Callable",
|
||||||
"Set", "MutableSet",
|
"Set", "MutableSet",
|
||||||
|
|
@ -148,6 +148,43 @@ class Awaitable(metaclass=_CoroutineMeta):
|
||||||
Awaitable.register(Coroutine)
|
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):
|
class Iterable(metaclass=ABCMeta):
|
||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import types
|
||||||
from collections import UserDict
|
from collections import UserDict
|
||||||
from collections import ChainMap
|
from collections import ChainMap
|
||||||
from collections import deque
|
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 Hashable, Iterable, Iterator, Generator
|
||||||
from collections.abc import Sized, Container, Callable
|
from collections.abc import Sized, Container, Callable
|
||||||
from collections.abc import Set, MutableSet
|
from collections.abc import Set, MutableSet
|
||||||
|
|
@ -573,6 +573,40 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||||
self.validate_abstract_methods(Hashable, '__hash__')
|
self.validate_abstract_methods(Hashable, '__hash__')
|
||||||
self.validate_isinstance(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):
|
def test_Iterable(self):
|
||||||
# Check some non-iterables
|
# Check some non-iterables
|
||||||
non_samples = [None, 42, 3.14, 1j]
|
non_samples = [None, 42, 3.14, 1j]
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,9 @@ Library
|
||||||
- Issue 24179: Support 'async for' for asyncio.StreamReader.
|
- Issue 24179: Support 'async for' for asyncio.StreamReader.
|
||||||
Contributed by Yury Selivanov.
|
Contributed by Yury Selivanov.
|
||||||
|
|
||||||
|
- Issue 24184: Add AsyncIterator and AsyncIterable ABCs to
|
||||||
|
collections.abc. Contributed by Yury Selivanov.
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue