Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3.3
Changeset: r74205:874078255648
Date: 2014-10-25 11:45 +0200
http://bitbucket.org/pypy/pypy/changeset/874078255648/
Log: Be sure to handle the returned value from delegated throw
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -130,41 +130,44 @@
w_yf = self._get_yield_from()
if w_yf is not None:
# Paused in a "yield from", pass the throw to the inner generator.
- if space.is_w(w_type, space.w_GeneratorExit):
- try:
- w_close = space.getattr(w_yf, space.wrap("close"))
- except OperationError as e:
- if not e.match(space, space.w_AttributeError):
- e.write_unraisable(space, "generator.close()")
- else:
- self.running = True
- try:
- space.call_function(w_close)
- except OperationError as operr:
- self.running = False
- return self.send_ex(space.w_None, operr)
- finally:
- self.running = False
- return self._throw_here(space, w_type, w_val, w_tb)
+ return self._throw_delegate(space, w_yf, w_type, w_val, w_tb)
+ else:
+ # Not paused in a "yield from", quit this generator
+ return self._throw_here(space, w_type, w_val, w_tb)
+
+ def _throw_delegate(self, space, w_yf, w_type, w_val, w_tb):
+ if space.is_w(w_type, space.w_GeneratorExit):
+ try:
+ w_close = space.getattr(w_yf, space.wrap("close"))
+ except OperationError as e:
+ if not e.match(space, space.w_AttributeError):
+ e.write_unraisable(space, "generator.close()")
else:
- try:
- w_throw = space.getattr(w_yf, space.wrap("throw"))
- except OperationError as e:
- if not e.match(space, space.w_AttributeError):
- raise
- return self._throw_here(space, w_type, w_val, w_tb)
self.running = True
try:
- space.call_function(w_throw, w_type, w_val, w_tb)
+ space.call_function(w_close)
except OperationError as operr:
self.running = False
- # XXX Should pop subiterator from stack?
return self.send_ex(space.w_None, operr)
finally:
self.running = False
-
- # Not paused in a "yield from", quit this generator
- return self._throw_here(space, w_type, w_val, w_tb)
+ return self._throw_here(space, w_type, w_val, w_tb)
+ else:
+ try:
+ w_throw = space.getattr(w_yf, space.wrap("throw"))
+ except OperationError as e:
+ if not e.match(space, space.w_AttributeError):
+ raise
+ return self._throw_here(space, w_type, w_val, w_tb)
+ self.running = True
+ try:
+ return space.call_function(w_throw, w_type, w_val, w_tb)
+ except OperationError as operr:
+ self.running = False
+ # XXX Should pop subiterator from stack?
+ return self.send_ex(space.w_None, operr)
+ finally:
+ self.running = False
def _throw_here(self, space, w_type, w_val, w_tb):
from pypy.interpreter.pytraceback import check_traceback
diff --git a/pypy/interpreter/test/test_generator.py
b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -550,3 +550,50 @@
gi.close()
assert 'ZeroDivisionError' in sys.stderr.getvalue()
+ def test_returning_value_from_delegated_throw(self):
+ """
+ Test returning value from delegated 'throw'
+ """
+ trace = []
+ class LunchError(Exception):
+ pass
+ d = dict(trace=trace, LunchError=LunchError)
+ exec('''if 1:
+ def g1():
+ try:
+ trace.append("Starting g1")
+ yield "g1 ham"
+ yield from g2()
+ yield "g1 eggs"
+ finally:
+ trace.append("Finishing g1")
+ def g2():
+ try:
+ trace.append("Starting g2")
+ yield "g2 spam"
+ yield "g2 more spam"
+ except LunchError:
+ trace.append("Caught LunchError in g2")
+ yield "g2 lunch saved"
+ yield "g2 yet more spam"
+ ''', d)
+ g1, g2 = d['g1'], d['g2']
+ g = g1()
+ for i in range(2):
+ x = next(g)
+ trace.append("Yielded %s" % (x,))
+ e = LunchError("tomato ejected")
+ g.throw(e)
+ for x in g:
+ trace.append("Yielded %s" % (x,))
+ assert trace == [
+ "Starting g1",
+ "Yielded g1 ham",
+ "Starting g2",
+ "Yielded g2 spam",
+ "Caught LunchError in g2",
+ "Yielded g2 yet more spam",
+ "Yielded g1 eggs",
+ "Finishing g1",
+ ]
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit