Issue #24400: Resurrect inspect.isawaitable()

collections.abc.Awaitable and collections.abc.Coroutine no longer
use __instancecheck__ hook to detect generator-based coroutines.

inspect.isawaitable() can be used to detect generator-based coroutines
and to distinguish them from regular generator objects.
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index ab2b733..fbaf712 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -511,8 +511,10 @@
             self.assertTrue(issubclass(type(x), Awaitable))
 
         c = coro()
-        self.assertIsInstance(c, Awaitable)
-        c.close() # awoid RuntimeWarning that coro() was not awaited
+        # Iterable coroutines (generators with CO_ITERABLE_COROUTINE
+        # flag don't have '__await__' method, hence can't be instances
+        # of Awaitable. Use inspect.isawaitable to detect them.
+        self.assertNotIsInstance(c, Awaitable)
 
         c = new_coro()
         self.assertIsInstance(c, Awaitable)
@@ -559,8 +561,10 @@
             self.assertTrue(issubclass(type(x), Awaitable))
 
         c = coro()
-        self.assertIsInstance(c, Coroutine)
-        c.close() # awoid RuntimeWarning that coro() was not awaited
+        # Iterable coroutines (generators with CO_ITERABLE_COROUTINE
+        # flag don't have '__await__' method, hence can't be instances
+        # of Coroutine. Use inspect.isawaitable to detect them.
+        self.assertNotIsInstance(c, Coroutine)
 
         c = new_coro()
         self.assertIsInstance(c, Coroutine)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index ab22c7d..a02f2e1 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -151,6 +151,29 @@
 
         coro.close(); gen_coro.close() # silence warnings
 
+    def test_isawaitable(self):
+        def gen(): yield
+        self.assertFalse(inspect.isawaitable(gen()))
+
+        coro = coroutine_function_example(1)
+        gen_coro = gen_coroutine_function_example(1)
+
+        self.assertTrue(inspect.isawaitable(coro))
+        self.assertTrue(inspect.isawaitable(gen_coro))
+
+        class Future:
+            def __await__():
+                pass
+        self.assertTrue(inspect.isawaitable(Future()))
+        self.assertFalse(inspect.isawaitable(Future))
+
+        class NotFuture: pass
+        not_fut = NotFuture()
+        not_fut.__await__ = lambda: None
+        self.assertFalse(inspect.isawaitable(not_fut))
+
+        coro.close(); gen_coro.close() # silence warnings
+
     def test_isroutine(self):
         self.assertTrue(inspect.isroutine(mod.spam))
         self.assertTrue(inspect.isroutine([].count))
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index ba8a1b9..738588e 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -1447,6 +1447,19 @@
         with self.assertRaisesRegex(Exception, 'ham'):
             wrapper.throw(Exception, Exception('ham'))
 
+    def test_returning_itercoro(self):
+        @types.coroutine
+        def gen():
+            yield
+
+        gencoro = gen()
+
+        @types.coroutine
+        def foo():
+            return gencoro
+
+        self.assertIs(foo(), gencoro)
+
     def test_genfunc(self):
         def gen(): yield
         self.assertIs(types.coroutine(gen), gen)
@@ -1457,9 +1470,6 @@
         g = gen()
         self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
         self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)
-        self.assertIsInstance(g, collections.abc.Coroutine)
-        self.assertIsInstance(g, collections.abc.Awaitable)
-        g.close() # silence warning
 
         self.assertIs(types.coroutine(gen), gen)