Skip to content

Commit 68b34a7

Browse files
asvetlovmiss-islington
authored andcommitted
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
1 parent dbacfc2 commit 68b34a7

File tree

12 files changed

+311
-320
lines changed

12 files changed

+311
-320
lines changed

Doc/library/asyncio-task.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,12 +916,13 @@ enforced.
916916
async def main():
917917
await old_style_coroutine()
918918

919-
This decorator is **deprecated** and is scheduled for removal in
920-
Python 3.10.
921-
922919
This decorator should not be used for :keyword:`async def`
923920
coroutines.
924921

922+
.. deprecated-removed:: 3.8 3.10
923+
924+
Use :keyword:`async def` instead.
925+
925926
.. function:: iscoroutine(obj)
926927

927928
Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`.

Lib/asyncio/coroutines.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
import traceback
99
import types
10+
import warnings
1011

1112
from . import base_futures
1213
from . import constants
@@ -107,6 +108,9 @@ def coroutine(func):
107108
If the coroutine is not yielded from before it is destroyed,
108109
an error message is logged.
109110
"""
111+
warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
112+
DeprecationWarning,
113+
stacklevel=2)
110114
if inspect.iscoroutinefunction(func):
111115
# In Python 3.5 that's all we need to do for coroutines
112116
# defined with "async def".

Lib/asyncio/locks.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
__all__ = ('Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore')
44

55
import collections
6+
import types
67
import warnings
78

89
from . import events
910
from . import futures
1011
from . import exceptions
11-
from .coroutines import coroutine
12+
from .import coroutines
1213

1314

1415
class _ContextManager:
@@ -55,7 +56,7 @@ def __exit__(self, *args):
5556
# always raises; that's how the with-statement works.
5657
pass
5758

58-
@coroutine
59+
@types.coroutine
5960
def __iter__(self):
6061
# This is not a coroutine. It is meant to enable the idiom:
6162
#
@@ -78,6 +79,9 @@ def __iter__(self):
7879
yield from self.acquire()
7980
return _ContextManager(self)
8081

82+
# The flag is needed for legacy asyncio.iscoroutine()
83+
__iter__._is_coroutine = coroutines._is_coroutine
84+
8185
async def __acquire_ctx(self):
8286
await self.acquire()
8387
return _ContextManager(self)

Lib/asyncio/tasks.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from . import events
2424
from . import exceptions
2525
from . import futures
26-
from .coroutines import coroutine
26+
from .coroutines import _is_coroutine
2727

2828
# Helper to generate new task names
2929
# This uses itertools.count() instead of a "+= 1" operation because the latter
@@ -638,7 +638,7 @@ def ensure_future(coro_or_future, *, loop=None):
638638
'required')
639639

640640

641-
@coroutine
641+
@types.coroutine
642642
def _wrap_awaitable(awaitable):
643643
"""Helper for asyncio.ensure_future().
644644
@@ -647,6 +647,8 @@ def _wrap_awaitable(awaitable):
647647
"""
648648
return (yield from awaitable.__await__())
649649

650+
_wrap_awaitable._is_coroutine = _is_coroutine
651+
650652

651653
class _GatheringFuture(futures.Future):
652654
"""Helper for gather().

Lib/test/test_asyncio/test_base_events.py

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,8 @@ def zero_error(fut):
575575
def test_default_exc_handler_coro(self):
576576
self.loop._process_events = mock.Mock()
577577

578-
@asyncio.coroutine
579-
def zero_error_coro():
580-
yield from asyncio.sleep(0.01)
578+
async def zero_error_coro():
579+
await asyncio.sleep(0.01)
581580
1/0
582581

583582
# Test Future.__del__
@@ -723,8 +722,7 @@ def test_set_task_factory(self):
723722
class MyTask(asyncio.Task):
724723
pass
725724

726-
@asyncio.coroutine
727-
def coro():
725+
async def coro():
728726
pass
729727

730728
factory = lambda loop, coro: MyTask(coro, loop=loop)
@@ -779,8 +777,7 @@ def test_create_task(self):
779777
class MyTask(asyncio.Task):
780778
pass
781779

782-
@asyncio.coroutine
783-
def test():
780+
async def test():
784781
pass
785782

786783
class EventLoop(base_events.BaseEventLoop):
@@ -830,8 +827,7 @@ def test_run_forever_keyboard_interrupt(self):
830827
# Python issue #22601: ensure that the temporary task created by
831828
# run_forever() consumes the KeyboardInterrupt and so don't log
832829
# a warning
833-
@asyncio.coroutine
834-
def raise_keyboard_interrupt():
830+
async def raise_keyboard_interrupt():
835831
raise KeyboardInterrupt
836832

837833
self.loop._process_events = mock.Mock()
@@ -849,8 +845,7 @@ def raise_keyboard_interrupt():
849845
def test_run_until_complete_baseexception(self):
850846
# Python issue #22429: run_until_complete() must not schedule a pending
851847
# call to stop() if the future raised a BaseException
852-
@asyncio.coroutine
853-
def raise_keyboard_interrupt():
848+
async def raise_keyboard_interrupt():
854849
raise KeyboardInterrupt
855850

856851
self.loop._process_events = mock.Mock()
@@ -1070,9 +1065,7 @@ def test_create_connection_multiple_errors(self, m_socket):
10701065
class MyProto(asyncio.Protocol):
10711066
pass
10721067

1073-
@asyncio.coroutine
1074-
def getaddrinfo(*args, **kw):
1075-
yield from []
1068+
async def getaddrinfo(*args, **kw):
10761069
return [(2, 1, 6, '', ('107.6.106.82', 80)),
10771070
(2, 1, 6, '', ('107.6.106.82', 80))]
10781071

@@ -1191,9 +1184,8 @@ def test_create_connection_no_host_port_sock(self):
11911184
self.assertRaises(ValueError, self.loop.run_until_complete, coro)
11921185

11931186
def test_create_connection_no_getaddrinfo(self):
1194-
@asyncio.coroutine
1195-
def getaddrinfo(*args, **kw):
1196-
yield from []
1187+
async def getaddrinfo(*args, **kw):
1188+
return []
11971189

11981190
def getaddrinfo_task(*args, **kwds):
11991191
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
@@ -1219,8 +1211,7 @@ def getaddrinfo_task(*args, **kwds):
12191211
OSError, self.loop.run_until_complete, coro)
12201212

12211213
def test_create_connection_multiple(self):
1222-
@asyncio.coroutine
1223-
def getaddrinfo(*args, **kw):
1214+
async def getaddrinfo(*args, **kw):
12241215
return [(2, 1, 6, '', ('0.0.0.1', 80)),
12251216
(2, 1, 6, '', ('0.0.0.2', 80))]
12261217

@@ -1247,8 +1238,7 @@ def bind(addr):
12471238

12481239
m_socket.socket.return_value.bind = bind
12491240

1250-
@asyncio.coroutine
1251-
def getaddrinfo(*args, **kw):
1241+
async def getaddrinfo(*args, **kw):
12521242
return [(2, 1, 6, '', ('0.0.0.1', 80)),
12531243
(2, 1, 6, '', ('0.0.0.2', 80))]
12541244

@@ -1349,8 +1339,7 @@ def test_create_connection_service_name(self, m_socket):
13491339
self.loop.run_until_complete(coro)
13501340

13511341
def test_create_connection_no_local_addr(self):
1352-
@asyncio.coroutine
1353-
def getaddrinfo(host, *args, **kw):
1342+
async def getaddrinfo(host, *args, **kw):
13541343
if host == 'example.com':
13551344
return [(2, 1, 6, '', ('107.6.106.82', 80)),
13561345
(2, 1, 6, '', ('107.6.106.82', 80))]
@@ -1488,11 +1477,10 @@ def test_create_server_empty_host(self):
14881477
# if host is empty string use None instead
14891478
host = object()
14901479

1491-
@asyncio.coroutine
1492-
def getaddrinfo(*args, **kw):
1480+
async def getaddrinfo(*args, **kw):
14931481
nonlocal host
14941482
host = args[0]
1495-
yield from []
1483+
return []
14961484

14971485
def getaddrinfo_task(*args, **kwds):
14981486
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
@@ -1854,9 +1842,10 @@ def test_accept_connection_exception(self, m_log):
18541842
MyProto, sock, None, None, mock.ANY, mock.ANY)
18551843

18561844
def test_call_coroutine(self):
1857-
@asyncio.coroutine
1858-
def simple_coroutine():
1859-
pass
1845+
with self.assertWarns(DeprecationWarning):
1846+
@asyncio.coroutine
1847+
def simple_coroutine():
1848+
pass
18601849

18611850
self.loop.set_debug(True)
18621851
coro_func = simple_coroutine
@@ -1880,9 +1869,7 @@ def test_log_slow_callbacks(self, m_logger):
18801869
def stop_loop_cb(loop):
18811870
loop.stop()
18821871

1883-
@asyncio.coroutine
1884-
def stop_loop_coro(loop):
1885-
yield from ()
1872+
async def stop_loop_coro(loop):
18861873
loop.stop()
18871874

18881875
asyncio.set_event_loop(self.loop)
@@ -1909,8 +1896,7 @@ def stop_loop_coro(loop):
19091896
class RunningLoopTests(unittest.TestCase):
19101897

19111898
def test_running_loop_within_a_loop(self):
1912-
@asyncio.coroutine
1913-
def runner(loop):
1899+
async def runner(loop):
19141900
loop.run_forever()
19151901

19161902
loop = asyncio.new_event_loop()

Lib/test/test_asyncio/test_events.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,10 @@ def tearDown(self):
253253
super().tearDown()
254254

255255
def test_run_until_complete_nesting(self):
256-
@asyncio.coroutine
257-
def coro1():
258-
yield
256+
async def coro1():
257+
await asyncio.sleep(0)
259258

260-
@asyncio.coroutine
261-
def coro2():
259+
async def coro2():
262260
self.assertTrue(self.loop.is_running())
263261
self.loop.run_until_complete(coro1())
264262

@@ -735,8 +733,7 @@ def test_connect_accepted_socket_ssl_timeout_for_plain_socket(self):
735733

736734
@mock.patch('asyncio.base_events.socket')
737735
def create_server_multiple_hosts(self, family, hosts, mock_sock):
738-
@asyncio.coroutine
739-
def getaddrinfo(host, port, *args, **kw):
736+
async def getaddrinfo(host, port, *args, **kw):
740737
if family == socket.AF_INET:
741738
return [(family, socket.SOCK_STREAM, 6, '', (host, port))]
742739
else:
@@ -1662,8 +1659,7 @@ def test_add_fds_after_closing(self):
16621659
loop.add_writer(w, callback)
16631660

16641661
def test_close_running_event_loop(self):
1665-
@asyncio.coroutine
1666-
def close_loop(loop):
1662+
async def close_loop(loop):
16671663
self.loop.close()
16681664

16691665
coro = close_loop(self.loop)
@@ -1673,8 +1669,7 @@ def close_loop(loop):
16731669
def test_close(self):
16741670
self.loop.close()
16751671

1676-
@asyncio.coroutine
1677-
def test():
1672+
async def test():
16781673
pass
16791674

16801675
func = lambda: False
@@ -2142,7 +2137,8 @@ def test_handle_repr(self):
21422137
'<Handle cancelled>')
21432138

21442139
# decorated function
2145-
cb = asyncio.coroutine(noop)
2140+
with self.assertWarns(DeprecationWarning):
2141+
cb = asyncio.coroutine(noop)
21462142
h = asyncio.Handle(cb, (), self.loop)
21472143
self.assertEqual(repr(h),
21482144
'<Handle noop() at %s:%s>'

0 commit comments

Comments
 (0)