summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2014-11-21 04:17:25 +0100
committerVictor Stinner <victor.stinner@gmail.com>2014-11-21 04:17:25 +0100
commitea24997de038d20c1b98496cc8abbdc595d460ca (patch)
tree484732a9dbc075dd8c16c28f2f391b859df33b06
parentb02bfe02f265c9a17f3ae77d86c8f02f42adf758 (diff)
downloadaioeventlet-ea24997de038d20c1b98496cc8abbdc595d460ca.tar.gz
Add the wrap_greenthread() function
-rw-r--r--README33
-rw-r--r--aiogreen.py18
-rw-r--r--tests/test_eventlet.py45
-rw-r--r--tox.ini9
4 files changed, 86 insertions, 19 deletions
diff --git a/README b/README
index 27ea8c9..5d0dc60 100644
--- a/README
+++ b/README
@@ -72,6 +72,38 @@ Hello World::
loop.close()
+Use a greenthread in a coroutine
+--------------------------------
+
+Use the ``wrap_greenthread()`` function to 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: In debug mode, when a greenthread raises an exception, the exception is
+logged to sys.stderr by eventlet, even if it is correctly copied to the Future
+object.
+
+
+API
+===
+
+Functions which are not in asyncio:
+
+* ``wrap_greenthread(gt)``: wrap a greenthread into a Future object
+
+
Installation
============
@@ -139,6 +171,7 @@ only call the callback once per loop iteration.
Changes:
+* Add the ``wrap_greenthread()`` function to 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
diff --git a/aiogreen.py b/aiogreen.py
index 5c45635..e7558c3 100644
--- a/aiogreen.py
+++ b/aiogreen.py
@@ -68,6 +68,24 @@ class _TpoolExecutor(object):
self._tpool.killall()
+def wrap_greenthread(gt, loop=None):
+ """Wrap an eventlet greenthread into a Future object."""
+ if loop is None:
+ loop = asyncio.get_event_loop()
+ fut = asyncio.Future(loop=loop)
+
+ def copy_result(gt):
+ try:
+ value = gt.wait()
+ except Exception as exc:
+ loop.call_soon(fut.set_exception, exc)
+ else:
+ loop.call_soon(fut.set_result, value)
+
+ gt.link(copy_result)
+ return fut
+
+
class _Selector(asyncio.selectors._BaseSelectorImpl):
def __init__(self, loop, hub):
super(_Selector, self).__init__()
diff --git a/tests/test_eventlet.py b/tests/test_eventlet.py
index eb428d7..4ff9e8c 100644
--- a/tests/test_eventlet.py
+++ b/tests/test_eventlet.py
@@ -1,5 +1,8 @@
+import aiogreen
import eventlet
import tests
+from tests import unittest
+
def eventlet_slow_append(result, value, delay):
eventlet.sleep(delay)
@@ -33,22 +36,25 @@ try:
return value
@asyncio.coroutine
- def coro_chain_greenthread():
+ def coro_wrap_greenthread():
result = []
loop = asyncio.get_event_loop()
g1 = eventlet.spawn(eventlet_slow_append, result, 1, 0.2)
- value = yield from wait_greenthread(g1, loop=loop)
+ fut = aiogreen.wrap_greenthread(g1, loop=loop)
+ value = yield from fut
result.append(value)
g2 = eventlet.spawn(eventlet_slow_append, result, 2, 0.1)
- value = yield from wait_greenthread(g2, loop=loop)
+ fut = aiogreen.wrap_greenthread(g2, loop=loop)
+ value = yield from fut
result.append(value)
g3 = eventlet.spawn(eventlet_slow_error, 0.001)
+ fut = aiogreen.wrap_greenthread(g3, loop=loop)
try:
- yield from wait_greenthread(g3, loop=loop)
+ yield from fut
except ValueError as exc:
result.append(str(exc))
@@ -89,22 +95,24 @@ except ImportError:
raise Return(value)
@asyncio.coroutine
- def coro_chain_greenthread():
+ def coro_wrap_greenthread():
result = []
loop = asyncio.get_event_loop()
g1 = eventlet.spawn(eventlet_slow_append, result, 1, 0.2)
-
- value = yield From(wait_greenthread(g1, loop=loop))
+ fut = aiogreen.wrap_greenthread(g1, loop=loop)
+ value = yield From(fut)
result.append(value)
g2 = eventlet.spawn(eventlet_slow_append, result, 2, 0.1)
- value = yield From(wait_greenthread(g2, loop=loop))
+ fut = aiogreen.wrap_greenthread(g2, loop=loop)
+ value = yield From(fut)
result.append(value)
g3 = eventlet.spawn(eventlet_slow_error, 0.001)
+ fut = aiogreen.wrap_greenthread(g3, loop=loop)
try:
- yield From(wait_greenthread(g3, loop=loop))
+ yield From(fut)
except ValueError as exc:
result.append(str(exc))
@@ -123,7 +131,7 @@ except ImportError:
raise ValueError("error")
-def wait_task(task):
+def link_task(task):
event = eventlet.event.Event()
def done(fut):
try:
@@ -137,19 +145,19 @@ def wait_task(task):
task.add_done_callback(done)
return event.wait()
-def greenthread_chain_coro(result, loop):
+def greenthread_link_task(result, loop):
try:
t1 = asyncio.async(coro_slow_append(result, 1, 0.2), loop=loop)
- value = wait_task(t1)
+ value = link_task(t1)
result.append(value)
t2 = asyncio.async(coro_slow_append(result, 2, 0.1), loop=loop)
- value = wait_task(t2)
+ value = link_task(t2)
result.append(value)
t3 = asyncio.async(coro_slow_error(0.001), loop=loop)
try:
- value = wait_task(t3)
+ value = link_task(t3)
except ValueError as exc:
result.append(str(exc))
@@ -204,13 +212,14 @@ class EventletTests(tests.TestCase):
self.loop.run_forever()
self.assertEqual(result, ["spawn", "spawn_after"])
- def test_coro_chain_greenthread(self):
- result = self.loop.run_until_complete(coro_chain_greenthread())
+ def test_coro_wrap_greenthread(self):
+ result = self.loop.run_until_complete(coro_wrap_greenthread())
self.assertEqual(result, [1, 10, 2, 20, 'error', 4])
- def test_greenthread_chain_coro(self):
+ def test_greenthread_link_task(self):
result = []
- self.loop.call_soon(eventlet.spawn, greenthread_chain_coro, result, self.loop)
+ self.loop.call_soon(eventlet.spawn,
+ greenthread_link_task, result, self.loop)
self.loop.run_forever()
self.assertEqual(result, [1, 10, 2, 20, 'error', 4])
diff --git a/tox.ini b/tox.ini
index 86aed81..6b6f983 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py26,py27,py27_patch,py32,py33,py34
+envlist = py26,py27,py27_patch,py32,py33,py34,py35
[testenv:py26]
setenv =
@@ -49,3 +49,10 @@ setenv =
deps=
eventlet
commands=python runtests.py -r
+
+[testenv:py35]
+setenv =
+ PYTHONASYNCIODEBUG = 1
+deps=
+ eventlet
+commands=python runtests.py -r