Source code for traits_futures.background_progress
# (C) Copyright 2018-2020 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
"""
Support for a progress-reporting background call.
The code in this module supports an arbitrary callable that accepts a
"progress" named argument, and can use that argument to submit progress
information.
Every progress submission also marks a point where the callable can
be cancelled.
"""
from traits.api import (
Callable,
Dict,
Event,
HasStrictTraits,
Str,
Tuple,
)
from traits_futures.base_future import BaseFuture
from traits_futures.i_task_specification import ITaskSpecification
# Message types for messages from ProgressBackgroundTask
# to ProgressFuture.
#: Task sends progress. Argument is a single object giving progress
#: information. This module does not interpret the contents of the argument.
PROGRESS = "progress"
class _ProgressCancelled(Exception):
"""
Exception raised when progress reporting is interrupted by
task cancellation.
"""
[docs]class ProgressReporter:
"""
Object used by the target callable to report progress.
"""
def __init__(self, send, cancelled):
self.send = send
self.cancelled = cancelled
[docs] def report(self, progress_info):
"""
Send progress information to the linked future.
The ``progress_info`` object will eventually be sent to the
corresponding future's ``progress`` event trait.
Parameters
----------
progress_info : object
An arbitrary object representing progress. Ideally, this
should be immutable and pickleable.
"""
if self.cancelled():
raise _ProgressCancelled("Task was cancelled")
self.send(PROGRESS, progress_info)
[docs]class ProgressBackgroundTask:
"""
Background portion of a progress background task.
This provides the callable that will be submitted to the worker pool, and
sends messages to communicate with the ProgressFuture.
"""
def __init__(self, callable, args, kwargs):
self.callable = callable
self.args = args
self.kwargs = kwargs
def __call__(self, send, cancelled):
progress = ProgressReporter(send=send, cancelled=cancelled)
self.kwargs["progress"] = progress.report
try:
return self.callable(*self.args, **self.kwargs)
except _ProgressCancelled:
return None
[docs]class ProgressFuture(BaseFuture):
"""
Object representing the front-end handle to a ProgressBackgroundTask.
"""
#: Event fired whenever a progress message arrives from the background.
progress = Event()
# Private methods #########################################################
def _process_progress(self, progress_info):
self.progress = progress_info
[docs]@ITaskSpecification.register
class BackgroundProgress(HasStrictTraits):
"""
Object representing the background task to be executed.
"""
#: The callable to be executed.
callable = Callable()
#: Positional arguments to be passed to the callable.
args = Tuple()
#: Named arguments to be passed to the callable.
kwargs = Dict(Str())
[docs] def future(self):
"""
Return a Future for the background task.
Returns
-------
future : ProgressFuture
Future object that can be used to monitor the status of the
background task.
"""
return ProgressFuture()
[docs] def background_task(self):
"""
Return a background callable for this task specification.
Returns
-------
collections.abc.Callable
Callable accepting arguments ``send`` and ``cancelled``. The
callable can use ``send`` to send messages and ``cancelled`` to
check whether cancellation has been requested.
"""
if "progress" in self.kwargs:
raise TypeError("progress may not be passed as a named argument")
return ProgressBackgroundTask(
callable=self.callable,
args=self.args,
kwargs=self.kwargs.copy(),
)
[docs]def submit_progress(executor, callable, *args, **kwargs):
"""
Convenience function to submit a background progress call.
Parameters
----------
executor : TraitsExecutor
Executor to submit the task to.
callable : collections.abc.Callable
Callable that executes the progress-providing function. This callable
must accept a "progress" named argument, in addition to the provided
arguments. The callable may then call the "progress" argument to
report progress.
*args
Positional arguments to pass to the callable.
**kwargs
Named arguments other than "progress" to pass to the callable. These
must not include "progress".
Returns
-------
future : ProgressFuture
Object representing the state of the background task.
"""
task = BackgroundProgress(callable=callable, args=args, kwargs=kwargs)
return executor.submit(task)