summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2014-06-11 17:27:30 +0200
committerVictor Stinner <victor.stinner@gmail.com>2014-06-11 17:27:30 +0200
commitc599890b99f202f7a26bfdf1b1be01cb96159d7f (patch)
tree1e69e8ccb55316831c7686c52a1a3dd9644feac9
parente3f4e5f7ae38b975d7d4ed2941157b25ecafe1a2 (diff)
downloadtrollius-c599890b99f202f7a26bfdf1b1be01cb96159d7f.tar.gz
Suppport yield from a trollius coroutine in an asyncio coroutine
-rw-r--r--tests/test_tasks.py2
-rw-r--r--trollius/coroutines.py50
-rw-r--r--trollius/tasks.py15
3 files changed, 47 insertions, 20 deletions
diff --git a/tests/test_tasks.py b/tests/test_tasks.py
index befe050..0381852 100644
--- a/tests/test_tasks.py
+++ b/tests/test_tasks.py
@@ -1451,7 +1451,7 @@ class TaskTests(test_utils.TestCase):
cw.send(None)
try:
cw.send(arg)
- except Return as ex:
+ except StopIteration as ex:
return ex.value
else:
raise AssertionError('StopIteration was expected')
diff --git a/trollius/coroutines.py b/trollius/coroutines.py
index 0a42f67..ee610c2 100644
--- a/trollius/coroutines.py
+++ b/trollius/coroutines.py
@@ -2,8 +2,13 @@ import functools
import inspect
import os
import sys
+try:
+ import asyncio
+except ImportError:
+ asyncio = None
-from trollius import futures
+from . import compat
+from . import futures
from .log import logger
# If you set _DEBUG to true, @coroutine will wrap the resulting
@@ -19,20 +24,37 @@ _DEBUG = (not sys.flags.ignore_environment
and bool(os.environ.get('PYTHONASYNCIODEBUG')))
-class Return(StopIteration):
- def __init__(self, *value):
- StopIteration.__init__(self)
- if not value:
- self.value = None
- elif len(value) == 1:
- self.value = value[0]
+if compat.PY33:
+ # Don't use the Return class on Python 3.3 and later to support asyncio
+ # coroutines (to avoid the warning emited in Return destructor).
+ #
+ # The problem is that Return inherits from StopIteration. "yield from
+ # trollius_coroutine". Task._step() does not receive the Return exception,
+ # because "yield from" handles it internally. So it's not possible to set
+ # the raised attribute to True to avoid the warning in Return destructor.
+ def Return(*args):
+ if not args:
+ value = None
+ elif len(args) == 1:
+ value = args[0]
else:
- self.value = value
- self.raised = False
-
- def __del__(self):
- if not self.raised:
- logger.error('Return(%r) used without raise', self.value)
+ value = args
+ return StopIteration(value)
+else:
+ class Return(StopIteration):
+ def __init__(self, *args):
+ StopIteration.__init__(self)
+ if not args:
+ self.value = None
+ elif len(args) == 1:
+ self.value = args[0]
+ else:
+ self.value = args
+ self.raised = False
+
+ def __del__(self):
+ if not self.raised:
+ logger.error('Return(%r) used without raise', self.value)
class CoroWrapper(object):
diff --git a/trollius/tasks.py b/trollius/tasks.py
index d97ee03..993cf0b 100644
--- a/trollius/tasks.py
+++ b/trollius/tasks.py
@@ -21,6 +21,7 @@ try:
except ImportError:
asyncio = None
+from . import compat
from . import events
from . import executor
from . import futures
@@ -232,12 +233,16 @@ class Task(futures.Future):
result = coro.send(value)
else:
result = next(coro)
- except Return as exc:
- exc.raised = True
- self.set_result(exc.value)
except StopIteration as exc:
- # asyncio Task object? get the result of the coroutine
- result = getattr(exc, 'value', None)
+ if compat.PY33:
+ # asyncio Task object? get the result of the coroutine
+ result = exc.value
+ else:
+ if isinstance(exc, Return):
+ exc.raised = True
+ result = exc.value
+ else:
+ result = None
self.set_result(result)
except futures.CancelledError as exc:
super(Task, self).cancel() # I.e., Future.cancel(self).