API

The API is identical whether you’re using Twisted or asyncio under the hood. Two bool variables are available if you need to know which framework is in use, and two helpers to enforce one or the other framework.

Explicitly Selecting a Framework

Until you explicitly select a framework, all txaio API methods just throw a usage error. So, you must call .use_twisted() or .use_asyncio() as appropriate. These will fail with ImportError if you don’t have the correct dependencies.

import txaio
txaio.use_twisted()
txaio.use_asyncio()

Set an Event Loop / Reactor

You can set txaio.config.loop to either an EventLoop instance (if using asyncio) or an explicit reactor (if using Twisted). By default, reactor is imported from twisted.internet on the first call_later invocation. For asyncio, asyncio.get_event_loop() is called at import time.

If you’ve installed your reactor before import txaio you shouldn’t need to do anything.

Note that under Twisted, only the IReactorTime interface is required.

Test Helpers

Test utilities are in txaio.testutil. There is a context-manager for testing delayed calls; see test_call_later.py for an example.

txaio.testutil.replace_loop(*args, **kwds)[source]

This is a context-manager that sets the txaio event-loop to the one supplied temporarily. It’s up to you to ensure you pass an event_loop or a reactor instance depending upon asyncio/Twisted.

Use like so:

from twisted.internet import task
with replace_loop(task.Clock()) as fake_reactor:
    f = txaio.call_later(5, foo)
    fake_reactor.advance(10)
    # ...etc

txaio module

txaio.using_twisted

True only if we’re using Twisted as our underlying event framework

txaio.using_asyncio

True only if we’re using asyncio as our underlying event framework

txaio.use_asyncio()[source]

Select asyncio framework (uses trollius/tulip on Pythons that lack asyncio).

txaio.use_twisted()[source]

Select the Twisted framework (will fail if Twisted is not installed).

txaio.create_future(result=None, error=None, canceller=None)

Create and return a new framework-specific future object. On asyncio this returns a Future, on Twisted it returns a Deferred.

Parameters:
  • result – if not None, the future is already fulfilled, with the given result.
  • error (class:IFailedFuture or Exception) – if not None then the future is already failed, with the given error.
  • canceller – a single-argument callable which is invoked if this future is cancelled (the single argument is the future object which has been cancelled)
Raises:

ValueError – if both value and error are provided.

Returns:

under Twisted a Deferred, under asyncio a Future

txaio.as_future(func, *args, **kwargs)

Call func with the provided arguments and keyword arguments, and always return a Future/Deferred. If func itself returns a future, that is directly returned. If it immediately succeed or failed then an already-resolved Future/Deferred is returned instead.

This allows you to write code that calls functions (e.g. possibly provided from user-code) and treat them uniformly. For example:

p = txaio.as_future(some_function, 1, 2, key='word')
txaio.add_callbacks(p, do_something, it_failed)

You therefore don’t have to worry if the underlying function was itself asynchronous or not – your code always treats it as asynchronous.

txaio.reject(future, error=None)

Resolve the given future as failed. This will call any errbacks registered against this Future/Deferred. On Twisted, the errback is called with a bare Failure instance; on asyncio we provide an object that implements IFailedFuture because there is no equivalent in asyncio (this mimics part of the Failure API).

Parameters:
  • future – an unresolved Deferred/Future as returned by create_future()
  • error (IFailedFuture or Exception) – The error to fail the Deferred/Future with. If this is None, sys.exc_info() is used to create an txaio.IFailedFuture (or Failure) wrapping the current exception (so in this case it must be called inside an except: clause).
txaio.cancel(future)

Cancel the given future. If a canceller was registered, it is invoked now. It is invalid to resolve or reject the future after cancelling it.

Parameters:future – an unresolved Deferred/Future as returned by create_future()
txaio.resolve(future, value)

Resolve the given future with the provided value. This triggers any callbacks registered against this Future/Deferred.

txaio.add_callbacks(future, callback, errback)

Adds the provided callback and/or errback to the given future. To add multiple callbacks, call this method multiple times. For example, to add just an errback, call add_callbacks(p, None, my_errback)

Note that txaio doesn’t do anything special with regards to callback or errback chaining – it is highly recommended that you always return the incoming argument unmodified in your callback/errback so that Twisted and asyncio behave the same. For example:

def callback_or_errback(value):
    # other code
    return value
