diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2014-06-11 17:27:30 +0200 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2014-06-11 17:27:30 +0200 |
commit | c599890b99f202f7a26bfdf1b1be01cb96159d7f (patch) | |
tree | 1e69e8ccb55316831c7686c52a1a3dd9644feac9 | |
parent | e3f4e5f7ae38b975d7d4ed2941157b25ecafe1a2 (diff) | |
download | trollius-c599890b99f202f7a26bfdf1b1be01cb96159d7f.tar.gz |
Suppport yield from a trollius coroutine in an asyncio coroutine
-rw-r--r-- | tests/test_tasks.py | 2 | ||||
-rw-r--r-- | trollius/coroutines.py | 50 | ||||
-rw-r--r-- | trollius/tasks.py | 15 |
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). |