Commit 68b34a72 authored by Andrew Svetlov's avatar Andrew Svetlov Committed by Miss Islington (bot)

bpo-36921: Deprecate @coroutine for sake of async def (GH-13346)



The second attempt. Now deprecate `@coroutine` only, keep `yield from fut` as is.


https://bugs.python.org/issue36921
parent dbacfc22
......@@ -916,12 +916,13 @@ enforced.
async def main():
await old_style_coroutine()
This decorator is **deprecated** and is scheduled for removal in
Python 3.10.
This decorator should not be used for :keyword:`async def`
coroutines.
.. deprecated-removed:: 3.8 3.10
Use :keyword:`async def` instead.
.. function:: iscoroutine(obj)
Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`.
......
......@@ -7,6 +7,7 @@ import os
import sys
import traceback
import types
import warnings
from . import base_futures
from . import constants
......@@ -107,6 +108,9 @@ def coroutine(func):
If the coroutine is not yielded from before it is destroyed,
an error message is logged.
"""
warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
DeprecationWarning,
stacklevel=2)
if inspect.iscoroutinefunction(func):
# In Python 3.5 that's all we need to do for coroutines
# defined with "async def".
......
......@@ -3,12 +3,13 @@
__all__ = ('Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore')
import collections
import types
import warnings
from . import events
from . import futures
from . import exceptions
from .coroutines import coroutine
from .import coroutines
class _ContextManager:
......@@ -55,7 +56,7 @@ class _ContextManagerMixin:
# always raises; that's how the with-statement works.
pass
@coroutine
@types.coroutine
def __iter__(self):
# This is not a coroutine. It is meant to enable the idiom:
#
......@@ -78,6 +79,9 @@ class _ContextManagerMixin:
yield from self.acquire()
return _ContextManager(self)
# The flag is needed for legacy asyncio.iscoroutine()
__iter__._is_coroutine = coroutines._is_coroutine
async def __acquire_ctx(self):
await self.acquire()
return _ContextManager(self)
......
......@@ -23,7 +23,7 @@ from . import coroutines
from . import events
from . import exceptions
from . import futures
from .coroutines import coroutine
from .coroutines import _is_coroutine
# Helper to generate new task names
# This uses itertools.count() instead of a "+= 1" operation because the latter
......@@ -638,7 +638,7 @@ def ensure_future(coro_or_future, *, loop=None):
'required')
@coroutine
@types.coroutine
def _wrap_awaitable(awaitable):
"""Helper for asyncio.ensure_future().
......@@ -647,6 +647,8 @@ def _wrap_awaitable(awaitable):
"""
return (yield from awaitable.__await__())
_wrap_awaitable._is_coroutine = _is_coroutine
class _GatheringFuture(futures.Future):
"""Helper for gather().
......
......@@ -575,9 +575,8 @@ class BaseEventLoopTests(test_utils.TestCase):
def test_default_exc_handler_coro(self):
self.loop._process_events = mock.Mock()
@asyncio.coroutine
def zero_error_coro():
yield from asyncio.sleep(0.01)
async def zero_error_coro():
await asyncio.sleep(0.01)
1/0
# Test Future.__del__
......@@ -723,8 +722,7 @@ class BaseEventLoopTests(test_utils.TestCase):
class MyTask(asyncio.Task):
pass
@asyncio.coroutine
def coro():
async def coro():
pass
factory = lambda loop, coro: MyTask(coro, loop=loop)
......@@ -779,8 +777,7 @@ class BaseEventLoopTests(test_utils.TestCase):
class MyTask(asyncio.Task):
pass
@asyncio.coroutine
def test():
async def test():
pass
class EventLoop(base_events.BaseEventLoop):
......@@ -830,8 +827,7 @@ class BaseEventLoopTests(test_utils.TestCase):
# Python issue #22601: ensure that the temporary task created by
# run_forever() consumes the KeyboardInterrupt and so don't log
# a warning
@asyncio.coroutine
def raise_keyboard_interrupt():
async def raise_keyboard_interrupt():
raise KeyboardInterrupt
self.loop._process_events = mock.Mock()
......@@ -849,8 +845,7 @@ class BaseEventLoopTests(test_utils.TestCase):
def test_run_until_complete_baseexception(self):
# Python issue #22429: run_until_complete() must not schedule a pending
# call to stop() if the future raised a BaseException
@asyncio.coroutine
def raise_keyboard_interrupt():
async def raise_keyboard_interrupt():
raise KeyboardInterrupt
self.loop._process_events = mock.Mock()
......@@ -1070,9 +1065,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
class MyProto(asyncio.Protocol):
pass
@asyncio.coroutine
def getaddrinfo(*args, **kw):
yield from []
async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('107.6.106.82', 80)),
(2, 1, 6, '', ('107.6.106.82', 80))]
......@@ -1191,9 +1184,8 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
self.assertRaises(ValueError, self.loop.run_until_complete, coro)
def test_create_connection_no_getaddrinfo(self):
@asyncio.coroutine
def getaddrinfo(*args, **kw):
yield from []
async def getaddrinfo(*args, **kw):
return []
def getaddrinfo_task(*args, **kwds):
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
......@@ -1219,8 +1211,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
OSError, self.loop.run_until_complete, coro)
def test_create_connection_multiple(self):
@asyncio.coroutine
def getaddrinfo(*args, **kw):
async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('0.0.0.1', 80)),
(2, 1, 6, '', ('0.0.0.2', 80))]
......@@ -1247,8 +1238,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
m_socket.socket.return_value.bind = bind
@asyncio.coroutine
def getaddrinfo(*args, **kw):
async def getaddrinfo(*args, **kw):
return [(2, 1, 6, '', ('0.0.0.1', 80)),
(2, 1, 6, '', ('0.0.0.2', 80))]
......@@ -1349,8 +1339,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
self.loop.run_until_complete(coro)
def test_create_connection_no_local_addr(self):
@asyncio.coroutine
def getaddrinfo(host, *args, **kw):
async def getaddrinfo(host, *args, **kw):
if host == 'example.com':
return [(2, 1, 6, '', ('107.6.106.82', 80)),
(2, 1, 6, '', ('107.6.106.82', 80))]
......@@ -1488,11 +1477,10 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
# if host is empty string use None instead
host = object()
@asyncio.coroutine
def getaddrinfo(*args, **kw):
async def getaddrinfo(*args, **kw):
nonlocal host
host = args[0]
yield from []
return []
def getaddrinfo_task(*args, **kwds):
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
......@@ -1854,9 +1842,10 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
MyProto, sock, None, None, mock.ANY, mock.ANY)
def test_call_coroutine(self):
@asyncio.coroutine
def simple_coroutine():
pass
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def simple_coroutine():
pass
self.loop.set_debug(True)
coro_func = simple_coroutine
......@@ -1880,9 +1869,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
def stop_loop_cb(loop):
loop.stop()
@asyncio.coroutine
def stop_loop_coro(loop):
yield from ()
async def stop_loop_coro(loop):
loop.stop()
asyncio.set_event_loop(self.loop)
......@@ -1909,8 +1896,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
class RunningLoopTests(unittest.TestCase):
def test_running_loop_within_a_loop(self):
@asyncio.coroutine
def runner(loop):
async def runner(loop):
loop.run_forever()
loop = asyncio.new_event_loop()
......
......@@ -253,12 +253,10 @@ class EventLoopTestsMixin:
super().tearDown()
def test_run_until_complete_nesting(self):
@asyncio.coroutine
def coro1():
yield
async def coro1():
await asyncio.sleep(0)
@asyncio.coroutine
def coro2():
async def coro2():
self.assertTrue(self.loop.is_running())
self.loop.run_until_complete(coro1())
......@@ -735,8 +733,7 @@ class EventLoopTestsMixin:
@mock.patch('asyncio.base_events.socket')
def create_server_multiple_hosts(self, family, hosts, mock_sock):
@asyncio.coroutine
def getaddrinfo(host, port, *args, **kw):
async def getaddrinfo(host, port, *args, **kw):
if family == socket.AF_INET:
return [(family, socket.SOCK_STREAM, 6, '', (host, port))]
else:
......@@ -1662,8 +1659,7 @@ class EventLoopTestsMixin:
loop.add_writer(w, callback)
def test_close_running_event_loop(self):
@asyncio.coroutine
def close_loop(loop):
async def close_loop(loop):
self.loop.close()
coro = close_loop(self.loop)
......@@ -1673,8 +1669,7 @@ class EventLoopTestsMixin:
def test_close(self):
self.loop.close()
@asyncio.coroutine
def test():
async def test():
pass
func = lambda: False
......@@ -2142,7 +2137,8 @@ class HandleTests(test_utils.TestCase):
'<Handle cancelled>')
# decorated function
cb = asyncio.coroutine(noop)
with self.assertWarns(DeprecationWarning):
cb = asyncio.coroutine(noop)
h = asyncio.Handle(cb, (), self.loop)
self.assertEqual(repr(h),
'<Handle noop() at %s:%s>'
......
......@@ -44,10 +44,11 @@ class LockTests(test_utils.TestCase):
self.assertTrue(repr(lock).endswith('[unlocked]>'))
self.assertTrue(RGX_REPR.match(repr(lock)))
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
yield from lock
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
yield from lock
self.loop.run_until_complete(acquire_lock())
self.assertTrue(repr(lock).endswith('[locked]>'))
......@@ -56,10 +57,11 @@ class LockTests(test_utils.TestCase):
def test_lock(self):
lock = asyncio.Lock(loop=self.loop)
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
res = self.loop.run_until_complete(acquire_lock())
......@@ -79,17 +81,18 @@ class LockTests(test_utils.TestCase):
asyncio.BoundedSemaphore(loop=loop),
]
@asyncio.coroutine
def test(lock):
yield from asyncio.sleep(0.01)
self.assertFalse(lock.locked())
with self.assertWarns(DeprecationWarning):
with (yield from lock) as _lock:
self.assertIs(_lock, None)
self.assertTrue(lock.locked())
yield from asyncio.sleep(0.01)
self.assertTrue(lock.locked())
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def test(lock):
yield from asyncio.sleep(0.01)
self.assertFalse(lock.locked())
with self.assertWarns(DeprecationWarning):
with (yield from lock) as _lock:
self.assertIs(_lock, None)
self.assertTrue(lock.locked())
yield from asyncio.sleep(0.01)
self.assertTrue(lock.locked())
self.assertFalse(lock.locked())
for primitive in primitives:
loop.run_until_complete(test(primitive))
......@@ -290,10 +293,11 @@ class LockTests(test_utils.TestCase):
def test_context_manager(self):
lock = asyncio.Lock(loop=self.loop)
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
with self.loop.run_until_complete(acquire_lock()):
self.assertTrue(lock.locked())
......@@ -303,10 +307,11 @@ class LockTests(test_utils.TestCase):
def test_context_manager_cant_reuse(self):
lock = asyncio.Lock(loop=self.loop)
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from lock)
# This spells "yield from lock" outside a generator.
cm = self.loop.run_until_complete(acquire_lock())
......@@ -773,10 +778,11 @@ class ConditionTests(test_utils.TestCase):
def test_context_manager(self):
cond = asyncio.Condition(loop=self.loop)
@asyncio.coroutine
def acquire_cond():
with self.assertWarns(DeprecationWarning):
return (yield from cond)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_cond():
with self.assertWarns(DeprecationWarning):
return (yield from cond)
with self.loop.run_until_complete(acquire_cond()):
self.assertTrue(cond.locked())
......@@ -869,10 +875,11 @@ class SemaphoreTests(test_utils.TestCase):
sem = asyncio.Semaphore(loop=self.loop)
self.assertEqual(1, sem._value)
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from sem)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from sem)
res = self.loop.run_until_complete(acquire_lock())
......@@ -1012,10 +1019,11 @@ class SemaphoreTests(test_utils.TestCase):
def test_context_manager(self):
sem = asyncio.Semaphore(2, loop=self.loop)
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from sem)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def acquire_lock():
with self.assertWarns(DeprecationWarning):
return (yield from sem)
with self.loop.run_until_complete(acquire_lock()):
self.assertFalse(sem.locked())
......
......@@ -130,9 +130,10 @@ class CoroutineTests(BaseTest):
def __await__(self):
return ('spam',)
@asyncio.coroutine
def func():
return Awaitable()
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def func():
return Awaitable()
coro = func()
self.assertEqual(coro.send(None), 'spam')
......
......@@ -588,8 +588,7 @@ class StreamTests(test_utils.TestCase):
stream = asyncio.StreamReader(loop=self.loop,
_asyncio_internal=True)
@asyncio.coroutine
def set_err():
async def set_err():
stream.set_exception(ValueError())
t1 = asyncio.Task(stream.readline(), loop=self.loop)
......
This diff is collapsed.
......@@ -1708,9 +1708,8 @@ class AsyncIteratorWrapper(typing.AsyncIterator[T_a]):
def __aiter__(self) -> typing.AsyncIterator[T_a]:
return self
@asyncio.coroutine
def __anext__(self) -> T_a:
data = yield from self.value
async def __anext__(self) -> T_a:
data = await self.value
if data:
return data
else:
......
Deprecate ``@coroutine`` for sake of ``async def``.
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