mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +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:`Set` ``__iter__``
|
||||||
:class:`ValuesView` :class:`MappingView` ``__contains__``, ``__iter__``
|
:class:`ValuesView` :class:`MappingView` ``__contains__``, ``__iter__``
|
||||||
:class:`Awaitable` ``__await__``
|
:class:`Awaitable` ``__await__``
|
||||||
:class:`Coroutine` ``send``, ``throw`` ``close``
|
:class:`Coroutine` :class:`Awaitable` ``send``, ``throw`` ``close``
|
||||||
:class:`AsyncIterable` ``__aiter__``
|
:class:`AsyncIterable` ``__aiter__``
|
||||||
:class:`AsyncIterator` :class:`AsyncIterable` ``__anext__`` ``__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
|
ABC for coroutine compatible classes that implement a subset of
|
||||||
generator methods defined in :pep:`342`, namely:
|
generator methods defined in :pep:`342`, namely:
|
||||||
:meth:`~generator.send`, :meth:`~generator.throw` and
|
:meth:`~generator.send`, :meth:`~generator.throw`,
|
||||||
:meth:`~generator.close` methods. All :class:`Coroutine` instances
|
:meth:`~generator.close` methods. :meth:`__await__` must also be
|
||||||
are also instances of :class:`Awaitable`. See also the definition
|
implemented. All :class:`Coroutine` instances are also instances of
|
||||||
of :term:`coroutine`.
|
:class:`Awaitable`. See also the definition of :term:`coroutine`.
|
||||||
|
|
||||||
.. versionadded:: 3.5
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Hashable(metaclass=ABCMeta):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
|
|
||||||
class _CoroutineMeta(ABCMeta):
|
class _AwaitableMeta(ABCMeta):
|
||||||
|
|
||||||
def __instancecheck__(cls, instance):
|
def __instancecheck__(cls, instance):
|
||||||
# 0x80 = CO_COROUTINE
|
# 0x80 = CO_COROUTINE
|
||||||
|
@ -92,7 +92,26 @@ class _CoroutineMeta(ABCMeta):
|
||||||
return super().__instancecheck__(instance)
|
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__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
@ -126,27 +145,19 @@ class Coroutine(metaclass=_CoroutineMeta):
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("coroutine ignored GeneratorExit")
|
raise RuntimeError("coroutine ignored GeneratorExit")
|
||||||
|
|
||||||
|
|
||||||
class Awaitable(metaclass=_CoroutineMeta):
|
|
||||||
|
|
||||||
__slots__ = ()
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __await__(self):
|
|
||||||
yield
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __subclasshook__(cls, C):
|
def __subclasshook__(cls, C):
|
||||||
if cls is Awaitable:
|
if cls is Coroutine:
|
||||||
for B in C.__mro__:
|
mro = C.__mro__
|
||||||
if "__await__" in B.__dict__:
|
for method in ('__await__', 'send', 'throw', 'close'):
|
||||||
if B.__dict__["__await__"]:
|
for base in mro:
|
||||||
return True
|
if method in base.__dict__:
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
return NotImplemented
|
||||||
|
return True
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
Awaitable.register(Coroutine)
|
|
||||||
|
|
||||||
|
|
||||||
class AsyncIterable(metaclass=ABCMeta):
|
class AsyncIterable(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
|
|
@ -97,18 +97,14 @@ class CoroutineTests(BaseTest):
|
||||||
finally:
|
finally:
|
||||||
f.close() # silence warning
|
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 send(self, value): pass
|
||||||
def throw(self, typ, val=None, tb=None): pass
|
def throw(self, typ, val=None, tb=None): pass
|
||||||
|
def close(self): pass
|
||||||
|
def __await__(self): yield
|
||||||
|
|
||||||
fc = FakeCoro()
|
self.assertTrue(asyncio.iscoroutine(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()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -496,6 +496,8 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||||
return value
|
return value
|
||||||
def throw(self, typ, val=None, tb=None):
|
def throw(self, typ, val=None, tb=None):
|
||||||
super().throw(typ, val, tb)
|
super().throw(typ, val, tb)
|
||||||
|
def __await__(self):
|
||||||
|
yield
|
||||||
|
|
||||||
non_samples = [None, int(), gen(), object()]
|
non_samples = [None, int(), gen(), object()]
|
||||||
for x in non_samples:
|
for x in non_samples:
|
||||||
|
@ -515,13 +517,7 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||||
self.assertIsInstance(c, Awaitable)
|
self.assertIsInstance(c, Awaitable)
|
||||||
c.close() # awoid RuntimeWarning that coro() was not awaited
|
c.close() # awoid RuntimeWarning that coro() was not awaited
|
||||||
|
|
||||||
class CoroLike:
|
class CoroLike: pass
|
||||||
def send(self, value):
|
|
||||||
pass
|
|
||||||
def throw(self, typ, val=None, tb=None):
|
|
||||||
pass
|
|
||||||
def close(self):
|
|
||||||
pass
|
|
||||||
Coroutine.register(CoroLike)
|
Coroutine.register(CoroLike)
|
||||||
self.assertTrue(isinstance(CoroLike(), Awaitable))
|
self.assertTrue(isinstance(CoroLike(), Awaitable))
|
||||||
self.assertTrue(issubclass(CoroLike, Awaitable))
|
self.assertTrue(issubclass(CoroLike, Awaitable))
|
||||||
|
@ -548,6 +544,8 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||||
return value
|
return value
|
||||||
def throw(self, typ, val=None, tb=None):
|
def throw(self, typ, val=None, tb=None):
|
||||||
super().throw(typ, val, tb)
|
super().throw(typ, val, tb)
|
||||||
|
def __await__(self):
|
||||||
|
yield
|
||||||
|
|
||||||
non_samples = [None, int(), gen(), object(), Bar()]
|
non_samples = [None, int(), gen(), object(), Bar()]
|
||||||
for x in non_samples:
|
for x in non_samples:
|
||||||
|
@ -567,6 +565,28 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||||
self.assertIsInstance(c, Coroutine)
|
self.assertIsInstance(c, Coroutine)
|
||||||
c.close() # awoid RuntimeWarning that coro() was not awaited
|
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):
|
def test_Hashable(self):
|
||||||
# Check some non-hashables
|
# Check some non-hashables
|
||||||
non_samples = [bytearray(), list(), set(), dict()]
|
non_samples = [bytearray(), list(), set(), dict()]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue