From 44badca2e4bdc2fefac1049ba9a524a02b1f6e10 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 21 Nov 2014 12:44:37 +0100 Subject: doc: add photo; add openstack section --- README | 4 +- doc/changelog.rst | 44 +++++++ doc/index.rst | 319 ++++------------------------------------------- doc/openstack.rst | 167 +++++++++++++++++++++++++ doc/poplar_hawk-moth.jpg | Bin 0 -> 34320 bytes doc/status.rst | 69 ++++++++++ doc/using.rst | 169 +++++++++++++++++++++++++ 7 files changed, 475 insertions(+), 297 deletions(-) create mode 100644 doc/changelog.rst create mode 100644 doc/openstack.rst create mode 100644 doc/poplar_hawk-moth.jpg create mode 100644 doc/status.rst create mode 100644 doc/using.rst diff --git a/README b/README index ac45488..e128531 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -aiogreen implements the asyncio API on top of eventet. It makes possible to -write asyncio code in a project currently written for eventlet. +aiogreen implements the asyncio API (PEP 3156) on top of eventet. It makes +possible to write asyncio code in a project currently written for eventlet. aiogreen allows to use greenthreads in asyncio coroutines, and to use asyncio coroutines, tasks and futures in greenthreads: see ``link_future()`` and diff --git a/doc/changelog.rst b/doc/changelog.rst new file mode 100644 index 0000000..1f4f9f1 --- /dev/null +++ b/doc/changelog.rst @@ -0,0 +1,44 @@ +Changelog +========= + +Version 0.2 (development version) +--------------------------------- + +The core of the event loop was rewritten to fits better in asyncio and +eventlet. aiogreen now reuses more code from asyncio/trollius. The code +handling file descriptors was also fixed to respect asyncio contract: +only call the callback once per loop iteration. + +Changes: + +* Add a Sphinx documentation published at http://aiogreen.readthedocs.org/ +* Add the :func:`link_future` function: wait for a future from a + greenthread. +* Add the :func:`wrap_greenthread` function: wrap a greenthread into a Future +* Support also eventlet 0.14, not only eventlet 0.15 or newer +* Support eventlet with monkey-patching +* Rewrite the code handling file descriptors to ensure that the listener is + only called once per loop iteration, to respect asyncio specification. +* Simplify the loop iteration: remove custom code to reuse instead the + asyncio/trollius code (_run_once) +* Reuse call_soon, call_soon_threadsafe, call_at, call_later from + asyncio/trollius, remove custom code +* sock_connect() is now asynchronous +* Add a suite of automated unit tests +* Fix EventLoop.stop(): don't stop immediatly, but schedule stopping the event + loop with call_soon() +* Add tox.ini to run tests with tox +* Setting debug mode of the event loop doesn't enable "debug_blocking" of + eventlet on Windows anymore, the feature is not implemented on Windows + in eventlet. +* add_reader() and add_writer() now cancels the previous handle and sets + a new handle +* In debug mode, detect calls to call_soon() from greenthreads which are not + threadsafe (would not wake up the event loop). +* Only set "debug_exceptions" of the eventlet hub when the debug mode of the + event loop is enabled. + +2014-11-19: version 0.1 +----------------------- + +* First public release diff --git a/doc/index.rst b/doc/index.rst index 52306ae..b135d71 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,8 +1,14 @@ aiogreen ======== -aiogreen implements the asyncio API on top of eventet. It makes possible to -write asyncio code in a project currently written for eventlet. +.. image:: poplar_hawk-moth.jpg + :alt: Poplar Hawk-moth (Laothoe populi), photo taken in France + :align: right + :target: https://www.flickr.com/photos/haypo/7181768969/in/set-72157629731066236 + +aiogreen implements the asyncio API (`PEP 3156 +`_) on top of eventet. It makes +possible to write asyncio code in a project currently written for eventlet. aiogreen allows to use greenthreads in asyncio coroutines, and to use asyncio coroutines, tasks and futures in greenthreads: see :func:`link_future` and @@ -14,308 +20,31 @@ greenthread with aiogreen. It means that it's possible to call ``run_forever()`` in the main thread and execute other greenthreads in parallel. -aiogreen: - * `aiogreen documentation `_ * `aiogreen project in the Python Cheeseshop (PyPI) `_ * `aiogreen project at Bitbucket `_ * Copyright/license: Open source, Apache 2.0. Enjoy! -Event loops: - -* `asyncio documentation `_ -* `trollus documentation `_ -* `eventlet documentation `_ -* `eventlet project `_ -* `greenlet documentation `_ -* `Tulip project `_ - - -Usage -===== - -Use aiogreen with trollius -------------------------- - -To support Python 2, you can use Trollius which uses ``yield`` instead -of ``yield from`` for coroutines: -http://trollius.readthedocs.org/ - -To use aiogreen with trollius, set the event loop policy before using an event -loop, example:: - - import aiogreen - import trollius - - trollius.set_event_loop_policy(aiogreen.EventLoopPolicy()) - # .... - -Hello World:: - - import aiogreen - import trollius as asyncio - - def hello_world(): - print("Hello World") - loop.stop() - - asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) - loop = asyncio.get_event_loop() - loop.call_soon(hello_world) - loop.run_forever() - loop.close() - - -Use aiogreen with asyncio -------------------------- - -aiogreen implements the asyncio API, see asyncio documentation: -https://docs.python.org/dev/library/asyncio.html - -eventlet 0.15 supports Python 3 if monkey-patching is not used. - -To use aiogreen with asyncio, set the event loop policy before using an event -loop, example:: - - import aiogreen - import asyncio - - asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) - # .... - -Adding this code should be enough to try examples of the asyncio documentation. - -Hello World:: - - import aiogreen - import asyncio - - def hello_world(): - print("Hello World") - loop.stop() - - asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) - loop = asyncio.get_event_loop() - loop.call_soon(hello_world) - loop.run_forever() - loop.close() - - -API -=== - -aiogreen specific functions: - -.. function:: link_future(future) - - Wait for a future (or a task) from a greenthread. - Return the result or raise the exception of the future. - - Example with asyncio:: - - @asyncio.coroutine - def coro_slow_sum(x, y): - yield from asyncio.sleep(1.0) - return x + y - - def green_sum(): - task = asyncio.async(coro_slow_sum(1, 2)) - value = aiogreen.link_future(task) - return value - -.. function:: wrap_greenthread(gt) - - Wrap a greenthread into a Future object. - - The Future object waits for the completion of a greenthread. - - Example with asyncio:: - - def slow_sum(x, y): - eventlet.sleep(1.0) - return x + y - - @asyncio.coroutine - def coro_sum(): - gt = eventlet.spawn(slow_sum, 1, 2) - fut = aiogreen.wrap_greenthread(gt, loop=loop) - result = yield from fut - return result - - .. note:: - If the debug mode of event loop is set, when a greenthread raises an - exception, the exception is logged to ``sys.stderr`` by eventlet, even if - the exception is copied to the Future object as expected. - +Table Of Contents +================= -Installation -============ +.. toctree:: -Requirements: + using + status + openstack + changelog -- eventlet 0.14 or newer -- asyncio or trollius: - - * Python 3.4 and newer: asyncio is now part of the stdlib - * Python 3.3: need Tulip 0.4.1 or newer (pip install asyncio), - but Tulip 3.4.1 or newer is recommended - * Python 2.6-3.2: need Trollius 0.3 or newer (pip install trollius), - but Trollius 1.0 or newer is recommended - -Type:: - - pip install aiogreen - -or:: - - python setup.py install - - -Run tests -========= - -Run tests with tox ------------------- - -The `tox project `_ can be used to build a -virtual environment with all runtime and test dependencies and run tests -against different Python versions (2.6, 2.7, 3.2, 3.3). - -For example, to run tests with Python 2.7, just type:: - - tox -e py27 - -To run tests against other Python versions: - -* ``py26``: Python 2.6 -* ``py27``: Python 2.7 -* ``py27_patch``: Python 2.7 with eventlet monkey patching -* ``py32``: Python 3.2 -* ``py33``: Python 3.3 -* ``py34``: Python 3.4 - -Run tests manually ------------------- - -Run the following command from the directory of the aiogreen project:: - - python runtests.py -r - - -Changelog -========= - -Version 0.2 (development version) ---------------------------------- - -The core of the event loop was rewritten to fits better in asyncio and -eventlet. aiogreen now reuses more code from asyncio/trollius. The code -handling file descriptors was also fixed to respect asyncio contract: -only call the callback once per loop iteration. - -Changes: - -* Add a Sphinx documentation published at http://aiogreen.readthedocs.org/ -* Add the :func:`link_future` function: wait for a future from a - greenthread. -* Add the :func:`wrap_greenthread` function: wrap a greenthread into a Future -* Support also eventlet 0.14, not only eventlet 0.15 or newer -* Support eventlet with monkey-patching -* Rewrite the code handling file descriptors to ensure that the listener is - only called once per loop iteration, to respect asyncio specification. -* Simplify the loop iteration: remove custom code to reuse instead the - asyncio/trollius code (_run_once) -* Reuse call_soon, call_soon_threadsafe, call_at, call_later from - asyncio/trollius, remove custom code -* sock_connect() is now asynchronous -* Add a suite of automated unit tests -* Fix EventLoop.stop(): don't stop immediatly, but schedule stopping the event - loop with call_soon() -* Add tox.ini to run tests with tox -* Setting debug mode of the event loop doesn't enable "debug_blocking" of - eventlet on Windows anymore, the feature is not implemented on Windows - in eventlet. -* add_reader() and add_writer() now cancels the previous handle and sets - a new handle -* In debug mode, detect calls to call_soon() from greenthreads which are not - threadsafe (would not wake up the event loop). -* Only set "debug_exceptions" of the eventlet hub when the debug mode of the - event loop is enabled. - -2014-11-19: version 0.1 ------------------------ - -* First public release - - -Implemented +Event loops =========== -Methods: - -* call_at() -* call_later() -* call_soon() -* run_forever() -* run_in_executor() -* run_until_complete() -* create_connection(): TCP client -* stop() -* coroutines and tasks - -Tests of aiogreen 0.1: - -* Tested on Python 2.7, 3.3 and 3.5 -* Tested on Linux and Windows -* Tested with Trollius 1.0, 1.0.1 and 1.0.2 -* Tested with asyncio 0.4.1 and 3.4.2 - - -To do (Not supported) -===================== - -* add_reader() does only support one callback per file descriptor currently. -* run an event loop in a thread different than the main thread -* sockets: create_server, sock_recv -* pipes: connect_read_pipe -* subprocesses: need pipes -* signal handlers: add_signal_handler (only for pyevent hub?) -* tox.ini: add py33_patch. eventlet with Python 3 and monkey-patch causes - an issue in importlib. - - -eventlet issues -=============== - -* eventlet monkey patching on Python 3 is incomplete. The most blocking issue - is in the importlib: the thread module is patched to use greenthreads, but - importlib really need to work on real threads. Pull request: - https://github.com/eventlet/eventlet/pull/168 -* eventlet.tpool.setup() seems to be broken on Windows in eventlet 0.15. - Pull request: - https://github.com/eventlet/eventlet/pull/167 -* hub.debug_blocking is implemented with signal.alarm() which is is not - available on Windows. - - -eventlet and Python 3 -===================== - -Issues: - -* https://github.com/eventlet/eventlet/issues/6 (root py3 issue) -* https://github.com/eventlet/eventlet/issues/157 (py3 related?) -* https://github.com/eventlet/eventlet/issues/153 (py3 related?) - -Pull requests: - -* https://github.com/eventlet/eventlet/pull/99 : complete monkey-patching -* => commit: https://github.com/therve/eventlet/commit/9c3118162cf1ca1e50be330ba2a289f054c48d3c -* https://github.com/eventlet/eventlet/pull/160 (py3 related?) - -OpenStack Kilo Summit: +* `asyncio documentation `_ +* `trollius documentation `_ +* `tulip project `_ +* `eventlet documentation `_ +* `eventlet project `_ +* `greenlet documentation `_ -* https://etherpad.openstack.org/p/kilo-oslo-python-3 -* https://etherpad.openstack.org/p/kilo-oslo-oslo.messaging -* https://etherpad.openstack.org/p/py34-transition (tangentially related) +See also the `greenio project `_: +"Greenlets support for asyncio (PEP 3156)". diff --git a/doc/openstack.rst b/doc/openstack.rst new file mode 100644 index 0000000..2cae95d --- /dev/null +++ b/doc/openstack.rst @@ -0,0 +1,167 @@ +asyncio in OpenStack +==================== + +First part (in progress): add support for trollius coroutines +------------------------------------------------------------- + +Prepare OpenStack (Oslo Messaging) to support trollius coroutines using +``yield``: explicit asynchrounous programming. Eventlet is still supported, +used by default, and applications and libraries don't need to be modified at +this point. + +Already done: + +* Write the trollius project: port asyncio to Python 2 +* Stabilize trollius API +* Add trollius dependency to OpenStack +* Write the aiogreen project to provide the asyncio API on top of eventlet + +To do: + +* Stabilize aiogreen API +* Add aiogreen dependency to OpenStack +* Write an aiogreen executor for Oslo Messaging: rewrite greenio executor + to replace greenio with aiogreen + +Second part (to do): rewrite code as trollius coroutines +-------------------------------------------------------- + +Switch from implicit asynchrounous programming (eventlet using greenthreads) to +explicit asynchronous programming (trollius coroutines using ``yield``). Need +to modify OpenStack Common Libraries and applications. Modifications can be +done step by step, the switch will take more than 6 months. + +The first application candidate is Ceilometer. The Ceilometer project is young, +developers are aware of eventlet issues and like Python 3, and Ceilometer don't +rely so much on asynchronous programming: most time is spent into waiting the +database anyway. + +The goal is to port Ceilometer to explicit asynchronous programming during the +cycle of OpenStack Kilo. + +Some applications may continue to use implicit asynchronous programming. For +example, nova is probably the most complex part beacuse it is and old project +with a lot of legacy code, it has many drivers and the code base is large. + +To do: + +* Ceilometer: add trollius dependency and set the trollius event loop policy to + aiogreen +* Ceilometer: change Oslo Messaging executor from "eventlet" to "aiogreen" +* Redesign the service class of Oslo Incubator to support aiogreen and/or + trollius. Currently, the class is designed for eventlet. The service class + is instanciated before forking, which requires hacks on eventlet to update + file descriptors. +* In Ceilometer and its OpenStack depedencencies: add new functions which + are written with explicit asynchronous programming in mind (ex: trollius + coroutines written with ``yield``). +* Rewrite Ceilometer endpoints (RPC methods) as trollius coroutines. + +Questions: + +* What about WSGI? aiohttp is not compatible with trollius yet. +* The quantity of code which need to be ported to asynchronous programming is + unknown right now. +* We should be prepared to see deadlocks. OpenStack was designed for eventlet + which implicitly switch on blocking operations. Critical sections may not be + protected with locks, or not the right kind of lock. +* For performances, blocking operations can be executed in threads. OpenStack + code is probably not thread-safe, which means new kinds of race conditions. + But the code executed in threads will be explicitly scheduled to be executed + in a thread (with ``loop.run_in_executor()``), so regressions can be easily + identified. +* This part will take a lot of time. We may need to split it into subparts + to have milestones, which is more attractive for developers. + + +Last part (to do): drop eventlet +-------------------------------- + +Replace aiogreen event loop with trollius event loop, drop aiogreen and drop +eventlet at the end. + +This change will be done on applications one by one. This is no need to port +all applications at once. The work will start on Ceilometer, as a follow up +of the second part. + +To do: + +* Port remaining code to trollius +* Write a "trollius" executor for Oslo Messaging +* Ceilometer: Add a blocking call to ``loop.run_forever()`` in the ``main()`` + function +* Ceilometer: Replace "aiogreen" executor with "trollius" executor +* Ceilometer: Use the standard trollius event loop policy +* Ceilometer: drop the eventlet dependency + +Questions: + +* Putting a blocking call to ``loop.run_forever()`` may need to redesign + Ceilometer, this part is unclear to me right now. + +Optimization, can be done later: + +* Oslo Messaging: watch directly the underlying file descriptor of sockets, + instead of using a busy loop polling the notifier +* Ceilometer: use libraries supporting directly trollius to be able to run + parallel tasks (ex: send multiple requests to a database) + + +History +------- + +Maybe the good one, aiogreen project: + +* November 19, 2014: First release of the aiogreen project + +New try with a greenio executor for Oslo Messaging: + +* July 29, 2014: Doug Hellmann proposed the blueprint + `A 'greenio' executor for oslo.messaging + `_, + approved by Mark McLoughlin. +* Jul 24, 2014: `Add greenio dependency `_ + merged into openstack/requirements +* Jul 22, 2014: Patch `Add a new greenio executor + `_ proposed to Oslo Messaging +* July 21, 2014: Release of greenio 0.6 which is now compatible with Trollius +* July 21, 2014: Release of Trollius 1.0 +* Jul 14, 2014: Patch `Add a 'greenio' oslo.messaging executor (spec) + `_ merged into openstack/oslo-specs. +* July 7, 2014: Patch `Fix AMQPListener for polling with timeout + `_ merged into Oslo Messaging +* July: greenio executor, `[openstack-dev] [oslo] Asyncio and oslo.messaging + `_ + +First try with a trollius executor for Oslo Messaging: + +* Jun 20, 2014: Patch `Add an optional timeout parameter to Listener.poll + `_ merged into Oslo Messaging +* April 23, 2014: Patch `Allow trollius 0.2 + `_ merged into + openstack/requirements +* Mar 21, 2014: Patch `Replace ad-hoc coroutines with Trollius coroutines + `_ proposed to Heat. Heat coroutines + are close to Trollius coroutines. Patch abandonned, need to be rewritten, + maybe with aiogreen. +* February 20, 2014: The full specification of the blueprint was written: + `Oslo/blueprints/asyncio + `_ +* Feb 8, 2014: Patch `Add a new dependency: trollius + `_ merged into + openstack/requirements +* February 27, 2014: Article `Use the new asyncio module and Trollius in OpenStack + `_ published +* February 4, 2014: Patch `Add a new asynchronous executor based on Trollius + `_ proposed to Oslo Messaging, + but it was abandonned. Running a classic Trollius event loop in a dedicated + thread doesn't fit well into eventlet event loop. + +First discussion around asyncio and OpenStack: + +* December 19, 2013: Article `Why should OpenStack move to Python 3 right now? + `_ published +* December 4, 2013: Blueprint `Add a asyncio executor to oslo.messaging + `_ + proposed by Flavio Percoco and accepted for OpenStack Icehouse by Mark + McLoughlin diff --git a/doc/poplar_hawk-moth.jpg b/doc/poplar_hawk-moth.jpg new file mode 100644 index 0000000..5ab1f7d Binary files /dev/null and b/doc/poplar_hawk-moth.jpg differ diff --git a/doc/status.rst b/doc/status.rst new file mode 100644 index 0000000..e894b79 --- /dev/null +++ b/doc/status.rst @@ -0,0 +1,69 @@ +Implemented +=========== + +Methods: + +* call_at() +* call_later() +* call_soon() +* run_forever() +* run_in_executor() +* run_until_complete() +* create_connection(): TCP client +* stop() +* coroutines and tasks + +Tests of aiogreen 0.1: + +* Tested on Python 2.7, 3.3 and 3.5 +* Tested on Linux and Windows +* Tested with Trollius 1.0, 1.0.1 and 1.0.2 +* Tested with asyncio 0.4.1 and 3.4.2 + + +To do (Not supported) +===================== + +* run an event loop in a thread different than the main thread +* sockets: create_server, sock_recv +* pipes: connect_read_pipe +* subprocesses: need pipes +* signal handlers: add_signal_handler (only for pyevent hub?) +* tox.ini: add py33_patch. eventlet with Python 3 and monkey-patch causes + an issue in importlib. + + +eventlet issues +=============== + +* eventlet monkey patching on Python 3 is incomplete. The most blocking issue + is in the importlib: the thread module is patched to use greenthreads, but + importlib really need to work on real threads. Pull request: + https://github.com/eventlet/eventlet/pull/168 +* eventlet.tpool.setup() seems to be broken on Windows in eventlet 0.15. + Pull request: + https://github.com/eventlet/eventlet/pull/167 +* hub.debug_blocking is implemented with signal.alarm() which is is not + available on Windows. + + +eventlet and Python 3 +===================== + +Issues: + +* https://github.com/eventlet/eventlet/issues/6 (root py3 issue) +* https://github.com/eventlet/eventlet/issues/157 (py3 related?) +* https://github.com/eventlet/eventlet/issues/153 (py3 related?) + +Pull requests: + +* https://github.com/eventlet/eventlet/pull/99 : complete monkey-patching +* => commit: https://github.com/therve/eventlet/commit/9c3118162cf1ca1e50be330ba2a289f054c48d3c +* https://github.com/eventlet/eventlet/pull/160 (py3 related?) + +OpenStack Kilo Summit: + +* https://etherpad.openstack.org/p/kilo-oslo-python-3 +* https://etherpad.openstack.org/p/kilo-oslo-oslo.messaging +* https://etherpad.openstack.org/p/py34-transition (tangentially related) diff --git a/doc/using.rst b/doc/using.rst new file mode 100644 index 0000000..325d647 --- /dev/null +++ b/doc/using.rst @@ -0,0 +1,169 @@ +Usage +===== + +Use aiogreen with trollius +-------------------------- + +To support Python 2, you can use Trollius which uses ``yield`` instead +of ``yield from`` for coroutines: +http://trollius.readthedocs.org/ + +To use aiogreen with trollius, set the event loop policy before using an event +loop, example:: + + import aiogreen + import trollius + + trollius.set_event_loop_policy(aiogreen.EventLoopPolicy()) + # .... + +Hello World:: + + import aiogreen + import trollius as asyncio + + def hello_world(): + print("Hello World") + loop.stop() + + asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) + loop = asyncio.get_event_loop() + loop.call_soon(hello_world) + loop.run_forever() + loop.close() + + +Use aiogreen with asyncio +------------------------- + +aiogreen implements the asyncio API, see asyncio documentation: +https://docs.python.org/dev/library/asyncio.html + +eventlet 0.15 supports Python 3 if monkey-patching is not used. + +To use aiogreen with asyncio, set the event loop policy before using an event +loop, example:: + + import aiogreen + import asyncio + + asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) + # .... + +Adding this code should be enough to try examples of the asyncio documentation. + +Hello World:: + + import aiogreen + import asyncio + + def hello_world(): + print("Hello World") + loop.stop() + + asyncio.set_event_loop_policy(aiogreen.EventLoopPolicy()) + loop = asyncio.get_event_loop() + loop.call_soon(hello_world) + loop.run_forever() + loop.close() + + +API +=== + +aiogreen specific functions: + +.. function:: link_future(future) + + Wait for a future (or a task) from a greenthread. + Return the result or raise the exception of the future. + + Example with asyncio:: + + @asyncio.coroutine + def coro_slow_sum(x, y): + yield from asyncio.sleep(1.0) + return x + y + + def green_sum(): + task = asyncio.async(coro_slow_sum(1, 2)) + value = aiogreen.link_future(task) + return value + +.. function:: wrap_greenthread(gt) + + Wrap a greenthread into a Future object. + + The Future object waits for the completion of a greenthread. + + Example with asyncio:: + + def slow_sum(x, y): + eventlet.sleep(1.0) + return x + y + + @asyncio.coroutine + def coro_sum(): + gt = eventlet.spawn(slow_sum, 1, 2) + fut = aiogreen.wrap_greenthread(gt, loop=loop) + result = yield from fut + return result + + .. note:: + If the debug mode of event loop is set, when a greenthread raises an + exception, the exception is logged to ``sys.stderr`` by eventlet, even if + the exception is copied to the Future object as expected. + + +Installation +============ + +Requirements: + +- eventlet 0.14 or newer +- asyncio or trollius: + + * Python 3.4 and newer: asyncio is now part of the stdlib + * Python 3.3: need Tulip 0.4.1 or newer (pip install asyncio), + but Tulip 3.4.1 or newer is recommended + * Python 2.6-3.2: need Trollius 0.3 or newer (pip install trollius), + but Trollius 1.0 or newer is recommended + +Type:: + + pip install aiogreen + +or:: + + python setup.py install + + +Run tests +========= + +Run tests with tox +------------------ + +The `tox project `_ can be used to build a +virtual environment with all runtime and test dependencies and run tests +against different Python versions (2.6, 2.7, 3.2, 3.3). + +For example, to run tests with Python 2.7, just type:: + + tox -e py27 + +To run tests against other Python versions: + +* ``py26``: Python 2.6 +* ``py27``: Python 2.7 +* ``py27_patch``: Python 2.7 with eventlet monkey patching +* ``py32``: Python 3.2 +* ``py33``: Python 3.3 +* ``py34``: Python 3.4 + +Run tests manually +------------------ + +Run the following command from the directory of the aiogreen project:: + + python runtests.py -r -- cgit v1.2.1