mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
Issue 24315: Make collections.abc.Coroutine derived from Awaitable
(Merge 3.5)
This commit is contained in:
commit
a24fcfdf23
4 changed files with 67 additions and 40 deletions
|
@ -82,7 +82,7 @@ ABC Inherits from Abstract Methods Mixin
|
|||
:class:`Set` ``__iter__``
|
||||
:class:`ValuesView` :class:`MappingView` ``__contains__``, ``__iter__``
|
||||
:class:`Awaitable` ``__await__``
|
||||
:class:`Coroutine` ``send``, ``throw`` ``close``
|
||||
:class:`Coroutine` :class:`Awaitable` ``send``, ``throw`` ``close``
|
||||
:class:`AsyncIterable` ``__aiter__``
|
||||
:class:`AsyncIterator` :class:`AsyncIterable` ``__anext__`` ``__aiter__``
|
||||
========================== ====================== ======================= ====================================================
|
||||
|
@ -166,10 +166,10 @@ ABC Inherits from Abstract Methods Mixin
|
|||
|
||||
ABC for coroutine compatible classes that implement a subset of
|
||||
generator methods defined in :pep:`342`, namely:
|
||||
:meth:`~generator.send`, :meth:`~generator.throw` and
|
||||
:meth:`~generator.close` methods. All :class:`Coroutine` instances
|
||||
are also instances of :class:`Awaitable`. See also the definition
|
||||
of :term:`coroutine`.
|
||||
:meth:`~generator.send`, :meth:`~generator.throw`,
|
||||
:meth:`~generator.close` methods. :meth:`__await__` must also be
|
||||
implemented. All :class:`Coroutine` instances are also instances of
|
||||
:class:`Awaitable`. See also the definition of :term:`coroutine`.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ class Hashable(metaclass=ABCMeta):
|
|||
return NotImplemented
|
||||
|
||||
|
||||
class _CoroutineMeta(ABCMeta):
|
||||
class _AwaitableMeta(ABCMeta):
|
||||
|
||||
def __instancecheck__(cls, instance):
|
||||
# 0x80 = CO_COROUTINE
|
||||
|
@ -92,7 +92,26 @@ class _CoroutineMeta(ABCMeta):
|
|||
return super().__instancecheck__(instance)
|
||||
|
||||
|
||||
class Coroutine(metaclass=_CoroutineMeta):
|
||||
class Awaitable(metaclass=_AwaitableMeta):
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __await__(self):
|
||||
yield
|
||||
|
||||
@classmethod
|
||||
def __subclasshook__(cls, C):
|
||||
if cls is Awaitable:
|
||||
for B in C.__mro__:
|
||||
if "__await__" in B.__dict__:
|
||||
if B.__dict__["__await__"]:
|
||||
return True
|
||||
break
|
||||
return NotImplemented
|
||||
|
||||
|
||||
class Coroutine(Awaitable):
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
|
@ -126,27 +145,19 @@ class Coroutine(metaclass=_CoroutineMeta):
|
|||
else:
|
||||
raise RuntimeError("coroutine ignored GeneratorExit")
|
||||
|
||||
|
||||
class Awaitable(metaclass=_CoroutineMeta):
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __await__(self):
|
||||
yield
|
||||
|
||||
@classmethod
|
||||
def __subclasshook__(cls, C):
|
||||
if cls is Awaitable:
|
||||
for B in C.__mro__:
|
||||
if "__await__" in B.__dict__:
|
||||
if B.__dict__["__await__"]:
|
||||
return True
|
||||
break
|
||||
if cls is Coroutine:
|
||||
mro = C.__mro__
|
||||
for method in ('__await__', 'send', 'throw', 'close'):
|
||||
for base in mro:
|
||||
if method in base.__dict__:
|
||||
break
|
||||
else:
|
||||
return NotImplemented
|
||||
return True
|
||||
return NotImplemented
|
||||
|
||||
Awaitable.register(Coroutine)
|
||||
|
||||
|
||||
class AsyncIterable(metaclass=ABCMeta):
|
||||
|
||||
|
|
|
@ -97,18 +97,14 @@ class CoroutineTests(BaseTest):
|
|||
finally:
|
||||
f.close() # silence warning
|
||||
|
||||
class FakeCoro(collections.abc.Coroutine):
|
||||
# Test that asyncio.iscoroutine() uses collections.abc.Coroutine
|
||||
class FakeCoro:
|
||||
def send(self, value): pass
|
||||
def throw(self, typ, val=None, tb=None): pass
|
||||
def close(self): pass
|
||||
def __await__(self): yield
|
||||
|
||||
fc = FakeCoro()
|
||||
try:
|
||||
self.assertTrue(asyncio.iscoroutine(fc))
|
||||
finally:
|
||||
# To make sure that ABCMeta caches are freed
|
||||
# from FakeCoro ASAP.
|
||||
fc = FakeCoro = None
|
||||
support.gc_collect()
|
||||
self.assertTrue(asyncio.iscoroutine(FakeCoro()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -496,6 +496,8 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
|||
return value
|
||||
def throw(self, typ, val=None, tb=None):
|
||||
super().throw(typ, val, tb)
|
||||
def __await__(self):
|
||||
yield
|
||||
|
||||
non_samples = [None, int(), gen(), object()]
|
||||
for x in non_samples:
|
||||
|
@ -515,13 +517,7 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
|||
self.assertIsInstance(c, Awaitable)
|
||||
c.close() # awoid RuntimeWarning that coro() was not awaited
|
||||
|
||||
class CoroLike:
|
||||
def send(self, value):
|
||||
pass
|
||||
def throw(self, typ, val=None, tb=None):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
class CoroLike: pass
|
||||
Coroutine.register(CoroLike)
|
||||
self.assertTrue(isinstance(CoroLike(), Awaitable))
|
||||
self.assertTrue(issubclass(CoroLike, Awaitable))
|
||||
|
@ -548,6 +544,8 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
|||
return value
|
||||
def throw(self, typ, val=None, tb=None):
|
||||
super().throw(typ, val, tb)
|
||||
def __await__(self):
|
||||
yield
|
||||
|
||||
non_samples = [None, int(), gen(), object(), Bar()]
|
||||
for x in non_samples:
|
||||
|
@ -567,6 +565,28 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
|||
self.assertIsInstance(c, Coroutine)
|
||||
c.close() # awoid RuntimeWarning that coro() was not awaited
|
||||
|
||||
class CoroLike:
|
||||
def send(self, value):
|
||||
pass
|
||||
def throw(self, typ, val=None, tb=None):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
def __await__(self):
|
||||
pass
|
||||
self.assertTrue(isinstance(CoroLike(), Coroutine))
|
||||
self.assertTrue(issubclass(CoroLike, Coroutine))
|
||||
|
||||
class CoroLike:
|
||||
def send(self, value):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
def __await__(self):
|
||||
pass
|
||||
self.assertFalse(isinstance(CoroLike(), Coroutine))
|
||||
self.assertFalse(issubclass(CoroLike, Coroutine))
|
||||
|
||||
def test_Hashable(self):
|
||||
# Check some non-hashables
|
||||
non_samples = [bytearray(), list(), set(), dict()]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue