77
88from __future__ import print_function
99
10+ import sys
1011import types
1112
1213from . import Effect , Func
@@ -26,11 +27,12 @@ def foo():
2627 eff = foo()
2728 return eff.on(...)
2829
29- ``@do`` must decorate a generator function. Any yielded values must either
30- be Effects or the result of a :func:`do_return` call. The result of a
31- yielded Effect will be passed back into the generator as the result of the
32- ``yield`` expression. Yielded :func:`do_return` values will provide the
33- ultimate result of the Effect that is returned by the decorated function.
30+ ``@do`` must decorate a generator function (not any other type of
31+ iterator). Any yielded values must either be Effects or the result of a
32+ :func:`do_return` call. The result of a yielded Effect will be passed back
33+ into the generator as the result of the ``yield`` expression. Yielded
34+ :func:`do_return` values will provide the ultimate result of the Effect
35+ that is returned by the decorated function.
3436
3537 It's important to note that any generator function decorated by ``@do``
3638 will no longer return a generator, but instead it will return an Effect,
@@ -88,7 +90,16 @@ def _do(result, generator, is_error):
8890 else :
8991 val = generator .send (result )
9092 except StopIteration :
91- return None
93+ # If the generator we're spinning directly raises StopIteration, we'll
94+ # treat it like returning None from the function. But there may be a
95+ # case where some other code is raising StopIteration up through this
96+ # generator, in which case we shouldn't really treat it like a function
97+ # return -- it could quite easily hide bugs.
98+ tb = sys .exc_info ()[2 ]
99+ if tb .tb_next :
100+ raise
101+ else :
102+ return None
92103 if type (val ) is _ReturnSentinel :
93104 return val .result
94105 elif type (val ) is Effect :
0 commit comments