Author Martin.Teichmann
Recipients Martin.Teichmann
Date 2018-05-02.18:39:17
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1525286358.11.0.682650639539.issue33413@psf.upfronthosting.co.za>
In-reply-to
Content
asyncio.gather() returns a _GatheringFuture, which inherits from asyncio.Future. This is weird in current asyncio, as futures are supposed to be created with loop.create_future(). So I tried to reimplement gather() without this weird special future. I succeeded, yet I stumbled over weird inconsistencies with cancellation. There are three cases:

- coroutines have no special notion of cancellation, they treat CancelledError as any other exception

- futures have a clear distinction between exceptions and cancellation: future.set_exception(CancelledError()) is different from future.cancel(), as only for the latter future.cancelled() is True. This is used in the _GatheringFuture: it is cancelled() only if it got cancelled via future.cancel(), if its children gets cancelled it may set_exception(CancelledError()), but it will not be cancelled itself.

- Tasks consider raising a CancelledError always as a cancellation, whether it actually got cancelled or the wrapped coroutine raised CancelledError for whatever other reason. There is one exception: if the coroutine manages to return immediately after being cancelled, it raises a CancelledError, but task.cancelled() is false. So if a coroutine ends in

    current_task().cancel()
    return

the current task raises a CancelledError, but task.cancelled() is false.

I consider the last exception actually a bug, but it allows me to make my inheritance-free gather() look to the outside exactly like it used to be.
History
Date User Action Args
2018-05-02 18:39:18Martin.Teichmannsetrecipients: + Martin.Teichmann
2018-05-02 18:39:18Martin.Teichmannsetmessageid: <1525286358.11.0.682650639539.issue33413@psf.upfronthosting.co.za>
2018-05-02 18:39:18Martin.Teichmannlinkissue33413 messages
2018-05-02 18:39:17Martin.Teichmanncreate