8000 bpo-43216: Remove @asyncio.coroutine · python/cpython@4e037da · GitHub
[go: up one dir, main page]

Skip to content

Commit 4e037da

Browse files
committed
bpo-43216: Remove @asyncio.coroutine
1 parent d18e5da commit 4e037da

File tree

11 files changed

+86
-610
lines changed

11 files changed

+86
-610
lines changed

Doc/library/asyncio-task.rst

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,6 @@ other coroutines::
138138

139139
asyncio.run(main())
140140

141-
.. important::
142-
143-
In this documentation the term "coroutine" can be used for
144-
two closely related concepts:
145-
146-
* a *coroutine function*: an :keyword:`async def` function;
147-
148-
* a *coroutine object*: an object returned by calling a
149-
*coroutine function*.
150-
151-
asyncio also supports legacy :ref:`generator-based
152-
<asyncio_generator_based_coro>` coroutines.
153-
154141

155142
.. rubric:: Tasks
156143

@@ -973,60 +960,3 @@ Task Object
973960
in the :func:`repr` output of a task object.
974961

975962
.. versionadded:: 3.8
976-
977-
978-
.. _asyncio_generator_based_coro:
979-
980-
Generator-based Coroutines
981-
==========================
982-
983-
.. note::
984-
985-
Support for generator-based coroutines is **deprecated** and
986-
is scheduled for removal in Python 3.10.
987-
988-
Generator-based coroutines predate async/await syntax. They are
989-
Python generators that use ``yield from`` expressions to await
990-
on Futures and other coroutines.
991-
992-
Generator-based coroutines should be decorated with
993-
:func:`@asyncio.coroutine <asyncio.coroutine>`, although this is not
994-
enforced.
995-
996-
997-
.. decorator:: coroutine
998-
999-
Decorator to mark generator-based coroutines.
1000-
1001-
This decorator enables legacy generator-based coroutines to be
1002-
compatible with async/await code::
1003-
1004-
@asyncio.coroutine
1005-
def old_style_coroutine():
1006-
yield from asyncio.sleep(1)
1007-
1008-
async def main():
1009-
await old_style_coroutine()
1010-
1011-
This decorator should not be used for :keyword:`async def`
1012-
coroutines.
1013-
1014-
.. deprecated-removed:: 3.8 3.10
1015-
1016-
Use :keyword:`async def` instead.
1017-
1018-
.. function:: iscoroutine(obj)
1019-
1020-
Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`.
1021-
1022-
This method is different from :func:`inspect.iscoroutine` because
1023-
it returns ``True`` for generator-based coroutines.
1024-
1025-
.. function:: iscoroutinefunction(func)
1026-
1027-
Return ``True`` if *func* is a :ref:`coroutine function
1028-
<coroutine>`.
1029-
1030-
This method is different from :func:`inspect.iscoroutinefunction`
1031-
because it returns ``True`` for generator-based coroutine functions
1032-
decorated with :func:`@coroutine <coroutine>`.

Doc/library/collections.abc.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ ABC Inherits from Abstract Methods Mixin
198198

199199
.. note::
200200
In CPython, generator-based coroutines (generators decorated with
201-
:func:`types.coroutine` or :func:`asyncio.coroutine`) are
201+
:func:`types.coroutine`) are
202202
*awaitables*, even though they do not have an :meth:`__await__` method.
203203
Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``.
204204
Use :func:`inspect.isawaitable` to detect them.
@@ -216,7 +216,7 @@ ABC Inherits from Abstract Methods Mixin
216216

217217
.. note::
218218
In CPython, generator-based coroutines (generators decorated with
219-
:func:`types.coroutine` or :func:`asyncio.coroutine`) are
219+
:func:`types.coroutine`) are
220220
*awaitables*, even though they do not have an :meth:`__await__` method.
221221
Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``.
222222
Use :func:`inspect.isawaitable` to detect them.

Doc/reference/datamodel.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2714,7 +2714,7 @@ are awaitable.
27142714
.. note::
27152715

27162716
The :term:`generator iterator` objects returned from generators
2717-
decorated with :func:`types.coroutine` or :func:`asyncio.coroutine`
2717+
decorated with :func:`types.coroutine`
27182718
are also awaitable, but they do not implement :meth:`__await__`.
27192719

27202720
.. method:: object.__await__(self)

Doc/whatsnew/3.11.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ Deprecated
126126
Removed
127127
=======
128128

129+
* The :func:`asyncio.coroutine` :term:`decorator` enabling legacy
130+
generator-based coroutines to be compatible with async/await code.
131+
Use :keyword:`async def` instead.
132+
(Contributed by Illia Volochii in :issue:`43216`.)
129133

130134

131135
Porting to Python 3.11

Lib/asyncio/coroutines.py

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
__all__ = 'coroutine', 'iscoroutinefunction', 'iscoroutine'
1+
__all__ = 'iscoroutinefunction', 'iscoroutine'
22

33
import collections.abc
4-
import functools
54
import inspect
65
import os
76
import sys
87
import traceback
98
import types
10-
import warnings
119

12-
from . import base_futures
1310
from . import constants
1411
from . import format_helpers
1512
from .log import logger
@@ -30,9 +27,6 @@ def _is_debug_mode():
3027
bool(os.environ.get('PYTHONASYNCIODEBUG')))
3128

3229

33-
_DEBUG = _is_debug_mode()
34-
35-
3630
class CoroWrapper:
3731
# Wrapper for coroutine object in _DEBUG mode.
3832

@@ -102,61 +96,6 @@ def __del__(self):
10296
logger.error(msg)
10397

10498

105-
def coroutine(func):
106-
"""Decorator to mark coroutines.
107-
108-
If the coroutine is not yielded from before it is destroyed,
109-
an error message is logged.
110-
"""
111-
warnings.warn('"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
112-
DeprecationWarning,
113-
stacklevel=2)
114-
if inspect.iscoroutinefunction(func):
115-
# In Python 3.5 that's all we need to do for coroutines
116-
# defined with "async def".
117-
return func
118-
119-
if inspect.isgeneratorfunction(func):
120-
coro = func
121-
else:
122-
@functools.wraps(func)
123-
def coro(*args, **kw):
124-
res = func(*args, **kw)
125-
if (base_futures.isfuture(res) or inspect.isgenerator(res) or
126-
isinstance(res, CoroWrapper)):
127-
res = yield from res
128-
else:
129-
# If 'res' is an awaitable, run it.
130-
try:
131-
await_meth = res.__await__
132-
except AttributeError:
133-
pass
134-
else:
135-
if isinstance(res, collections.abc.Awaitable):
136-
res = yield from await_meth()
137-
return res
138-
139-
coro = types.coroutine(coro)
140-
if not _DEBUG:
141-
wrapper = coro
142-
else:
143-
@functools.wraps(func)
144-
def wrapper(*args, **kwds):
145-
w = CoroWrapper(coro(*args, **kwds), func=func)
146-
if w._source_traceback:
147-
del w._source_traceback[-1]
148-
# Python < 3.5 does not implement __qualname__
149-
# on generator objects, so we set it manually.
150-
# We use getattr as some callables (such as
151-
# functools.partial may lack __qualname__).
152-
w.__name__ = getattr(func, '__name__', None)
153-
w.__qualname__ = getattr(func, '__qualname__', None)
154-
return w
155-
156-
wrapper._is_coroutine = _is_coroutine # For iscoroutinefunction().
157-
return wrapper
158-
159-
16099
# A marker for iscoroutinefunction.
161100
_is_coroutine = object()
162101

Lib/test/test_asyncio/test_base_events.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,10 +1884,8 @@ def test_accept_connection_exception(self, m_log):
18841884
MyProto, sock, None, None, mock.ANY, mock.ANY)
18851885

18861886
def test_call_coroutine(self):
1887-
with self.assertWarns(DeprecationWarning):
1888-
@asyncio.coroutine
1889-
def simple_coroutine():
1890-
pass
1887+
async def simple_coroutine():
1888+
pass
18911889

18921890
self.loop.set_debug(True)
18931891
coro_func = simple_coroutine

Lib/test/test_asyncio/test_events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import sys
1818
import threading
1919
import time
20+
import types
2021
import errno
2122
import unittest
2223
from unittest import mock
@@ -2163,8 +2164,7 @@ def test_handle_repr(self):
21632164
'<Handle cancelled>')
21642165

21652166
# decorated function
2166-
with self.assertWarns(DeprecationWarning):
2167-
cb = asyncio.coroutine(noop)
2167+
cb = types.coroutine(noop)
21682168
h = asyncio.Handle(cb, (), self.loop)
21692169
self.assertEqual(repr(h),
21702170
'<Handle noop() at %s:%s>'

Lib/test/test_asyncio/test_locks.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,12 @@ def test_repr(self):
3838
def test_lock(self):
3939
lock = asyncio.Lock()
4040

41-
with self.assertWarns(DeprecationWarning):
42-
@asyncio.coroutine
43-
def acquire_lock():
44-
return (yield from lock)
41+
async def acquire_lock():
42+
return await lock
4543

4644
with self.assertRaisesRegex(
4745
TypeError,
48-
"object is not iterable"
46+
"object Lock can't be used in 'await' expression"
4947
):
5048
self.loop.run_until_complete(acquire_lock())
5149

@@ -78,18 +76,16 @@ def test_lock_by_with_statement(self):
7876
asyncio.BoundedSemaphore(),
7977
]
8078

81-
with self.assertWarns(DeprecationWarning):
82-
@asyncio.coroutine
83-
def test(lock):
84-
yield from asyncio.sleep(0.01)
85-
self.assertFalse(lock.locked())
86-
with self.assertRaisesRegex(
87-
TypeError,
88-
"object is not iterable"
89-
):
90-
with (yield from lock):
91-
pass
92-
self.assertFalse(lock.locked())
79+
async def test(lock):
80+
await asyncio.sleep(0.01)
81+
self.assertFalse(lock.locked())
82+
with self.assertRaisesRegex(
83+
TypeError,
84+
r"object \w+ can't be used in 'await' expression"
85+
):
86+
with await lock:
87+
pass
88+
self.assertFalse(lock.locked())
9389

9490
for primitive in primitives:
9591
loop.run_until_complete(test(primitive))
@@ -788,14 +784,12 @@ def test_semaphore(self):
788784
sem = asyncio.Semaphore()
789785
self.assertEqual(1, sem._value)
790786

791-
with self.assertWarns(DeprecationWarning):
792-
@asyncio.coroutine
793-
def acquire_lock():
794-
return (yield from sem)
787+
async def acquire_lock():
788+
return await sem
795789

796790
with self.assertRaisesRegex(
797791
TypeError,
798-
"'Semaphore' object is not iterable",
792+
"object Semaphore can't be used in 'await' expression",
799793
):
800794
self.loop.run_until_complete(acquire_lock())
801795

Lib/test/test_asyncio/test_pep492.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,6 @@ def test_iscoroutinefunction(self):
123123
async def foo(): pass
124124
self.assertTrue(asyncio.iscoroutinefunction(foo))
125125

126-
def test_function_returning_awaitable(self):
127-
class Awaitable:
128-
def __await__(self):
129-
return ('spam',)
130-
131-
with self.assertWarns(DeprecationWarning):
132-
@asyncio.coroutine
133-
def func():
134-
return Awaitable()
135-
136-
coro = func()
137-
self.assertEqual(coro.send(None), 'spam')
138-
coro.close()
139-
140126
def test_async_def_coroutines(self):
141127
async def bar():
142128
return 'spam'

0 commit comments

Comments
 (0)
0