Trollius and asyncio

Differences between Trollius and asyncio

Syntax of coroutines

The major difference between Trollius and asyncio is the syntax of coroutines:

asyncio Trollius
yield from ... yield From(...)
yield from [] yield From(None)
return raise Return()
return x raise Return(x)
return x, y raise Return(x, y)

Because of this major difference, it was decided to call the module trollius instead of asyncio. This choice also allows to use Trollius on Python 3.4 and later. Changing imports is not enough to use Trollius code with asyncio: the asyncio event loop explicit rejects coroutines using yield (instead of yield from).

OSError and socket.error exceptions

The OSError exception changed in Python 3.3: there are now subclasses like ConnectionResetError or BlockingIOError. The exception hierarchy also changed: socket.error is now an alias to OSError. The asyncio module is written for Python 3.3 and newer and so is based on these new exceptions.

On Python 3.2 and older, Trollius wraps OSError, IOError, socket.error and select.error exceptions on operating system and socket operations to raise more specific exceptions, subclasses of OSError:

  • trollius.BlockingIOError
  • trollius.BrokenPipeError
  • trollius.ChildProcessError
  • trollius.ConnectionAbortedError
  • trollius.ConnectionRefusedError
  • trollius.ConnectionResetError
  • trollius.FileNotFoundError
  • trollius.InterruptedError
  • trollius.PermissionError

On Python 3.3 and newer, these symbols are just aliases to builtin exceptions.

Note

ssl.SSLError exceptions are not wrapped to OSError, even if ssl.SSLError is a subclass of socket.error.

SSLError

On Python 3.2 and older, Trollius wraps ssl.SSLError exceptions to raise more specific exceptions, subclasses of ssl.SSLError, to mimic the Python 3.3:

  • trollius.SSLEOFError
  • trollius.SSLWantReadError
  • trollius.SSLWantWriteError

On Python 3.3 and newer, these symbols are just aliases to exceptions of the ssl module.

trollius.BACKPORT_SSL_ERRORS constant:

  • True if ssl.SSLError are wrapped to Trollius exceptions (Python 2 older than 2.7.9, or Python 3 older than 3.3),
  • False is trollius SSL exceptions are just aliases.

SSLContext

Python 3.3 has a new ssl.SSLContext class: see the documentaton of the ssl.SSLContext class.

On Python 3.2 and older, Trollius has a basic trollius.SSLContext class to mimic Python 3.3 API, but it only has a few features:

  • protocol, certfile and keyfile attributes
  • read-only verify_mode attribute: its value is CERT_NONE
  • load_cert_chain(certfile, keyfile) method
  • wrap_socket(sock, **kw) method: see the ssl.wrap_socket() documentation of your Python version for the keyword parameters

Example of missing features:

  • no options attribute
  • the verify_mode attriubte cannot be modified
  • no set_default_verify_paths() method
  • no “Server Name Indication” (SNI) support
  • etc.

On Python 3.2 and older, the trollius SSL transport does not have the 'compression' extra info.

trollius.BACKPORT_SSL_CONTEXT constant:

  • True if trollius.SSLContext is the backported class (Python 2 older than 2.7.9, or Python 3 older than 3.3),
  • False if trollius.SSLContext is just an alias to ssl.SSLContext.

Other differences

  • Trollius uses the TROLLIUSDEBUG envrionment variable instead of the PYTHONASYNCIODEBUG envrionment variable. TROLLIUSDEBUG variable is used even if the Python command line option -E is used.
  • asyncio.subprocess has no DEVNULL constant
  • Python 2 does not support keyword-only parameters.
  • If the concurrent.futures module is missing, BaseEventLoop.run_in_executor() uses a synchronous executor instead of a pool of threads. It blocks until the function returns. For example, DNS resolutions are blocking in this case.
  • Trollius has more symbols than asyncio for compatibility with Python older than 3.3:
    • From: part of yield From(...) syntax
    • Return: part of raise Return(...) syntax

Write code working on Trollius and asyncio

Trollius and asyncio are different, especially for coroutines (yield From(...) vs yield from ...).

To use asyncio or Trollius on Python 2 and Python 3, add the following code at the top of your file:

try:
    # Use builtin asyncio on Python 3.4+, or asyncio on Python 3.3
    import asyncio
except ImportError:
    # Use Trollius on Python <= 3.2
    import trollius as asyncio

It is possible to write code working on both projects using only callbacks. This option is used by the following projects which work on Trollius and asyncio:

  • AutobahnPython: WebSocket & WAMP for Python, it works on Trollius (Python 2.6 and 2.7), asyncio (Python 3.3) and Python 3.4 (asyncio), and also on Twisted.
  • Pulsar: Event driven concurrent framework for Python. With pulsar you can write asynchronous servers performing one or several activities in different threads and/or processes. Trollius 0.3 requires Pulsar 0.8.2 or later. Pulsar uses the asyncio module if available, or import trollius.
  • Tornado supports asyncio and Trollius since Tornado 3.2: tornado.platform.asyncio — Bridge between asyncio and Tornado. It tries to import asyncio or fallback on importing trollius.

Another option is to provide functions returning Future objects, so the caller can decide to use callback using fut.add_done_callback(callback) or to use coroutines (yield From(fut) for Trollius, or yield from fut for asyncio). This option is used by the aiodns project for example.

Since Trollius 0.4, it’s possible to use asyncio and Trollius coroutines in the same process. The only limit is that the event loop must be a Trollius event loop.

Note

The Trollius module was called asyncio in Trollius version 0.2. The module name changed to trollius to support Python 3.4.