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
This commit is contained in:
Andrew Svetlov 2019-05-16 17:52:10 +03:00 committed by Miss Islington (bot)
parent dbacfc2273
commit 68b34a7204
12 changed files with 311 additions and 320 deletions

View file

@ -28,8 +28,7 @@ def tearDownModule():
asyncio.set_event_loop_policy(None)
@asyncio.coroutine
def coroutine_function():
async def coroutine_function():
pass
@ -103,8 +102,7 @@ class BaseTaskTests:
def __del__(self):
gc.collect()
@asyncio.coroutine
def run():
async def run():
return Evil()
self.loop.run_until_complete(
@ -138,8 +136,7 @@ class BaseTaskTests:
self.loop.run_until_complete(task)
def test_task_class(self):
@asyncio.coroutine
def notmuch():
async def notmuch():
return 'ok'
t = self.new_task(self.loop, notmuch())
self.loop.run_until_complete(t)
@ -156,9 +153,10 @@ class BaseTaskTests:
loop.close()
def test_ensure_future_coroutine(self):
@asyncio.coroutine
def notmuch():
return 'ok'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def notmuch():
return 'ok'
t = asyncio.ensure_future(notmuch(), loop=self.loop)
self.loop.run_until_complete(t)
self.assertTrue(t.done())
@ -194,8 +192,7 @@ class BaseTaskTests:
self.assertIs(f, f_orig)
def test_ensure_future_task(self):
@asyncio.coroutine
def notmuch():
async def notmuch():
return 'ok'
t_orig = self.new_task(self.loop, notmuch())
t = asyncio.ensure_future(t_orig)
@ -222,9 +219,10 @@ class BaseTaskTests:
def __await__(self):
return (yield from self.coro)
@asyncio.coroutine
def coro():
return 'ok'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
return 'ok'
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
@ -276,9 +274,7 @@ class BaseTaskTests:
def test_task_repr(self):
self.loop.set_debug(False)
@asyncio.coroutine
def notmuch():
yield from []
async def notmuch():
return 'abc'
# test coroutine function
@ -327,8 +323,7 @@ class BaseTaskTests:
"<Task finished name='TestTask' %s result='abc'>" % coro)
def test_task_repr_autogenerated(self):
@asyncio.coroutine
def notmuch():
async def notmuch():
return 123
t1 = self.new_task(self.loop, notmuch(), None)
@ -346,8 +341,7 @@ class BaseTaskTests:
self.loop.run_until_complete(t2)
def test_task_repr_name_not_str(self):
@asyncio.coroutine
def notmuch():
async def notmuch():
return 123
t = self.new_task(self.loop, notmuch())
@ -358,11 +352,12 @@ class BaseTaskTests:
def test_task_repr_coro_decorator(self):
self.loop.set_debug(False)
@asyncio.coroutine
def notmuch():
# notmuch() function doesn't use yield from: it will be wrapped by
# @coroutine decorator
return 123
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def notmuch():
# notmuch() function doesn't use yield from: it will be wrapped by
# @coroutine decorator
return 123
# test coroutine function
self.assertEqual(notmuch.__name__, 'notmuch')
@ -440,7 +435,8 @@ class BaseTaskTests:
async def func(x, y):
await asyncio.sleep(0)
partial_func = asyncio.coroutine(functools.partial(func, 1))
with self.assertWarns(DeprecationWarning):
partial_func = asyncio.coroutine(functools.partial(func, 1))
task = self.loop.create_task(partial_func(2))
# make warnings quiet
@ -492,11 +488,12 @@ class BaseTaskTests:
self.assertFalse(t.cancel())
def test_cancel_yield(self):
@asyncio.coroutine
def task():
yield
yield
return 12
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def task():
yield
yield
return 12
t = self.new_task(self.loop, task())
test_utils.run_briefly(self.loop) # start coro
@ -618,8 +615,7 @@ class BaseTaskTests:
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
@asyncio.coroutine
def task():
async def task():
t.cancel()
self.assertTrue(t._must_cancel) # White-box test.
return 12
@ -736,8 +732,7 @@ class BaseTaskTests:
foo_started = False
@asyncio.coroutine
def foo():
async def foo():
nonlocal foo_started
foo_started = True
@ -814,8 +809,7 @@ class BaseTaskTests:
def test_wait_for_blocking(self):
loop = self.new_test_loop()
@asyncio.coroutine
def coro():
async def coro():
return 'done'
res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None))
@ -976,9 +970,10 @@ class BaseTaskTests:
def test_wait_duplicate_coroutines(self):
@asyncio.coroutine
def coro(s):
return s
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro(s):
return s
c = coro('test')
task =self.new_task(
@ -1036,14 +1031,12 @@ class BaseTaskTests:
# there is possibility that some tasks in the pending list
# became done but their callbacks haven't all been called yet
@asyncio.coroutine
def coro1():
yield
async def coro1():
await asyncio.sleep(0)
@asyncio.coroutine
def coro2():
yield
yield
async def coro2():
await asyncio.sleep(0)
await asyncio.sleep(0)
a = self.new_task(self.loop, coro1())
b = self.new_task(self.loop, coro2())
@ -1070,8 +1063,7 @@ class BaseTaskTests:
# first_exception, task already has exception
a = self.new_task(loop, asyncio.sleep(10.0))
@asyncio.coroutine
def exc():
async def exc():
raise ZeroDivisionError('err')
b = self.new_task(loop, exc())
@ -1131,9 +1123,8 @@ class BaseTaskTests:
a = self.new_task(loop, asyncio.sleep(0.1))
@asyncio.coroutine
def sleeper():
yield from asyncio.sleep(0.15)
async def sleeper():
await asyncio.sleep(0.15)
raise ZeroDivisionError('really')
b = self.new_task(loop, sleeper())
@ -1220,25 +1211,25 @@ class BaseTaskTests:
completed = set()
time_shifted = False
@asyncio.coroutine
def sleeper(dt, x):
nonlocal time_shifted
yield from asyncio.sleep(dt)
completed.add(x)
if not time_shifted and 'a' in completed and 'b' in completed:
time_shifted = True
loop.advance_time(0.14)
return x
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def sleeper(dt, x):
nonlocal time_shifted
yield from asyncio.sleep(dt)
completed.add(x)
if not time_shifted and 'a' in completed and 'b' in completed:
time_shifted = True
loop.advance_time(0.14)
return x
a = sleeper(0.01, 'a')
b = sleeper(0.01, 'b')
c = sleeper(0.15, 'c')
@asyncio.coroutine
def foo():
async def foo():
values = []
for f in asyncio.as_completed([b, c, a], loop=loop):
values.append((yield from f))
values.append(await f)
return values
res = loop.run_until_complete(self.new_task(loop, foo()))
@ -1350,18 +1341,20 @@ class BaseTaskTests:
def test_as_completed_duplicate_coroutines(self):
@asyncio.coroutine
def coro(s):
return s
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro(s):
return s
@asyncio.coroutine
def runner():
result = []
c = coro('ham')
for f in asyncio.as_completed([c, c, coro('spam')],
loop=self.loop):
result.append((yield from f))
return result
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def runner():
result = []
c = coro('ham')
for f in asyncio.as_completed([c, c, coro('spam')],
loop=self.loop):
result.append((yield from f))
return result
fut = self.new_task(self.loop, runner())
self.loop.run_until_complete(fut)
@ -1380,10 +1373,9 @@ class BaseTaskTests:
loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleeper(dt, arg):
yield from asyncio.sleep(dt/2)
res = yield from asyncio.sleep(dt/2, arg)
async def sleeper(dt, arg):
await asyncio.sleep(dt/2)
res = await asyncio.sleep(dt/2, arg)
return res
t = self.new_task(loop, sleeper(0.1, 'yeah'))
@ -1431,16 +1423,14 @@ class BaseTaskTests:
loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleep(dt):
yield from asyncio.sleep(dt)
async def sleep(dt):
await asyncio.sleep(dt)
@asyncio.coroutine
def doit():
async def doit():
sleeper = self.new_task(loop, sleep(5000))
loop.call_later(0.1, sleeper.cancel)
try:
yield from sleeper
await sleeper
except asyncio.CancelledError:
return 'cancelled'
else:
@ -1453,9 +1443,8 @@ class BaseTaskTests:
def test_task_cancel_waiter_future(self):
fut = self.new_future(self.loop)
@asyncio.coroutine
def coro():
yield from fut
async def coro():
await fut
task = self.new_task(self.loop, coro())
test_utils.run_briefly(self.loop)
@ -1469,8 +1458,7 @@ class BaseTaskTests:
self.assertTrue(fut.cancelled())
def test_task_set_methods(self):
@asyncio.coroutine
def notmuch():
async def notmuch():
return 'ko'
gen = notmuch()
@ -1487,11 +1475,12 @@ class BaseTaskTests:
'ko')
def test_step_result(self):
@asyncio.coroutine
def notmuch():
yield None
yield 1
return 'ko'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def notmuch():
yield None
yield 1
return 'ko'
self.assertRaises(
RuntimeError, self.loop.run_until_complete, notmuch())
@ -1511,10 +1500,9 @@ class BaseTaskTests:
fut = Fut(loop=self.loop)
result = None
@asyncio.coroutine
def wait_for_future():
async def wait_for_future():
nonlocal result
result = yield from fut
result = await fut
t = self.new_task(self.loop, wait_for_future())
test_utils.run_briefly(self.loop)
@ -1536,16 +1524,14 @@ class BaseTaskTests:
loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleeper():
yield from asyncio.sleep(10)
async def sleeper():
await asyncio.sleep(10)
base_exc = BaseException()
@asyncio.coroutine
def notmutch():
async def notmutch():
try:
yield from sleeper()
await sleeper()
except asyncio.CancelledError:
raise base_exc
@ -1571,9 +1557,10 @@ class BaseTaskTests:
yield
self.assertFalse(asyncio.iscoroutinefunction(fn1))
@asyncio.coroutine
def fn2():
yield
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def fn2():
yield
self.assertTrue(asyncio.iscoroutinefunction(fn2))
self.assertFalse(asyncio.iscoroutinefunction(mock.Mock()))
@ -1581,9 +1568,10 @@ class BaseTaskTests:
def test_yield_vs_yield_from(self):
fut = self.new_future(self.loop)
@asyncio.coroutine
def wait_for_future():
yield fut
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def wait_for_future():
yield fut
task = wait_for_future()
with self.assertRaises(RuntimeError):
@ -1592,17 +1580,19 @@ class BaseTaskTests:
self.assertFalse(fut.done())
def test_yield_vs_yield_from_generator(self):
@asyncio.coroutine
def coro():
yield
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
yield
@asyncio.coroutine
def wait_for_future():
gen = coro()
try:
yield gen
finally:
gen.close()
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def wait_for_future():
gen = coro()
try:
yield gen
finally:
gen.close()
task = wait_for_future()
self.assertRaises(
@ -1610,9 +1600,10 @@ class BaseTaskTests:
self.loop.run_until_complete, task)
def test_coroutine_non_gen_function(self):
@asyncio.coroutine
def func():
return 'test'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def func():
return 'test'
self.assertTrue(asyncio.iscoroutinefunction(func))
@ -1625,12 +1616,12 @@ class BaseTaskTests:
def test_coroutine_non_gen_function_return_future(self):
fut = self.new_future(self.loop)
@asyncio.coroutine
def func():
return fut
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def func():
return fut
@asyncio.coroutine
def coro():
async def coro():
fut.set_result('test')
t1 = self.new_task(self.loop, func())
@ -1887,11 +1878,12 @@ class BaseTaskTests:
# A function that asserts various things.
# Called twice, with different debug flag values.
@asyncio.coroutine
def coro():
# The actual coroutine.
self.assertTrue(gen.gi_running)
yield from fut
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
# The actual coroutine.
self.assertTrue(gen.gi_running)
yield from fut
# A completed Future used to run the coroutine.
fut = self.new_future(self.loop)
@ -1922,19 +1914,22 @@ class BaseTaskTests:
def test_yield_from_corowrapper(self):
with set_coroutine_debug(True):
@asyncio.coroutine
def t1():
return (yield from t2())
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def t1():
return (yield from t2())
@asyncio.coroutine
def t2():
f = self.new_future(self.loop)
self.new_task(self.loop, t3(f))
return (yield from f)
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def t2():
f = self.new_future(self.loop)
self.new_task(self.loop, t3(f))
return (yield from f)
@asyncio.coroutine
def t3(f):
f.set_result((1, 2, 3))
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def t3(f):
f.set_result((1, 2, 3))
task = self.new_task(self.loop, t1())
val = self.loop.run_until_complete(task)
@ -2009,13 +2004,14 @@ class BaseTaskTests:
def test_log_destroyed_pending_task(self):
Task = self.__class__.Task
@asyncio.coroutine
def kill_me(loop):
future = self.new_future(loop)
yield from future
# at this point, the only reference to kill_me() task is
# the Task._wakeup() method in future._callbacks
raise Exception("code never reached")
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def kill_me(loop):
future = self.new_future(loop)
yield from future
# at this point, the only reference to kill_me() task is
# the Task._wakeup() method in future._callbacks
raise Exception("code never reached")
mock_handler = mock.Mock()
self.loop.set_debug(True)
@ -2064,14 +2060,12 @@ class BaseTaskTests:
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
@asyncio.coroutine
def coro():
async def coro():
raise TypeError
@asyncio.coroutine
def runner():
async def runner():
task = self.new_task(loop, coro())
yield from asyncio.sleep(0.05)
await asyncio.sleep(0.05)
task.cancel()
task = None
@ -2081,9 +2075,10 @@ class BaseTaskTests:
@mock.patch('asyncio.coroutines.logger')
def test_coroutine_never_yielded(self, m_log):
with set_coroutine_debug(True):
@asyncio.coroutine
def coro_noop():
pass
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro_noop():
pass
tb_filename = __file__
tb_lineno = sys._getframe().f_lineno + 2
@ -2112,13 +2107,15 @@ class BaseTaskTests:
from @asyncio.coroutine()-wrapped function should have same effect as
returning generator object or Future."""
def check():
@asyncio.coroutine
def outer_coro():
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def inner_coro():
return 1
def outer_coro():
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def inner_coro():
return 1
return inner_coro()
return inner_coro()
result = self.loop.run_until_complete(outer_coro())
self.assertEqual(result, 1)
@ -2147,11 +2144,10 @@ class BaseTaskTests:
loop = asyncio.new_event_loop()
self.addCleanup(loop.close)
@asyncio.coroutine
def blocking_coroutine():
async def blocking_coroutine():
fut = self.new_future(loop)
# Block: fut result is never set
yield from fut
await fut
task = loop.create_task(blocking_coroutine())
@ -2230,14 +2226,12 @@ class BaseTaskTests:
def test_exception_traceback(self):
# See http://bugs.python.org/issue28843
@asyncio.coroutine
def foo():
async def foo():
1 / 0
@asyncio.coroutine
def main():
async def main():
task = self.new_task(self.loop, foo())
yield # skip one loop iteration
await asyncio.sleep(0) # skip one loop iteration
self.assertIsNotNone(task.exception().__traceback__)
self.loop.run_until_complete(main())
@ -2248,9 +2242,10 @@ class BaseTaskTests:
raise ValueError
self.loop.call_soon = call_soon
@asyncio.coroutine
def coro():
pass
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
pass
self.assertFalse(m_log.error.called)
@ -2280,9 +2275,10 @@ class BaseTaskTests:
def test_create_task_with_oldstyle_coroutine(self):
@asyncio.coroutine
def coro():
pass
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
pass
task = self.new_task(self.loop, coro())
self.assertIsInstance(task, self.Task)
@ -2553,8 +2549,7 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest,
@support.refcount_test
def test_refleaks_in_task___init__(self):
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
@asyncio.coroutine
def coro():
async def coro():
pass
task = self.new_task(self.loop, coro())
self.loop.run_until_complete(task)
@ -2565,8 +2560,7 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest,
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
def test_del__log_destroy_pending_segfault(self):
@asyncio.coroutine
def coro():
async def coro():
pass
task = self.new_task(self.loop, coro())
self.loop.run_until_complete(task)
@ -3054,15 +3048,13 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase):
def wrap_futures(self, *futures):
coros = []
for fut in futures:
@asyncio.coroutine
def coro(fut=fut):
return (yield from fut)
async def coro(fut=fut):
return await fut
coros.append(coro())
return coros
def test_constructor_loop_selection(self):
@asyncio.coroutine
def coro():
async def coro():
return 'abc'
gen1 = coro()
gen2 = coro()
@ -3078,9 +3070,10 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase):
self.other_loop.run_until_complete(fut2)
def test_duplicate_coroutines(self):
@asyncio.coroutine
def coro(s):
return s
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro(s):
return s
c = coro('abc')
fut = asyncio.gather(c, c, coro('def'), c, loop=self.one_loop)
self._run_loop(self.one_loop)
@ -3091,21 +3084,19 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase):
proof = 0
waiter = asyncio.Future(loop=self.one_loop)
@asyncio.coroutine
def inner():
async def inner():
nonlocal proof
yield from waiter
await waiter
proof += 1
child1 = asyncio.ensure_future(inner(), loop=self.one_loop)
child2 = asyncio.ensure_future(inner(), loop=self.one_loop)
gatherer = None
@asyncio.coroutine
def outer():
async def outer():
nonlocal proof, gatherer
gatherer = asyncio.gather(child1, child2, loop=self.one_loop)
yield from gatherer
await gatherer
proof += 100
f = asyncio.ensure_future(outer(), loop=self.one_loop)
@ -3123,17 +3114,15 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase):
def test_exception_marking(self):
# Test for the first line marked "Mark exception retrieved."
@asyncio.coroutine
def inner(f):
yield from f
async def inner(f):
await f
raise RuntimeError('should not be ignored')
a = asyncio.Future(loop=self.one_loop)
b = asyncio.Future(loop=self.one_loop)
@asyncio.coroutine
def outer():
yield from asyncio.gather(inner(a), inner(b), loop=self.one_loop)
async def outer():
await asyncio.gather(inner(a), inner(b), loop=self.one_loop)
f = asyncio.ensure_future(outer(), loop=self.one_loop)
test_utils.run_briefly(self.one_loop)
@ -3152,15 +3141,14 @@ class RunCoroutineThreadsafeTests(test_utils.TestCase):
self.loop = asyncio.new_event_loop()
self.set_event_loop(self.loop) # Will cleanup properly
@asyncio.coroutine
def add(self, a, b, fail=False, cancel=False):
async def add(self, a, b, fail=False, cancel=False):
"""Wait 0.05 second and return a + b."""
yield from asyncio.sleep(0.05)
await asyncio.sleep(0.05)
if fail:
raise RuntimeError("Fail!")
if cancel:
asyncio.current_task(self.loop).cancel()
yield
await asyncio.sleep(0)
return a + b
def target(self, fail=False, cancel=False, timeout=None,
@ -3261,11 +3249,10 @@ class SleepTests(test_utils.TestCase):
nonlocal result
result += num
@asyncio.coroutine
def coro():
async def coro():
self.loop.call_soon(inc_result, 1)
self.assertEqual(result, 0)
num = yield from asyncio.sleep(0, result=10)
num = await asyncio.sleep(0, result=10)
self.assertEqual(result, 1) # inc'ed by call_soon
inc_result(num) # num should be 11
@ -3318,24 +3305,27 @@ class CompatibilityTests(test_utils.TestCase):
def test_yield_from_awaitable(self):
@asyncio.coroutine
def coro():
yield from asyncio.sleep(0)
return 'ok'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro():
yield from asyncio.sleep(0)
return 'ok'
result = self.loop.run_until_complete(coro())
self.assertEqual('ok', result)
def test_await_old_style_coro(self):
@asyncio.coroutine
def coro1():
return 'ok1'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro1():
return 'ok1'
@asyncio.coroutine
def coro2():
yield from asyncio.sleep(0)
return 'ok2'
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
def coro2():
yield from asyncio.sleep(0)
return 'ok2'
async def inner():
return await asyncio.gather(coro1(), coro2(), loop=self.loop)