asyncpool.futures — asyncpool 1.0.1 documentation

# Source code for asyncpool.futures

    """Defines the futures returned to users."""

    import asyncio
    import concurrent.futures
    from concurrent.futures._base import PENDING

    class ConcurrentFuture(concurrent.futures.Future):
        """A concurrent.futures.Future subclass that cancels like asyncio.Task.
        """
        def __init__(self, cancel_interface):
            super().__init__()
            self._cancel_interface = cancel_interface

            # A flag to avoid cancelling twice and that work finishs
            # before the cancellation function scheduled.
            self._cancel_interface_called = False

        def cancel(self):
            """Tries to cancel the work submitted to worker.

            *Unlike* ``concurrent.futures``, the *running* work is *cancellable*
            as long as it's a ``coroutine function``.

            Returns:
                True if cancellable, False otherwise.

            """
            with self._condition:
                if super().cancel():
                    # Cancellable if it's pending.
                    return True
                else:
                    # Running or finished.
                    if self.running():
                        # The interface didn't be provided to this future, since
                        # the submitted work is not a coroutine function.
                        if self._cancel_interface is None:
                            return False

                        # Avoid cancelling twice.
                        if not self._cancel_interface_called:
                            self._cancel_interface_called = True
                            self._cancel_interface(self)
                        return True  # Returns True as asyncio.Task.cancel() does.
                    else:
                        return False

        def _cancel_running(self):
            """A method called by executor's handler to force the running
            futures into cancelled state.
            """
            with self._condition:
                assert self.running()
                self._state = PENDING  # Unable to cancel if its RUNNING.
                super().cancel()
                self.set_running_or_notify_cancel()
                return True

    class AsyncioFuture(asyncio.Future):
        """Asyncio.Future subclass that cancels like asyncio.Task.
        """

        def __init__(self, concurrent_future, loop=None):
            super().__init__(loop=loop)
            self._future = concurrent_future

            # TODO(Lun): Not to use _chain_future, since it's private.
            asyncio.futures._chain_future(self._future, self)

        def cancel(self):
            """Tries to cancel the work submitted to worker.

            *Unlike* ``concurrent.futures``, the *running* work is *cancellable*
            as long as it's a ``coroutine function``.

            Returns:
                True if cancellable, False otherwise.

            """
            # This method will call by users and be called again by the
            # callback scheduled in the chained concurrent future.
            # When called by a callback, ``asyncio.Future.cancel`` will
            # be executed via super().cancel().

            # The chained future will be cancelled if and only if the work is
            # done by cancelling. Then just run ``asyncio.Future.cancel``.
            if self._future.cancelled():
                return super().cancel()

            # The below block will be executed when it's called by the user.
            self._log_traceback = False
            return self._future.cancel()