aiomas 2.0.1
Asyncio-based, layered networking library providing request-reply channels, RPC, and multi-agent systems.
Requires Python: >=3.5

aiomas – A library for multi-agent systems and RPC based on asyncio
===================================================================

.. image:: https://gitlab.com/sscherfke/aiomas/badges/master/pipeline.svg
   :height: 20px
   :alt: pipeline status
   :target: https://gitlab.com/sscherfke/aiomas/commits/master

.. image:: https://gitlab.com/sscherfke/aiomas/badges/master/coverage.svg
   :height: 20px
   :alt: coverage report
   :target: https://gitlab.com/sscherfke/aiomas/commits/master

*aiomas* is an easy-to-use library for *request-reply channels*, *remote
procedure calls (RPC)* and *multi-agent systems (MAS)*.  It’s written in pure
Python on top of asyncio__.

Here are three simple examples that show the different layers of aiomas and
what they add on top of each other:

The *request-reply channel* has the lowest level of abstraction (but already
offers more then vanilla asyncio):

.. code-block:: python3

   >>> import aiomas
   >>>
   >>>
   >>> async def handle_client(channel):
   ...     """Handle a client connection."""
   ...     req = await channel.recv()
   ...     print(req.content)
   ...     await req.reply('cya')
   ...     await channel.close()
   >>>
   >>>
   >>> async def client():
   ...     """Client coroutine: Send a greeting to the server and wait for a
   ...     reply."""
   ...     channel = await aiomas.channel.open_connection(('localhost', 5555))
   ...     rep = await channel.send('ohai')
   ...     print(rep)
   ...     await channel.close()
   >>>
   >>>
   >>> server = aiomas.run(aiomas.channel.start_server(('localhost', 5555), handle_client))
   >>> aiomas.run(client())
   ohai
   cya
   >>> server.close()
   >>> aiomas.run(server.wait_closed())

The *RPC layer* adds remote procedure calls on top of it:

.. code-block:: python3

   >>> import aiomas
   >>>
   >>>
   >>> class MathServer:
   ...     router = aiomas.rpc.Service()
   ...
   ...     @router.expose
   ...     def add(self, a, b):
   ...         return a + b
   ...
   >>>
   >>> async def client():
   ...     """Client coroutine: Call the server's "add()" method."""
   ...     rpc_con = await aiomas.rpc.open_connection(('localhost', 5555))
   ...     rep = await rpc_con.remote.add(3, 4)
   ...     print('What’s 3 + 4?', rep)
   ...     await rpc_con.close()
   >>>
   >>> server = aiomas.run(aiomas.rpc.start_server(('localhost', 5555), MathServer()))
   >>> aiomas.run(client())
   What’s 3 + 4? 7
   >>> server.close()
   >>> aiomas.run(server.wait_closed())

Finally, the *agent layer* hides some of the boilerplate code required to setup
the sockets and allows agent instances to easily talk with each other:

.. code-block:: python3

   >>> import aiomas
   >>>
   >>> class TestAgent(aiomas.Agent):
   ...     def __init__(self, container):
   ...         super().__init__(container)
   ...         print('Ohai, I am %s' % self)
   ...
   ...     async def run(self, addr):
   ...         remote_agent = await self.container.connect(addr)
   ...         ret = await remote_agent.service(42)
   ...         print('%s got %s from %s' % (self, ret, remote_agent))
   ...
   ...     @aiomas.expose
   ...     def service(self, value):
   ...         return value
   >>>
   >>> c = aiomas.Container.create(('localhost', 5555))
   >>> agents = [TestAgent(c) for i in range(2)]
   Ohai, I am TestAgent('tcp://localhost:5555/0')
   Ohai, I am TestAgent('tcp://localhost:5555/1')
   >>> aiomas.run(until=agents[0].run(agents[1].addr))
   TestAgent('tcp://localhost:5555/0') got 42 from TestAgentProxy('tcp://localhost:5555/1')
   >>> c.shutdown()

*aiomas* is released under the MIT license. It requires Python 3.4 and above
and runs on Linux, OS X, and Windows.

