Author: Armin Rigo <ar...@tunes.org>
Branch: py3.5-corowrapper
Changeset: r87115:209720711d97
Date: 2016-09-14 20:11 +0200
http://bitbucket.org/pypy/pypy/changeset/209720711d97/

Log:    CO_FUTURE_GENERATOR_STOP, not tested so far

diff --git a/pypy/interpreter/astcompiler/consts.py 
b/pypy/interpreter/astcompiler/consts.py
--- a/pypy/interpreter/astcompiler/consts.py
+++ b/pypy/interpreter/astcompiler/consts.py
@@ -25,7 +25,8 @@
 
 PyCF_MASK = (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT |
              CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION |
-             CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL)
+             CO_FUTURE_UNICODE_LITERALS | CO_FUTURE_BARRY_AS_BDFL |
+             CO_FUTURE_GENERATOR_STOP)
 PyCF_SOURCE_IS_UTF8 = 0x0100
 PyCF_DONT_IMPLY_DEDENT = 0x0200
 PyCF_ONLY_AST = 0x0400
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -116,10 +116,15 @@
         try:
             try:
                 w_result = frame.execute_frame(w_arg, operr)
-            except OperationError:
+            except OperationError as e:
                 # errors finish a frame
-                self.frame = None
+                try:
+                    if e.match(space, space.w_StopIteration):
+                        self._leak_stopiteration(e)
+                finally:
+                    self.frame = None
                 raise
+            #
             # if the frame is now marked as finished, it was RETURNed from
             if frame.frame_finished_execution:
                 self.frame = None
@@ -135,6 +140,25 @@
             frame.f_backref = jit.vref_None
             self.running = False
 
+    def _leak_stopiteration(self, e):
+        # Check for __future__ generator_stop and conditionally turn
+        # a leaking StopIteration into RuntimeError (with its cause
+        # set appropriately).
+        space = self.space
+        if self.pycode.co_flags & (consts.CO_FUTURE_GENERATOR_STOP |
+                                   consts.CO_COROUTINE |
+                                   consts.CO_ITERABLE_COROUTINE):
+            e2 = OperationError(space.w_RuntimeError,
+                                space.wrap("%s raised StopIteration" %
+                                           self.KIND),
+                                w_cause=e.get_w_value(space))
+            e2.record_context(space, self.frame)
+            raise e2
+        else:
+            space.warn(space.wrap("generator '%s' raised StopIteration"
+                                  % self.get_qualname()),
+                       space.w_PendingDeprecationWarning)
+
     def descr_throw(self, w_type, w_val=None, w_tb=None):
         """throw(typ[,val[,tb]]) -> raise exception in generator/coroutine,
 return next yielded value or raise StopIteration."""
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -101,7 +101,7 @@
     """
     def __init__(self, space, override_version=None):
         PyCodeCompiler.__init__(self, space)
-        self.future_flags = future.futureFlags_3_2
+        self.future_flags = future.futureFlags_3_5
         self.parser = pyparse.PythonParser(space, self.future_flags)
         self.additional_rules = {}
         self.compiler_flags = self.future_flags.allowed_flags
diff --git a/pypy/interpreter/pyparser/future.py 
b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -30,6 +30,7 @@
 futureFlags_2_5 = FutureFlags((2, 5, 0, 'final', 0))
 futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0))
 futureFlags_3_2 = FutureFlags((3, 2, 0, 'final', 0))
+futureFlags_3_5 = FutureFlags((3, 5, 0, 'final', 0))
 
 
 class TokenIterator:
diff --git a/pypy/interpreter/pyparser/pyparse.py 
b/pypy/interpreter/pyparser/pyparse.py
--- a/pypy/interpreter/pyparser/pyparse.py
+++ b/pypy/interpreter/pyparser/pyparse.py
@@ -95,7 +95,7 @@
 
 class PythonParser(parser.Parser):
 
-    def __init__(self, space, future_flags=future.futureFlags_3_2,
+    def __init__(self, space, future_flags=future.futureFlags_3_5,
                  grammar=pygram.python_grammar):
         parser.Parser.__init__(self, grammar)
         self.space = space
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
@@ -641,3 +641,23 @@
             2,
         ]
 
+
+class AppTestGeneratorStop:
+
+    def test_past_generator_stop(self):
+        # how it works without 'from __future__' import generator_stop
+        def f(x):
+            raise StopIteration
+            yield x
+        raises(StopIteration, next, f(5))
+
+    def test_future_generator_stop(self):
+        d = {}
+        exec("""from __future__ import generator_stop
+
+def f(x):
+    raise StopIteration
+    yield x
+""", d)
+        f = d['f']
+        raises(RuntimeError, next, f(5))
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to