Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #16 from akaptur/yield-from-send-fix

More yielding from
commit f1142e0f860ff9df091141d77c5e77fe44ce2704 2 parents b1dbdf4 + d59290c
Ned Batchelder authored
2  byterun/pyobj.py
View
@@ -218,7 +218,7 @@ def send(self, value=None):
self.started = True
val = self.vm.resume_frame(self.gi_frame)
if self.finished:
- raise StopIteration
+ raise StopIteration(val)
return val
__next__ = next
16 byterun/pyvm2.py
View
@@ -977,19 +977,15 @@ def byte_YIELD_FROM(self):
x = self.top()
try:
- if hasattr(x, "send"):
- retval = x.send(u)
- else:
+ if not isinstance(x, Generator) or u is None:
+ # Call next on iterators.
retval = next(x)
+ else:
+ retval = x.send(u)
self.return_value = retval
- except StopIteration:
+ except StopIteration as e:
self.pop()
- if self.last_exception is not None:
- _, exc_val, _ = self.last_exception
- val = exc_val.value
- else:
- val = None
- self.push(val)
+ self.push(e.value)
else:
# YIELD_FROM decrements f_lasti, so that it will be called
# repeatedly until a StopIteration is raised.
76 tests/test_functions.py
View
@@ -307,3 +307,79 @@ def outer():
main()
""")
+
+ def test_distinguish_iterators_and_generators(self):
+ self.assert_ok("""\
+ class Foo(object):
+ def __iter__(self):
+ return FooIter()
+
+ class FooIter(object):
+ def __init__(self):
+ self.state = 0
+
+ def __next__(self):
+ if self.state >= 10:
+ raise StopIteration
+ self.state += 1
+ return self.state
+
+ def send(self, n):
+ print("sending")
+
+ def outer():
+ yield from Foo()
+
+ for x in outer():
+ print(x)
+ """)
+
+ def test_nested_yield_from(self):
+ self.assert_ok("""\
+ def main():
+ x = outer()
+ next(x)
+ y = x.send("Hello, World")
+ print(y)
+
+ def outer():
+ yield from middle()
+
+ def middle():
+ yield from inner()
+
+ def inner():
+ y = yield
+ yield y
+
+ main()
+ """)
+
+ def test_return_from_generator(self):
+ self.assert_ok("""\
+ def gen():
+ yield 1
+ return 2
+
+ x = gen()
+ while True:
+ try:
+ print(next(x))
+ except StopIteration as e:
+ print(e.value)
+ break
+ """)
+
+ def test_return_from_generator_with_yield_from(self):
+ self.assert_ok("""\
+ def returner():
+ if False:
+ yield
+ return 1
+
+ def main():
+ y = yield from returner()
+ print(y)
+
+ list(main())
+ """)
32 tests/test_with.py
View
@@ -3,6 +3,8 @@
from __future__ import print_function
from . import vmtest
+import six
+PY3 = six.PY3
class TestWithStatement(vmtest.VmTestCase):
@@ -307,3 +309,33 @@ def my_context_manager(val):
with my_context_manager(17) as x:
assert x == 17
""")
+
+ if PY3:
+ def test_generator_with_context_manager(self):
+ self.assert_ok("""\
+ from contextlib import contextmanager
+
+ def inner():
+ yield "I'm inner!"
+
+ def foo():
+ yield from inner()
+
+ @contextmanager
+ def cmgr():
+ yield "Context Manager!"
+ raise StopIteration(cmgr())
+
+ def main():
+ with (yield from foo()) as x:
+ print(x)
+
+ def run(fn, *args):
+ x = fn(*args)
+ while True:
+ try:
+ print(next(x))
+ except StopIteration as e:
+ return e.value
+ run(main)
+ """)
Please sign in to comment.
Something went wrong with that request. Please try again.