User’s Guide


Obelus, as a network programming library, doesn’t want to be tied to a particular framework. Some people want to use Twisted, others Tornado, others asyncio. The solution is to provide APIs that are framework-agnostic. Everyone can then write their own adapters, though Obelus provides a couple of them (TornadoAdapter, TwistedAdapter).

Still, to avoid inventing yet another API, it was decided to settle on PEP 3156-like protocols.


asyncio doesn’t need any adapter: Obelus protocols can be used directly.

Bytes and strings

As a library that works both under Python 2 and Python 3, Obelus has to be careful about its bytes / test separation model. Since Asterisk itself doesn’t seem very careful in this regard, the following choice was made:

  • Under Python 2, all text and data is represented using the str class.
  • Under Python 3, binary data (going in and out of protocols) uses bytes objects, but all high-level data (such as command and action names and parameters) uses str objects. An utf-8 encoding is implied by default, but this can be changed. Encoding and decoding is handled by the protocols.

Futures, promises... handlers

Non-blocking network programming usually revolves around passing and invoking callbacks. To abstract that notion, Obelus defines a Handler class. When a library function performing an operation returns a handler, you can set its on_result and on_exception attributes to functions which will be called with the successful or exceptional result of the operation, respectively.

Protocols and transports


This section is only useful if you are writing your own protocol adapter, rather than using one of the provided ones.

A protocol is a class (or instance) implementing a particular network protocol. Obelus provides AMIProtocol and AGIProtocol. Protocols don’t do any I/O on their own: they don’t need any socket or file-like object. Rather, they use event-driven programming and callbacks.

Here are the standard event-driven methods on a protocol:


Signal that data has been received and should be processed by the protocol. Note that the protocol may only buffer the data, if e.g. it is incomplete.

data should be a bytestring.


Signal the protocol that the connection is established, and can be accessed (written to, or closed) using the given transport object.


Signal the protocol that the connection is lost, for whatever reason. If exc is not None, it is an exception instance giving information about the error that marked the connection lost.

Here are the methods which should be implemented by a transport (which is generally also your adapter instance):


Write the data (a bytestring) on the underlying connection.


Close the underlying connection.

See also

“Bidirectional Stream Transports” and “Stream Protocols” in PEP 3156.

Writing an adapter

An adapter should implement the two required transport methods (write(), close()), and be able to call the three aforementioned protocol methods (connection_made(), data_received(), connection_lost()).

Asterisk Management Interface

The AMI allows you to connect to a well-known TCP port on your Asterisk server. You can then emit commands (“actions”) to it, receive response and asynchronous events sent by the server.

You can interact with the AMI using the obelus.ami.AMIProtocol.

To send actions, call the send_action() method. To listen to specific events, call the register_event_handler() method.


The first action you’ll send should be the login action with appropriate username and secret headers.


What actions you can emit and what events you can receive depends on the Asterisk configuration (especially the manager.conf file). Please consult the Asterisk docs.

See also

Unofficial Asterisk manager API documentation at

Making calls

The obelus.ami.CallManager class helps you originate calls using an AMIProtocol instance and track their status changes.

Asterisk Gateway Interface

The AGI works in reverse. You cannot “connect” using the AGI to your Asterisk instance. Rather, Asterisk will initiate an AGI communication whenever its dialplan tells it to do so.

AGI is a very simple command / response protocol. The AGI-implementing application can only send commands, to which Asterisk replies when it has finished. No events cannot be notified. Furthermore, an AGI communication happens on a well-defined channel (in the Asterisk sense) and cannot cross that boundary.

There are several ways an AGI communication can be initiated by Asterisk, depending on its configuration:

  • By executing a script on the filesystem, like a Web server would execute a CGI script (hence the name). The communication is carried over stdin and stdout, until either end closes the pipe. This is “traditional” AGI or AGI in short.
  • By contacting a TCP server listening on a given host and port. If the server accepts the incoming connection, the communication is carried over the resulting TCP connection, until the connection is terminated by either end. This is called “FastAGI” (by analogy with FastCGI, perhaps).
  • By encapsulating the AGI communication over a series of AMI events and actions. This is called “Async AGI”.

Obelus provides support for FastAGI and Async AGI (using AsyncAGIExecutor).