Raises:ValueError – if both callback and errback are None
txaio.failure_message(fail)

Takes an txaio.IFailedFuture instance and returns a formatted message suitable to show to a user. This will be a str with no newlines for the form: {exception_name}: {error_message} where error_message is the result of running str() on the exception instance (under asyncio) or the result of .getErrorMessage() on the Failure under Twisted.

txaio.failure_traceback(fail)

Take an txaio.IFailedFuture instance and returns the Python traceback instance associated with the failure.

failure_format_traceback(fail):

Take an txaio.IFailedFuture instance and returns a formatted string showing the traceback. Typically, this will have many newlines in it and look like a “normal” Python traceback.

txaio.call_later(delay, func, *args, **kwargs)

This calls the function func with the given parameters at the specified time in the future. Although asyncio doesn’t directly support kwargs with loop.call_later we wrap it in a functools.partial, as asyncio documentation suggests.

Note: see txaio.make_batched_timer() if you may have a lot of timers, and their absolute accuracy isn’t very important.

Parameters:delay – how many seconds in the future to make the call
Returns:The underlying library object, which will at least have a .cancel() method on it. It’s really IDelayedCall in Twisted and a Handle in asyncio.
txaio.make_batched_timer(seconds_per_bucket, chunk_size)

This returns an object implementing txaio.IBatchedTimer such that any .call_later calls done through it (instead of via txaio.call_later()) will be “quantized” into buckets and processed in chunk_size batches “near” the time they are supposed to fire. seconds_per_bucket is only accurate to “milliseconds”.

When there are “tens of thousands” of outstanding timers, CPU usage can become a problem – if the accuracy of the timers isn’t very important, using “batched” timers can greatly reduce the number of “real” delayed calls in the event loop.

For example, Autobahn uses this feature for auto-ping timeouts, where the exact time of the event isn’t extremely important – but there are 2 outstanding calls per connection.

txaio.gather(futures, consume_exceptions=True)

Returns a new Future that waits for the results from all the futures provided.

The Future/Deferred returned will callback with a list the same length as futures containing either the return value from each future, or an IFailedFuture/Failure instance if it failed.

Note that on Twisted, we use DeferredList which usually returns a list of 2-tuples of (status, value). We do inject a callback that unpacks this list to be just the value (or Failure) so that your callback can be identical on Twisted and asyncio.

txaio.make_logger()

Creates and returns an instance of ILogger. This can pick up context from where it’s instantiated (e.g. the containing class or module) so the best way to use this is to create a logger for each class that produces logs; see the example in ILogger ‘s documentation

class txaio.interfaces.ILogger[source]

Bases: object

This defines the methods you can call on the object returned from txaio.make_logger() – although the actual object may have additional methods, you should only call the methods listed here.

All the log methods have the same signature, they just differ in what “log level” they represent to the handlers/emitters. The message argument is a format string using PEP3101-style references to things from the kwargs. Note that there are also the following keys added to the kwargs: log_time and log_level.

For example:

class MyThing(object):
    log = txaio.make_logger()

    def something_interesting(self, things=dict(one=1, two=2)):
        try:
            self.log.debug("Called with {things[one]}", things=things)
            result = self._method_call()
            self.log.info("Got '{result}'.", result=result)
        except Exception:
            fail = txaio.create_failure()
            self.log.critical(txaio.failure_format_traceback(fail))

The philsophy behind txaio’s interface is fairly similar to Twisted’s logging APIs after version 15. See Twisted’s documentation for details.

critical(message, **kwargs)[source]

log a critical-level message

error(message, **kwargs)[source]

log a error-level message

warn(message, **kwargs)[source]

log a error-level message

info(message, **kwargs)[source]

log an info-level message

debug(message, **kwargs)[source]

log an debug-level message

trace(message, **kwargs)[source]

log a trace-level message

class txaio.interfaces.IFailedFuture[source]

Bases: object

This defines the interface for a common object encapsulating a failure from either an asyncio task/coroutine or a Twisted Deferred.

An instance implementing this interface is given to any errback callables you provide via txaio.add_callbacks()

In your errback you can extract information from an IFailedFuture with txaio.failure_message() and txaio.failure_traceback() or use .value to get the Exception instance.

Depending on other details or methods will probably cause incompatibilities between asyncio and Twisted.

value

An actual Exception instance. Same as the second item returned from sys.exc_info()