bpo-31033: Add a msg argument to Future.cancel() and Task.cancel() (GH-19979)

This commit is contained in:
Chris Jerdonek 2020-05-15 16:55:50 -07:00 committed by GitHub
parent fe1176e882
commit 1ce5841eca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 355 additions and 70 deletions

View file

@ -103,6 +103,31 @@ class BaseTaskTests:
self.loop.set_task_factory(self.new_task)
self.loop.create_future = lambda: self.new_future(self.loop)
def test_task_cancel_message_getter(self):
async def coro():
pass
t = self.new_task(self.loop, coro())
self.assertTrue(hasattr(t, '_cancel_message'))
self.assertEqual(t._cancel_message, None)
t.cancel('my message')
with self.assertRaises(asyncio.CancelledError):
self.loop.run_until_complete(t)
self.assertEqual(t._cancel_message, 'my message')
def test_task_cancel_message_setter(self):
async def coro():
pass
t = self.new_task(self.loop, coro())
t.cancel('my message')
t._cancel_message = 'my new message'
self.assertEqual(t._cancel_message, 'my new message')
# Also check that the value is used for cancel().
with self.assertRaises(asyncio.CancelledError):
self.loop.run_until_complete(t)
self.assertEqual(t._cancel_message, 'my new message')
def test_task_del_collect(self):
class Evil:
def __del__(self):
@ -520,6 +545,86 @@ class BaseTaskTests:
self.assertTrue(t.cancelled())
self.assertFalse(t.cancel())
def test_cancel_with_message_then_future_result(self):
# Test Future.result() after calling cancel() with a message.
cases = [
((), ('',)),
((None,), ('',)),
(('my message',), ('my message',)),
# Non-string values should roundtrip.
((5,), (5,)),
]
for cancel_args, expected_args in cases:
with self.subTest(cancel_args=cancel_args):
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
async def sleep():
await asyncio.sleep(10)
async def coro():
task = self.new_task(loop, sleep())
await asyncio.sleep(0)
task.cancel(*cancel_args)
done, pending = await asyncio.wait([task])
task.result()
task = self.new_task(loop, coro())
with self.assertRaises(asyncio.CancelledError) as cm:
loop.run_until_complete(task)
exc = cm.exception
self.assertEqual(exc.args, expected_args)
def test_cancel_with_message_then_future_exception(self):
# Test Future.exception() after calling cancel() with a message.
cases = [
((), ('',)),
((None,), ('',)),
(('my message',), ('my message',)),
# Non-string values should roundtrip.
((5,), (5,)),
]
for cancel_args, expected_args in cases:
with self.subTest(cancel_args=cancel_args):
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
async def sleep():
await asyncio.sleep(10)
async def coro():
task = self.new_task(loop, sleep())
await asyncio.sleep(0)
task.cancel(*cancel_args)
done, pending = await asyncio.wait([task])
task.exception()
task = self.new_task(loop, coro())
with self.assertRaises(asyncio.CancelledError) as cm:
loop.run_until_complete(task)
exc = cm.exception
self.assertEqual(exc.args, expected_args)
def test_cancel_with_message_before_starting_task(self):
loop = asyncio.new_event_loop()
self.set_event_loop(loop)
async def sleep():
await asyncio.sleep(10)
async def coro():
task = self.new_task(loop, sleep())
# We deliberately leave out the sleep here.
task.cancel('my message')
done, pending = await asyncio.wait([task])
task.exception()
task = self.new_task(loop, coro())
with self.assertRaises(asyncio.CancelledError) as cm:
loop.run_until_complete(task)
exc = cm.exception
self.assertEqual(exc.args, ('my message',))
def test_cancel_yield(self):
with self.assertWarns(DeprecationWarning):
@asyncio.coroutine
@ -2285,31 +2390,42 @@ class BaseTaskTests:
self.assertEqual(gather_task.result(), [42])
def test_cancel_gather_2(self):
loop = asyncio.new_event_loop()
self.addCleanup(loop.close)
cases = [
((), ('',)),
((None,), ('',)),
(('my message',), ('my message',)),
# Non-string values should roundtrip.
((5,), (5,)),
]
for cancel_args, expected_args in cases:
with self.subTest(cancel_args=cancel_args):
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
loop = asyncio.new_event_loop()
self.addCleanup(loop.close)
async def main():
qwe = self.new_task(loop, 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')
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
loop.run_until_complete(main())
async def main():
qwe = self.new_task(loop, test())
await asyncio.sleep(0.2)
qwe.cancel(*cancel_args)
try:
await qwe
except asyncio.CancelledError as exc:
self.assertEqual(exc.args, expected_args)
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