Traits Futures: reactive background processing for Traits and TraitsUI

Release v0.3.1.

The traits_futures package provides a means to fire off a background calculation from a TraitsUI application, and later respond to the result(s) of that calculation, leaving the main UI responsive for user interactions while the background calculation is in progress.


  • Supports simple calls, iterations, and progress-reporting functions. Can easily be extended to support other messaging patterns.

  • Dispatching a background task returns a “future” object, which provides:

    • information about state changes (e.g., background task completion)

    • facilities to (cooperatively) cancel a long-running background task

    • access to result(s) arriving from the background task

  • Future objects are HasTraits instances, suitable for integration into a TraitsUI application.

  • No need to be a threading expert! Incoming results arrive as trait changes in the main thread. This eliminates a large class of potential issues with traditional thread-based solutions (race conditions, deadlocks, and UI updates off the main thread).

  • Cross-platform.


Quick start

Here’s a complete example showing a minimal TraitsUI application that fires off a background computation when its “Calculate” button is pressed, and shows the result when it arrives.

import time

from traits.api import (
from traits_futures.api import CallFuture, submit_call, TraitsExecutor
from traitsui.api import Item, UItem, View

def slow_square(n):
    """Square the given input, slowly."""
    return n * n

class QuickStartExample(HasStrictTraits):
    #: The executor to submit tasks to.
    traits_executor = Instance(TraitsExecutor)

    #: The future object returned on task submission.
    future = Instance(CallFuture)

    #: Input for the calculation.
    input = Int(10)

    #: Copy of the input for the last-run / currently-running calculation.
    input_for_calculation = Int()

    #: Message about state of calculation.
    message = Str("No previous calculation runs")

    #: Button to start the calculation.
    calculate = Button()

    #: Boolean used to decide whether to enable the "calculate" button.
    no_running_future = Property(Bool(), observe="future:done")

    def _submit_background_call(self, event):
        # Returns immediately.
        input = self.input
        self.input_for_calculation = self.input
        self.message = "Calculating square of {} ...".format(input)
        self.future = submit_call(self.traits_executor, slow_square, input)
        # Keep a record so that we can present messages accurately.
        self.input_for_calculation = input

    def _report_result(self, event):
        future = event.object
        self.message = "The square of {} is {}.".format(
            self.input_for_calculation, future.result

    def _get_no_running_future(self):
        return self.future is None or self.future.done

    traits_view = View(
        UItem("message", style="readonly"),
        UItem("calculate", enabled_when="no_running_future"),

if __name__ == "__main__":
    traits_executor = TraitsExecutor()

API Documentation

Indices and tables