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
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index c665ebe..9664ea7 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
@@ -107,6 +108,9 @@
     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".
diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
index 639bd11..d59eb8f 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 .import coroutines
 
 
 class _ContextManager:
@@ -55,7 +56,7 @@
         # 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 @@
         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)
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 211b912..b274b9b 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -23,7 +23,7 @@
 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 @@
                         'required')
 
 
-@coroutine
+@types.coroutine
 def _wrap_awaitable(awaitable):
     """Helper for asyncio.ensure_future().
 
@@ -647,6 +647,8 @@
     """
     return (yield from awaitable.__await__())
 
+_wrap_awaitable._is_coroutine = _is_coroutine
+
 
 class _GatheringFuture(futures.Future):
     """Helper for gather().