I had an issue with my code where I called Task.cancel on an instance and 
it would stay in state pending (cancelled returning False). I did some 
digging and found in the source that Task overwrites the cancel method and 
does not directly set the new state. Going back to the documentation, I did 
not find anything that documents this behavior.

The problematic use case was a situation like the following: I iterate over 
a list of tasks, check various properties (like how long they are running 
etc.) and based on that decide to either give it more time or cancel it or 
check its results if its done. After having handled all running tasks, I do 
other work and later return to check them again. When I checked again, I 
explicitly checked the case where I already had cancelled a task. In this 
next iteration I want to see if it is done yet or if it needs some more 
time cleaning up. However, to my surprise, task.cancelled() returned false, 
which led me to execute task.cancel() again, which in turn raised a 
CancellationError inside the finally-block doing cleanup. I then added 
something like this:

task.cancel()
assert task.canelled()

A statement that, on a future, has to succeed (as I see it from the source) 
but on a task must fail. Is there a reason this behavior is not documented 
or did I miss it somewhere?

Also since this seems to be desired behavior, is there a reliable way to 
perform this check on a task? In __repr__ you check against _must_cancel 
for the difference between displaying "PENDING" and "CANCELLING" (this 
actually led me to the point of looking at the Task source). However, this 
is an internal variable and so I probably shouldn't use it. The only other 
thing I can come up with is using the return value and store it somewhere 
else and then check that variable, however that seems rather "dirty", 
storing a value that should belong to the task outside of it.

Reply via email to