From dd0f5dfcd39852fc864fd5615faad925bf792ded Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 17:00:02 +0300 Subject: [PATCH 1/9] Work on --- Lib/asyncio/coroutines.py | 7 ++ Lib/asyncio/futures.py | 7 +- Lib/test/test_asyncio/test_tasks.py | 126 ++++++++++++++-------------- Modules/_asynciomodule.c | 17 +++- 4 files changed, 89 insertions(+), 68 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index c665ebe33ee1962..2b9e56c0153adb8 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -7,6 +7,7 @@ import sys import traceback import types +import warnings from . import base_futures from . import constants @@ -52,6 +53,8 @@ def __repr__(self): return f'<{self.__class__.__name__} {coro_repr}>' def __iter__(self): + warnings.warn("yield from coro is deprecated, please use await coro instead", + DeprecationWarning) return self def __next__(self): @@ -107,6 +110,10 @@ def coroutine(func): If the coroutine is not yielded from before it is destroyed, an error message is logged. """ + warnings.warn("@coroutine decoratur is deprecated, " + "please use async def function 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". diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 98a5308ed061839..773f759f34e6a13 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -8,6 +8,7 @@ import contextvars import logging import sys +import warnings from . import base_futures from . import events @@ -259,7 +260,11 @@ def __await__(self): raise RuntimeError("await wasn't used with future") return self.result() # May raise too. - __iter__ = __await__ # make compatible with 'yield from'. + def __iter__(self): + warnings.warn("yield from fut is deprecated, please use await fut instead", + DeprecationWarning, + stacklevel=2) + return self.__await__() # Needed for testing purposes. diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index fa9783f2ff2196f..cac3af9b1650356 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1220,10 +1220,9 @@ def gen(): completed = set() time_shifted = False - @asyncio.coroutine - def sleeper(dt, x): + async def sleeper(dt, x): nonlocal time_shifted - yield from asyncio.sleep(dt) + await asyncio.sleep(dt) completed.add(x) if not time_shifted and 'a' in completed and 'b' in completed: time_shifted = True @@ -1234,11 +1233,10 @@ def sleeper(dt, x): 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,17 +1348,15 @@ def gen(): def test_as_completed_duplicate_coroutines(self): - @asyncio.coroutine - def coro(s): + async def coro(s): return s - @asyncio.coroutine - def runner(): + async def runner(): result = [] c = coro('ham') for f in asyncio.as_completed([c, c, coro('spam')], loop=self.loop): - result.append((yield from f)) + result.append(await f) return result fut = self.new_task(self.loop, runner()) @@ -1380,10 +1376,9 @@ def gen(): 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 +1426,14 @@ def gen(): 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 +1446,8 @@ def doit(): 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 +1461,7 @@ def coro(): self.assertTrue(fut.cancelled()) def test_task_set_methods(self): - @asyncio.coroutine - def notmuch(): + async def notmuch(): return 'ko' gen = notmuch() @@ -1487,11 +1478,12 @@ def notmuch(): '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 +1503,9 @@ def add_done_callback(self, *args, **kwargs): 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 +1527,14 @@ def gen(): 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 +1560,10 @@ def fn1(): 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 +1571,10 @@ def fn2(): 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 +1583,19 @@ def wait_for_future(): 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 +1603,10 @@ def wait_for_future(): 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,13 +1619,15 @@ def func(): 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(): - fut.set_result('test') + with self.assertWarns(DeprecationWarning): + @asyncio.coroutine + def coro(): + fut.set_result('test') t1 = self.new_task(self.loop, func()) t2 = self.new_task(self.loop, coro()) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index f9037c279ac9c34..12dabb6bfd2e279 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -128,6 +128,8 @@ class _asyncio.Future "FutureObj *" "&Future_Type" /* Get FutureIter from Future */ static PyObject * future_new_iter(PyObject *); +/* Deprecated version of future_new_iter */ +static PyObject * future_new_iter_deprecated(PyObject *); static PyRunningLoopHolder * new_running_loop_holder(PyObject *); @@ -1437,7 +1439,7 @@ static PyTypeObject FutureType = { .tp_traverse = (traverseproc)FutureObj_traverse, .tp_clear = (inquiry)FutureObj_clear, .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), - .tp_iter = (getiterfunc)future_new_iter, + .tp_iter = (getiterfunc)future_new_iter_deprecated, .tp_methods = FutureType_methods, .tp_getset = FutureType_getsetlist, .tp_dictoffset = offsetof(FutureObj, dict), @@ -1667,6 +1669,17 @@ future_new_iter(PyObject *fut) } +static PyObject * +future_new_iter_deprecated(PyObject *fut) +{ + if(PyErr_WarnEx(PyExc_DeprecationWarning, + "yield from fut is deprecated, please use await fut instead", + 1)) { + return NULL; + } + return future_new_iter(fut); +} + /*********************** Task **************************/ @@ -2468,7 +2481,7 @@ static PyTypeObject TaskType = { .tp_traverse = (traverseproc)TaskObj_traverse, .tp_clear = (inquiry)TaskObj_clear, .tp_weaklistoffset = offsetof(TaskObj, task_weakreflist), - .tp_iter = (getiterfunc)future_new_iter, + .tp_iter = (getiterfunc)future_new_iter_deprecated, .tp_methods = TaskType_methods, .tp_getset = TaskType_getsetlist, .tp_dictoffset = offsetof(TaskObj, dict), From 504f7297acb41b58db006d81555309fa9ab1b1a9 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 17:12:23 +0300 Subject: [PATCH 2/9] Work on --- Lib/test/test_asyncio/test_tasks.py | 83 ++++++++++++++++------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index cac3af9b1650356..8b4b7a006f29be6 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1036,14 +1036,16 @@ def test_wait_really_done(self): # 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 + with self.assertWarns(DeprecationWarning): + @asyncio.coroutine + def coro1(): + yield - @asyncio.coroutine - def coro2(): - yield - yield + with self.assertWarns(DeprecationWarning): + @asyncio.coroutine + def coro2(): + yield + yield a = self.new_task(self.loop, coro1()) b = self.new_task(self.loop, coro2()) @@ -1131,9 +1133,8 @@ def gen(): 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,24 +1221,28 @@ def gen(): completed = set() time_shifted = False - async def sleeper(dt, x): - nonlocal time_shifted - await 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') - async def foo(): - values = [] - for f in asyncio.as_completed([b, c, a], loop=loop): - values.append(await f) - return values + with self.assertWarns(DeprecationWarning): + @asyncio.coroutine + def foo(): + values = [] + for f in asyncio.as_completed([b, c, a], loop=loop): + values.append((yield from f)) + return values res = loop.run_until_complete(self.new_task(loop, foo())) self.assertAlmostEqual(0.15, loop.time()) @@ -1918,19 +1923,24 @@ def coro(): 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(): + with self.assertWarns(DeprecationWarning): + 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)) + with self.assertWarns(DeprecationWarning): + 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) @@ -3257,11 +3267,10 @@ def inc_result(num): 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 From 647aff75cbcb979140fc329ed482e3f38c7e6531 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 17:28:16 +0300 Subject: [PATCH 3/9] Work on --- Lib/test/test_asyncio/test_tasks.py | 55 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 8b4b7a006f29be6..551dc0e36856070 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -103,8 +103,7 @@ class Evil: def __del__(self): gc.collect() - @asyncio.coroutine - def run(): + async def run(): return Evil() self.loop.run_until_complete( @@ -138,8 +137,7 @@ async def test(): 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 +154,10 @@ def notmuch(): 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 +193,7 @@ def test_ensure_future_future(self): 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 +220,10 @@ def __init__(self, coro): 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,10 +275,11 @@ async def runner(): def test_task_repr(self): self.loop.set_debug(False) - @asyncio.coroutine - def notmuch(): - yield from [] - return 'abc' + with self.assertWarns(DeprecationWarning): + @asyncio.coroutine + def notmuch(): + yield from [] + return 'abc' # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') @@ -327,8 +327,7 @@ def notmuch(): "" % 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 +345,7 @@ def notmuch(): 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 +356,12 @@ def notmuch(): 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') @@ -736,8 +735,7 @@ def gen(): foo_started = False - @asyncio.coroutine - def foo(): + async def foo(): nonlocal foo_started foo_started = True @@ -814,8 +812,7 @@ async def foo(): 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)) From 9f44587b202c6b395864c7772d9b1bff15351bb6 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 17:28:36 +0300 Subject: [PATCH 4/9] Work on --- Lib/test/test_asyncio/test_tasks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 551dc0e36856070..341c4e3fd00ff82 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1069,8 +1069,7 @@ def gen(): # 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()) From 125a52f7439d2e24643400314717830291868ab7 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 17:53:42 +0300 Subject: [PATCH 5/9] Work on --- Lib/asyncio/coroutines.py | 5 +- Lib/test/test_asyncio/test_tasks.py | 89 ++++++++++++++++------------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 2b9e56c0153adb8..17bca55885a5fa1 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -54,7 +54,8 @@ def __repr__(self): def __iter__(self): warnings.warn("yield from coro is deprecated, please use await coro instead", - DeprecationWarning) + DeprecationWarning, + stacklevel=2) return self def __next__(self): @@ -110,7 +111,7 @@ def coroutine(func): If the coroutine is not yielded from before it is destroyed, an error message is logged. """ - warnings.warn("@coroutine decoratur is deprecated, " + warnings.warn("@coroutine decorator is deprecated, " "please use async def function instead", DeprecationWarning, stacklevel=2) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 341c4e3fd00ff82..8d652d68990c4a1 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -439,7 +439,8 @@ def test_task_repr_partial_corowrapper(self): 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 @@ -973,9 +974,10 @@ async def foo(): 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( @@ -1632,7 +1634,8 @@ def coro(): t1 = self.new_task(self.loop, func()) t2 = self.new_task(self.loop, coro()) - res = self.loop.run_until_complete(t1) + with self.assertWarns(DeprecationWarning): + res = self.loop.run_until_complete(t1) self.assertEqual(res, 'test') self.assertIsNone(t2.result()) @@ -1884,11 +1887,13 @@ def check(): # 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) + with self.assertWarns(DeprecationWarning): + yield from fut # A completed Future used to run the coroutine. fut = self.new_future(self.loop) @@ -2011,13 +2016,15 @@ async def coro(): 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) + with self.assertWarns(DeprecationWarning): + 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) @@ -2066,14 +2073,12 @@ def test_tb_logger_not_called_after_cancel(self, m_log): 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 @@ -2083,9 +2088,10 @@ def runner(): @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 @@ -2114,13 +2120,15 @@ def test_return_coroutine_from_coroutine(self): 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) @@ -2131,7 +2139,8 @@ def inner_coro(): # Test with debug flag set. with set_coroutine_debug(True): - check() + with self.assertWarns(DeprecationWarning): + check() def test_task_source_traceback(self): self.loop.set_debug(True) @@ -2232,14 +2241,12 @@ async def main(): 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()) @@ -2250,8 +2257,7 @@ def call_soon(callback, *args, **kwargs): raise ValueError self.loop.call_soon = call_soon - @asyncio.coroutine - def coro(): + async def coro(): pass self.assertFalse(m_log.error.called) @@ -2282,9 +2288,10 @@ def test_create_task_with_noncoroutine(self): 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) From f53eb64ac31008ba0a896cc1f8f5b8133cffe6ee Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 18:02:11 +0300 Subject: [PATCH 6/9] Work on --- Lib/test/test_asyncio/test_tasks.py | 64 +++++++++++++---------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 8d652d68990c4a1..cc39ca6a1342775 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -492,11 +492,12 @@ async def task(): 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 +619,7 @@ def test_cancel_at_end(self): 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 @@ -2158,11 +2158,10 @@ def _test_cancel_wait_for(self, timeout): 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()) @@ -2191,7 +2190,8 @@ def test_cancel_gather_1(self): # The indirection fut->child_coro is needed since otherwise the # gathering task is done at the same time as the child future def child_coro(): - return (yield from fut) + with self.assertWarns(DeprecationWarning): + return (yield from fut) gather_future = asyncio.gather(child_coro(), loop=loop) gather_task = asyncio.ensure_future(gather_future, loop=loop) @@ -3063,15 +3063,13 @@ def setUp(self): 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() @@ -3087,9 +3085,10 @@ def coro(): 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) @@ -3100,21 +3099,19 @@ def test_cancellation_broadcast(self): 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) @@ -3132,17 +3129,15 @@ def outer(): 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) @@ -3161,15 +3156,14 @@ def setUp(self): 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, From e7b10626b92b86b99221059f7a2f54edef20f0f1 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 18:16:07 +0300 Subject: [PATCH 7/9] Finish test_tasks --- Lib/asyncio/locks.py | 6 +++-- Lib/asyncio/tasks.py | 5 ++++- Lib/test/test_asyncio/test_tasks.py | 34 ++++++++++++++--------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py index 639bd11bd06838f..c3c8f9ebf1e0360 100644 --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -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 .coroutines import _is_coroutine class _ContextManager: @@ -55,7 +56,7 @@ def __exit__(self, *args): # 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: # @@ -77,6 +78,7 @@ def __iter__(self): DeprecationWarning, stacklevel=2) yield from self.acquire() return _ContextManager(self) + __iter__._is_coroutine = _is_coroutine async def __acquire_ctx(self): await self.acquire() diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 211b9126b0114a2..227cc2c4503c0c0 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -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(). @@ -648,6 +648,9 @@ def _wrap_awaitable(awaitable): return (yield from awaitable.__await__()) +_wrap_awaitable._is_coroutine = coroutines._is_coroutine + + class _GatheringFuture(futures.Future): """Helper for gather(). diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index cc39ca6a1342775..b8bdef791ab38ed 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -28,8 +28,7 @@ def tearDownModule(): asyncio.set_event_loop_policy(None) -@asyncio.coroutine -def coroutine_function(): +async def coroutine_function(): pass @@ -2562,8 +2561,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) @@ -2574,8 +2572,7 @@ def coro(): 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) @@ -3320,24 +3317,27 @@ def tearDown(self): 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) From cf822655d89f461fbd16918ee7ab08152a638044 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 14 May 2019 19:06:33 +0300 Subject: [PATCH 8/9] Finish deprecation --- Lib/test/test_asyncio/test_base_events.py | 49 +++++-------- Lib/test/test_asyncio/test_events.py | 17 ++--- Lib/test/test_asyncio/test_futures.py | 12 ++-- Lib/test/test_asyncio/test_locks.py | 84 +++++++++++++---------- Lib/test/test_asyncio/test_pep492.py | 7 +- 5 files changed, 80 insertions(+), 89 deletions(-) diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 25420b2ff6fa7ea..6e8cf7514f49d9f 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -575,9 +575,8 @@ def zero_error(fut): 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 @@ def test_set_task_factory(self): 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 @@ def test_create_task(self): class MyTask(asyncio.Task): pass - @asyncio.coroutine - def test(): + async def test(): pass class EventLoop(base_events.BaseEventLoop): @@ -830,8 +827,7 @@ def test_run_forever_keyboard_interrupt(self): # 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 @@ def raise_keyboard_interrupt(): 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 @@ def test_create_connection_multiple_errors(self, m_socket): 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 @@ def test_create_connection_no_host_port_sock(self): 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): + pass def getaddrinfo_task(*args, **kwds): return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) @@ -1219,8 +1211,7 @@ def getaddrinfo_task(*args, **kwds): 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 @@ def bind(addr): 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 @@ def test_create_connection_service_name(self, m_socket): 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,9 @@ def test_create_server_empty_host(self): # 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 [] def getaddrinfo_task(*args, **kwds): return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) @@ -1854,8 +1841,7 @@ def test_accept_connection_exception(self, m_log): MyProto, sock, None, None, mock.ANY, mock.ANY) def test_call_coroutine(self): - @asyncio.coroutine - def simple_coroutine(): + async def simple_coroutine(): pass self.loop.set_debug(True) @@ -1880,9 +1866,7 @@ def test_log_slow_callbacks(self, m_logger): 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 +1893,7 @@ def stop_loop_coro(loop): 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() diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index b46b614e556eae6..3442496fc1a4da4 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -253,12 +253,10 @@ def tearDown(self): 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 @@ def test_connect_accepted_socket_ssl_timeout_for_plain_socket(self): @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 @@ def test_add_fds_after_closing(self): 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 @@ def close_loop(loop): def test_close(self): self.loop.close() - @asyncio.coroutine - def test(): + async def test(): pass func = lambda: False diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 2e4583d12450c71..e51ec34e681209f 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -253,9 +253,11 @@ def test_yield_from_twice(self): def fixture(): yield 'A' - x = yield from f + with self.assertWarns(DeprecationWarning): + x = yield from f yield 'B', x - y = yield from f + with self.assertWarns(DeprecationWarning): + y = yield from f yield 'C', y g = fixture() @@ -533,7 +535,8 @@ def test_set_result_unless_cancelled(self): def test_future_stop_iteration_args(self): fut = self._new_future(loop=self.loop) fut.set_result((1, 2)) - fi = fut.__iter__() + with self.assertWarns(DeprecationWarning): + fi = fut.__iter__() result = None try: fi.send(None) @@ -545,7 +548,8 @@ def test_future_stop_iteration_args(self): def test_future_iter_throw(self): fut = self._new_future(loop=self.loop) - fi = iter(fut) + with self.assertWarns(DeprecationWarning): + fi = iter(fut) self.assertRaises(TypeError, fi.throw, Exception, Exception("elephant"), 32) self.assertRaises(TypeError, fi.throw, diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py index b61cf743c3c543a..5063a1da448e65d 100644 --- a/Lib/test/test_asyncio/test_locks.py +++ b/Lib/test/test_asyncio/test_locks.py @@ -44,10 +44,11 @@ def test_repr(self): 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 @@ def acquire_lock(): 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 @@ def test_lock_by_with_statement(self): 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 @@ def test_release_no_waiters(self): 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 @@ def acquire_lock(): 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 @@ def test_repr(self): 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 @@ def test_semaphore(self): 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 @@ def test_release_no_waiters(self): 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()) diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py index 558e268415cd004..297a3b3901d6314 100644 --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -130,9 +130,10 @@ class Awaitable: 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') From 1e16471077d2ac3475e1e9f7fe74fab437318ec5 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 15 May 2019 11:33:35 +0300 Subject: [PATCH 9/9] Add changenote --- .../next/Library/2019-05-15-11-33-26.bpo-36921.fKRltR.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-05-15-11-33-26.bpo-36921.fKRltR.rst diff --git a/Misc/NEWS.d/next/Library/2019-05-15-11-33-26.bpo-36921.fKRltR.rst b/Misc/NEWS.d/next/Library/2019-05-15-11-33-26.bpo-36921.fKRltR.rst new file mode 100644 index 000000000000000..80e024f7bb0f9aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-05-15-11-33-26.bpo-36921.fKRltR.rst @@ -0,0 +1,2 @@ +Deprecate ``@coroutine`` and ``yield from`` in asyncio in favor or ``async +def`` and ``await``.