Backport of the concurrent.futures package from Python 3 for Python 2
—
Future objects represent the result of an asynchronous computation. They provide methods to check the status of the computation, retrieve results, handle exceptions, and attach callbacks that execute when the computation completes.
The Future class encapsulates the lifecycle and result of an asynchronous operation.
class Future:
def __init__(self):
"""
Initialize a Future object.
Note: Should not be called directly by client code.
Futures are created by Executor.submit() calls.
"""
def cancel(self):
"""
Attempt to cancel the future.
Returns:
bool: True if successfully cancelled, False if already running or completed
Note: Cannot cancel futures that are already running or finished
"""
def cancelled(self):
"""
Check if the future was cancelled.
Returns:
bool: True if the future was cancelled before completion
"""
def running(self):
"""
Check if the future is currently executing.
Returns:
bool: True if the future is currently being executed
"""
def done(self):
"""
Check if the future has completed.
Returns:
bool: True if future completed (finished, cancelled, or failed)
"""
def result(self, timeout=None):
"""
Get the result of the future.
Parameters:
- timeout (float, optional): Maximum time to wait in seconds
Returns:
Any: The result returned by the callable
Raises:
CancelledError: If the future was cancelled
TimeoutError: If timeout exceeded before completion
Exception: Any exception raised by the callable
"""
def exception(self, timeout=None):
"""
Get the exception raised by the future's callable.
Parameters:
- timeout (float, optional): Maximum time to wait in seconds
Returns:
Exception or None: Exception raised by callable, or None if successful
Raises:
CancelledError: If the future was cancelled
TimeoutError: If timeout exceeded before completion
"""
def exception_info(self, timeout=None):
"""
Get exception and traceback information.
Parameters:
- timeout (float, optional): Maximum time to wait in seconds
Returns:
tuple: (exception, traceback) or (None, None) if successful
Raises:
CancelledError: If the future was cancelled
TimeoutError: If timeout exceeded before completion
"""
def add_done_callback(self, fn):
"""
Attach a callback to be called when the future completes.
Parameters:
- fn (callable): Function to call with the future as argument
Note: Callback is called immediately if future is already complete.
Multiple callbacks are called in the order they were added.
"""Basic Future Usage:
from concurrent.futures import ThreadPoolExecutor
def slow_function(n):
import time
time.sleep(1)
if n < 0:
raise ValueError("Negative number")
return n * n
with ThreadPoolExecutor() as executor:
# Submit task and get future
future = executor.submit(slow_function, 5)
# Check status
print(f"Cancelled: {future.cancelled()}") # False
print(f"Running: {future.running()}") # True or False
print(f"Done: {future.done()}") # False initially
# Get result (blocks until complete)
result = future.result()
print(f"Result: {result}") # 25
# Check final status
print(f"Done: {future.done()}") # TrueHandling Exceptions:
with ThreadPoolExecutor() as executor:
# Submit task that will raise exception
future = executor.submit(slow_function, -1)
try:
result = future.result()
except ValueError as e:
print(f"Task failed: {e}")
# Alternative: check exception directly
exception = future.exception()
if exception:
print(f"Exception occurred: {exception}")Using Timeouts:
with ThreadPoolExecutor() as executor:
future = executor.submit(slow_function, 5)
try:
# Wait maximum 0.5 seconds
result = future.result(timeout=0.5)
print(f"Quick result: {result}")
except TimeoutError:
print("Task didn't complete in time")
# Future continues running in background
# Wait for actual completion
result = future.result() # No timeout
print(f"Final result: {result}")Cancelling Futures:
import time
with ThreadPoolExecutor() as executor:
future = executor.submit(slow_function, 10)
# Try to cancel immediately
if future.cancel():
print("Successfully cancelled")
else:
print("Could not cancel (already running)")
# Check if cancelled
if future.cancelled():
try:
result = future.result()
except CancelledError:
print("Future was cancelled")Done Callbacks:
def task_completed(future):
try:
result = future.result()
print(f"Task completed with result: {result}")
except Exception as e:
print(f"Task failed with exception: {e}")
with ThreadPoolExecutor() as executor:
future = executor.submit(slow_function, 7)
# Add callback (can add multiple)
future.add_done_callback(task_completed)
# Callback will be called when future completes
# Main thread can continue other work
result = future.result() # Also wait for completionAdvanced Callback Usage:
def log_completion(name):
def callback(future):
status = "succeeded" if not future.exception() else "failed"
print(f"Task '{name}' {status}")
return callback
def process_result(future):
if not future.exception():
result = future.result()
# Do something with result
print(f"Processing result: {result}")
with ThreadPoolExecutor() as executor:
future = executor.submit(slow_function, 3)
# Add multiple callbacks
future.add_done_callback(log_completion("calculation"))
future.add_done_callback(process_result)
# Both callbacks will be called when future completes
future.result()A future progresses through these states:
# Example showing state transitions
with ThreadPoolExecutor(max_workers=1) as executor:
def check_states(future, name):
print(f"{name} - Cancelled: {future.cancelled()}, "
f"Running: {future.running()}, Done: {future.done()}")
future = executor.submit(slow_function, 2)
check_states(future, "After submit") # May show running=True
result = future.result()
check_states(future, "After completion") # done=TrueComprehensive Error Handling:
from concurrent.futures import CancelledError, TimeoutError
def handle_future_result(future, timeout=None):
try:
result = future.result(timeout=timeout)
return {"success": True, "result": result}
except CancelledError:
return {"success": False, "error": "cancelled"}
except TimeoutError:
return {"success": False, "error": "timeout"}
except Exception as e:
return {"success": False, "error": str(e)}
# Usage
with ThreadPoolExecutor() as executor:
future = executor.submit(slow_function, 5)
outcome = handle_future_result(future, timeout=2.0)
if outcome["success"]:
print(f"Result: {outcome['result']}")
else:
print(f"Failed: {outcome['error']}")These methods are primarily for use by Executor implementations:
def set_running_or_notify_cancel(self):
"""
Mark future as running or notify cancellation.
Returns:
bool: False if cancelled, True if set to running
Note: For internal use by executors
"""
def set_result(self, result):
"""
Set the future's result.
Parameters:
- result: The result value
Note: For internal use by executors
"""
def set_exception(self, exception):
"""
Set the future's exception.
Parameters:
- exception: The exception that occurred
Note: For internal use by executors
"""
def set_exception_info(self, exception, traceback):
"""
Set the future's exception with traceback.
Parameters:
- exception: The exception that occurred
- traceback: The traceback information
Note: For internal use by executors
"""Install with Tessl CLI
npx tessl i tessl/pypi-futures