Proxy futures: f_proxy

The f_proxy function allows wrapping a future with a proxy which will pass attribute lookups and method calls through to the underlying result, blocking as needed.

The primary goal of f_proxy is to make it possible to define APIs which support both blocking and non-blocking coding styles.

Example

Imagine we have defined some classes as follows:

class DatabaseService:
    def get_connection(self):
        """Obtain a connection to this application's database.
        Returns a Future[DatabaseConnection]."""
        ...

class DatabaseConnection:
    def query(self, sql, *params):
        """Perform an SQL query using this connection.
        Returns a Future[DatabaseCursor]."""
        ...

class DatabaseCursor:
    def __iter__(self):
        """Iterate over all results referenced by this cursor."""
        ...

This API could be used with a non-blocking coding style by composing futures:

def process_results(cursor):
    for row in cursor:
       # assume it does something useful with each row
       ...

connection = db_service.get_connection()
cursor = f_flat_map(connection, lambda c: c.query(some_sql))
results = f_map(cursor, process_results)

Or it could be used in a blocking coding style by adding calls to .result():

connection = db_service.get_connection().result()
cursor = connection.query(some_sql).result()
results = process_results(cursor)

If we define the API as returning proxy futures (i.e. wrap each returned future using f_proxy), the above two code snippets will continue to work, and the below example also becomes possible: using the API in a blocking coding style without requiring explicit calls to .result():

connection = db_service.get_connection()
cursor = connection.query(some_sql)
results = process_results(cursor)
more_executors.f_proxy(f, timeout=None)

Proxy calls on a future through to the future’s result.

The value returned by this function is a future resolved with the same result (or exception) as the input future f. It will also proxy most attribute lookups and method calls through to the underlying result, awaiting the result when needed.

Note that since the returned value is intended to remain usable as a Future, this proxy is relatively conservative and avoids proxying functionality which would clash with the Future interface.

Functionality which is not proxied includes:

  • conversion to boolean (__bool__)

  • conversion to string (__str__, __repr__)

  • methods relating to object identity (__eq__, __hash__)

Signature: Future<X> Future<X>

Parameters
  • f (Future) – Any future.

  • timeout (float) – Timeout applied when awaiting the future’s result during proxied calls.

Returns

Future

a Future which proxies calls through to the future’s result as needed.

New in version 2.3.0.