Issue #26923: Fix asyncio.Gather to refuse being cancelled once all children are done.

Patch by Johannes Ebke.
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 14949d1..8852aa5 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -592,9 +592,11 @@
     def cancel(self):
         if self.done():
             return False
+        ret = False
         for child in self._children:
-            child.cancel()
-        return True
+            if child.cancel():
+                ret = True
+        return ret
 
 
 def gather(*coros_or_futures, loop=None, return_exceptions=False):
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index a5af7d1..1ceb9b2 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1899,6 +1899,36 @@
     def test_cancel_wait_for(self):
         self._test_cancel_wait_for(60.0)
 
+    def test_cancel_gather(self):
+        """Ensure that a gathering future refuses to be cancelled once all
+        children are done"""
+        loop = asyncio.new_event_loop()
+        self.addCleanup(loop.close)
+
+        fut = asyncio.Future(loop=loop)
+        # 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)
+        gather_future = asyncio.gather(child_coro(), loop=loop)
+        gather_task = asyncio.ensure_future(gather_future, loop=loop)
+
+        cancel_result = None
+        def cancelling_callback(_):
+            nonlocal cancel_result
+            cancel_result = gather_task.cancel()
+        fut.add_done_callback(cancelling_callback)
+
+        fut.set_result(42) # calls the cancelling_callback after fut is done()
+
+        # At this point the task should complete.
+        loop.run_until_complete(gather_task)
+
+        # Python issue #26923: asyncio.gather drops cancellation
+        self.assertEqual(cancel_result, False)
+        self.assertFalse(gather_task.cancelled())
+        self.assertEqual(gather_task.result(), [42])
+
 
 class GatherTestsBase:
 
diff --git a/Misc/NEWS b/Misc/NEWS
index 2d50cf6..48bd626 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -398,6 +398,10 @@
 
 - Issue #27972: Prohibit Tasks to await on themselves.
 
+- Issue #26923: Fix asyncio.Gather to refuse being cancelled once all 
+  children are done.
+  Patch by Johannes Ebke.
+
 IDLE
 ----