[Python-checkins] bpo-32684: Fix gather to propagate cancel of itself with return_exceptions (GH-7209)

Yury Selivanov webhook-mailer at python.org
Tue May 29 17:20:11 EDT 2018


https://github.com/python/cpython/commit/863b6749093a86810c4077112a857363410cc221
commit: 863b6749093a86810c4077112a857363410cc221
branch: master
author: Yury Selivanov <yury at magic.io>
committer: GitHub <noreply at github.com>
date: 2018年05月29日T17:20:02-04:00
summary:
bpo-32684: Fix gather to propagate cancel of itself with return_exceptions (GH-7209)
files:
A Misc/NEWS.d/next/Library/2018-05-29-12-51-18.bpo-32684.ZEIism.rst
M Doc/library/asyncio-task.rst
M Lib/asyncio/tasks.py
M Lib/test/test_asyncio/test_tasks.py
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index 233cc9454967..dc450c375aad 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -640,6 +640,10 @@ Task functions
 outer Future is *not* cancelled in this case. (This is to prevent the
 cancellation of one child to cause other children to be cancelled.)
 
+ .. versionchanged:: 3.7.0
+ If the *gather* itself is cancelled, the cancellation is propagated
+ regardless of *return_exceptions*.
+
 .. function:: iscoroutine(obj)
 
 Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`,
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 67fb57c6a781..6cef33d5212e 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -591,6 +591,7 @@ class _GatheringFuture(futures.Future):
 def __init__(self, children, *, loop=None):
 super().__init__(loop=loop)
 self._children = children
+ self._cancel_requested = False
 
 def cancel(self):
 if self.done():
@@ -599,6 +600,11 @@ def cancel(self):
 for child in self._children:
 if child.cancel():
 ret = True
+ if ret:
+ # If any child tasks were actually cancelled, we should
+ # propagate the cancellation request regardless of
+ # *return_exceptions* argument. See issue 32684.
+ self._cancel_requested = True
 return ret
 
 
@@ -673,7 +679,13 @@ def _done_callback(fut):
 res = fut.result()
 results.append(res)
 
- outer.set_result(results)
+ if outer._cancel_requested:
+ # If gather is being cancelled we must propagate the
+ # cancellation regardless of *return_exceptions* argument.
+ # See issue 32684.
+ outer.set_exception(futures.CancelledError())
+ else:
+ outer.set_result(results)
 
 arg_to_fut = {}
 children = []
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 33300c91a367..1280584d318c 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -2037,7 +2037,7 @@ def test_cancel_blocking_wait_for(self):
 def test_cancel_wait_for(self):
 self._test_cancel_wait_for(60.0)
 
- def test_cancel_gather(self):
+ def test_cancel_gather_1(self):
 """Ensure that a gathering future refuses to be cancelled once all
 children are done"""
 loop = asyncio.new_event_loop()
@@ -2067,6 +2067,33 @@ def cancelling_callback(_):
 self.assertFalse(gather_task.cancelled())
 self.assertEqual(gather_task.result(), [42])
 
+ def test_cancel_gather_2(self):
+ loop = asyncio.new_event_loop()
+ self.addCleanup(loop.close)
+
+ async def test():
+ time = 0
+ while True:
+ time += 0.05
+ await asyncio.gather(asyncio.sleep(0.05),
+ return_exceptions=True,
+ loop=loop)
+ if time > 1:
+ return
+
+ async def main():
+ qwe = asyncio.Task(test())
+ await asyncio.sleep(0.2)
+ qwe.cancel()
+ try:
+ await qwe
+ except asyncio.CancelledError:
+ pass
+ else:
+ self.fail('gather did not propagate the cancellation request')
+
+ loop.run_until_complete(main())
+
 def test_exception_traceback(self):
 # See http://bugs.python.org/issue28843
 
diff --git a/Misc/NEWS.d/next/Library/2018-05-29-12-51-18.bpo-32684.ZEIism.rst b/Misc/NEWS.d/next/Library/2018-05-29-12-51-18.bpo-32684.ZEIism.rst
new file mode 100644
index 000000000000..b360bbcf7998
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-05-29-12-51-18.bpo-32684.ZEIism.rst
@@ -0,0 +1 @@
+Fix gather to propagate cancellation of itself even with return_exceptions.


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /