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

Reply via email to