__ https://docs.python.org/3/library/asyncio.html


Installation
------------

*aiomas* requires Python >= 3.6 (or PyPy3 >= 5.10.0).  It uses the *JSON* codec
by default and only has pure Python dependencies.

Install *aiomas* via pip__ by running:

.. code-block:: bash

   $ pip install aiomas

You can enable the optional MsgPack__ codec or its Blosc__ compressed version
by installing the corresponding features (note, that you need a C compiler to
install them):

.. code-block:: bash

   $ pip install aiomas[mp]   # Enables the MsgPack codec
   $ pip install aiomas[mpb]  # Enables the MsgPack and MsgPackBlosc codecs

__ https://pip.pypa.io/
__ https://pypi.python.org/pypi/msgpack-python/
__ https://pypi.python.org/pypi/blosc/


Features
--------

*aiomas* just puts three layers of abstraction around raw TCP / unix domain
sockets provided by *asyncio*:

Agents and agent containers:
  The top-layer provides a simple base class for your own agents. All agents
  live in a container.

  Containers take care of creating agent instances and performing the
  communication between them.

  The container provides a *clock* for the agents. This clock can either be
  synchronized with the real (wall-clock) time or be set by an external process
  (e.g., other simulators).

RPC:
  The *rpc* layer implements remote procedure calls which let you call methods
  on remote objects nearly as if they were normal objects:

  Instead of ``ret = obj.meth(arg)`` you write ``ret = await obj.meth(arg)``.

Request-reply channel:
  The *channel* layer is the basis for the *rpc* layer. It sends JSON__ or
  MsgPack__ encoded byte strings over TCP or unix domain sockets. It also maps
  replies (of success or failure) to their corresponding request.

Other features:

- TLS support for authorization and encrypted communication.

- Interchangeable and extensible codecs: JSON and MsgPack (the latter
  optionally compressed with Blosc) are built-in.  You can add custom codecs or
  write (de)serializers for your own objects to extend a codec.

- Deterministic, emulated sockets: A *LocalQueue* transport lets you send and
  receive message in a deterministic and reproducible order within a single
  process.  This helps testing and debugging distributed algorithms.

__ http://www.json.org/
__ http://msgpack.org/


Planned features
^^^^^^^^^^^^^^^^

Some ideas for future releases:

- Optional automatic re-connect after connection loss


Contribute
----------

- Issue Tracker: https://gitlab.com/sscherfke/aiomas/issues
- Source Code: https://gitlab.com/sscherfke/aiomas

Set-up a development environment with:

.. code-block:: bash

   $ virtualenv -p `which python3` aiomas
   $ pip install -r requirements-setup.txt

Run the tests with:

.. code-block:: bash

   $ pytest
   $ # or
   $ tox


Support
-------

- Documentation: https://aiomas.readthedocs.io/en/latest/

- Mailing list: https://groups.google.com/forum/#!forum/python-tulip

- Stack Overflow: http://stackoverflow.com/questions/tagged/aiomas

- IRC: #asyncio


License
-------

The project is licensed under the MIT license.


Changelog
=========

2.0.1 – 2017-12-29
------------------

- [CHANGE] Restore support for Python 3.5 so that the docs on Read the Docs
  build again.


2.0.0 – 2017-12-28
------------------

- [BREAKING] Converted to f-Strings and ``async``/``await`` syntax.  The
  minimum required Python versions are now Python 3.6 and PyPy3 5.10.0.

- [BREAKING] Removed ``aiomas.util.async()`` and ``aiomas.util.create_task()``.

- [CHANGE] Move from Bitbucket and Mercurial to GitLab and Git.

- [FIX] Adjust to asyncio changes and explicitly pass references to the current
  event loop where necessary.

You can find information about older versions in the `documentation
<https://aiomas.readthedocs.io/en/latest/development/changelog.html>`_.


Authors
=======

The original author of aiomas is Stefan Scherfke.

The initial development has kindly been supported by `OFFIS
<www.offis.de/en/>`_.