Hi,

I'm trying to follow the discussion about the PEP 479 (Change
StopIteration handling inside generators), but it's hard to read all
messages. I'm concerned by trollius and asyncio which heavily rely on
StopIteration.

Trollius currently supports running asyncio coroutines: a trollius
coroutine can executes an asyncio coroutine, and and asyncio coroutine
can execute a trollius coroutine.

I modified the Return class of Trollius to not inherit from
StopIteration. All trollius tests pass on Python 3.3 except on one
(which makes me happy, the test suite is wide enough to detect bugs
;-)): test_trollius_in_asyncio.

This specific test executes an asyncio which executes a trollius coroutine.
https://bitbucket.org/enovance/trollius/src/873d21ac0badec36835ed24d13e2aeda24f2dc64/tests/test_asyncio.py?at=trollius#cl-60

The problem is that an asyncio coroutine cannot execute a Trollius
coroutine anymore: "yield from coro" raises a Return exception instead
of simply "stopping" the generator and return the result (value passed
to Return).

I don't see how an asyncio coroutine calling "yield from
trollius_coroutine" can handle the Return exception if it doesn't
inherit from StopIteration. It means that I have to drop this feature
in Python 3.5 (or later when the PEP 479 becomes effective)?

I'm talking about the current behaviour of Python 3.3, I didn't try
the PEP 479 (I don't know if an exception exists).

Victor
class Return(Exception):
    def __init__(self, value):
        self.value = value

class Task:
    def __init__(self, coro):
        self.coro = coro
        self.result = None
        self.done = False

    def _step(self):
        try:
            result = next(self.coro)
        except Return as exc:
            result = exc.value
            self.done = True

    def __iter__(self):
        while not self.done:
            yield self._step()
        return self.result

def trollius_coro(calls):
    calls.append("enter trollius_coro")
    yield None
    calls.append("exit trollius_coro with Return")
    raise Return(5)

def asyncio_coro(calls):
    calls.append("enter asyncio_coro")
    coro = trollius_coro(calls)
    calls.append("asyncio_coro yield from trollius_coro")
    result = yield from coro
    calls.append("asyncio_coro returns %r" % result)
    return result

def test():
    calls = []
    coro = asyncio_coro(calls)

    # simulate a call to loop.run_until_complete(coro)
    task = Task(coro)
    result = yield from task

    for call in calls:
        print(call)
    print("Result: %r" % result)

for item in test():
    pass
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to