[pypy-commit] pypy py3.6-exc-info: revert some parts, fix the rest

arigo pypy.commits at gmail.com
Thu Nov 7 07:32:01 EST 2019


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.6-exc-info
Changeset: r97974:2857fcf6b913
Date: 2019-11-07 13:30 +0100
http://bitbucket.org/pypy/pypy/changeset/2857fcf6b913/

Log:	revert some parts, fix the rest

diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -32,9 +32,9 @@
         self.topframeref = jit.vref_None
         # this is exposed to app-level as 'sys.exc_info()'.  At any point in
         # time it is the exception caught by the topmost 'except ... as e:'
-        # app-level block.  (This is the *last* item in the list; previous
-        # items form a stack of older operrors.)
-        self.sys_exc_operrors = [None]
+        # app-level block.
+        self.sys_exc_operror = None
+        self.previous_operror_stack = []
         self.w_tracefunc = None
         self.is_tracing = 0
         self.compiler = space.createcompiler()
@@ -243,17 +243,23 @@
     def sys_exc_info(self):
         """Implements sys.exc_info().
         Return an OperationError instance or None.
+        Returns the "top-most" exception in the stack.
 
         # NOTE: the result is not the wrapped sys.exc_info() !!!
 
         """
-        i = len(self.sys_exc_operror) - 1
-        while i > 0 and self.sys_exc_operrors[i] is None:
-            i -= 1
-        return self.sys_exc_operrors[i]
+        result = self.sys_exc_operror
+        if result is None:
+            i = len(self.previous_operror_stack) - 1
+            while i >= 0:
+                result = self.previous_operror_stack[i]
+                if result is not None:
+                    break
+                i -= 1
+        return result
 
     def set_sys_exc_info(self, operror):
-        self.sys_exc_operrors[-1] = operror
+        self.sys_exc_operror = operror
 
     def set_sys_exc_info3(self, w_type, w_value, w_traceback):
         space = self.space
@@ -269,6 +275,21 @@
             operror = OperationError(w_type, w_value, tb)
         self.set_sys_exc_info(operror)
 
+    def enter_error_stack_item(self, saved_operr):
+        self.previous_operror_stack.append(saved_operr)
+
+    def leave_error_stack_item(self):
+        return self.previous_operror_stack.pop()
+
+    def fetch_and_clear_error_stack_state(self):
+        result = self.sys_exc_operror, self.previous_operror_stack
+        self.sys_exc_operror = None
+        self.previous_operror_stack = []
+        return result
+
+    def restore_error_stack_state(self, saved):
+        self.sys_exc_operror, self.previous_operror_stack = saved
+
     @jit.dont_look_inside
     def settrace(self, w_func):
         """Set the global trace function."""
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -105,11 +105,6 @@
         frame = self.frame
         if self.running:
             raise oefmt(space.w_ValueError, "%s already executing", self.KIND)
-        ec = space.getexecutioncontext()
-        current_exc_info = ec.sys_exc_info()
-        if self.saved_operr is not None:
-            ec.set_sys_exc_info(self.saved_operr)
-            self.saved_operr = None
         #
         # Optimization only: after we've started a Coroutine without
         # CO_YIELD_INSIDE_TRY, then Coroutine._finalize_() will be a no-op
@@ -123,6 +118,8 @@
                 raise oefmt(space.w_TypeError,
                             "can't send non-None value to a just-started %s",
                             self.KIND)
+        ec = space.getexecutioncontext()
+        ec.enter_error_stack_item(self.saved_operr)
         self.running = True
         try:
             w_result = frame.execute_frame(w_arg_or_err)
@@ -142,10 +139,8 @@
             self.running = False
             # note: this is not perfectly correct: see
             # test_exc_info_in_generator_4.  But it's simpler and
-            # bug-to-bug compatible with CPython 3.5.
-            if frame._any_except_or_finally_handler():
-                self.saved_operr = ec.sys_exc_info()
-            ec.set_sys_exc_info(current_exc_info)
+            # bug-to-bug compatible with CPython 3.5 and 3.6.
+            self.saved_operr = ec.leave_error_stack_item()
         return w_result
 
     def get_delegate(self):
diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -60,8 +60,7 @@
         try:
             raise ValueError
         except ValueError as e:
-            pass
-        assert e.__context__ is terr
+            assert e.__context__ is terr
 
     def test_set_exc_info_issue3096(self):
         from __pypy__ import set_exc_info
diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -46,9 +46,9 @@
         #
         global_state.origin = self
         self.sthread = sthread
-        saved_exception = pre_switch(sthread)
+        saved_error_state = pre_switch(sthread)
         h = sthread.new(new_stacklet_callback)
-        post_switch(sthread, h, saved_exception)
+        post_switch(sthread, h, saved_error_state)
 
     def switch(self, w_to):
         sthread = self.sthread
@@ -84,9 +84,9 @@
             # double switch: the final destination is to.h
             global_state.destination = to
         #
-        saved_exception = pre_switch(sthread)
+        saved_error_state = pre_switch(sthread)
         h = sthread.switch(global_state.destination.h)
-        return post_switch(sthread, h, saved_exception)
+        return post_switch(sthread, h, saved_error_state)
 
     @unwrap_spec(w_value = WrappedDefault(None),
                  w_to = WrappedDefault(None))
@@ -257,11 +257,9 @@
     return self.h
 
 def pre_switch(sthread):
-    saved_exception = sthread.ec.sys_exc_info()
-    sthread.ec.set_sys_exc_info(None)
-    return saved_exception
+    return sthread.ec.fetch_and_clear_error_stack_state()
 
-def post_switch(sthread, h, saved_exception):
+def post_switch(sthread, h, saved_error_state):
     origin = global_state.origin
     self = global_state.destination
     global_state.origin = None
@@ -270,7 +268,7 @@
     #
     current = sthread.ec.topframeref
     sthread.ec.topframeref = self.bottomframe.f_backref
-    sthread.ec.set_sys_exc_info(saved_exception)
+    sthread.ec.restore_error_stack_state(saved_error_state)
     self.bottomframe.f_backref = origin.bottomframe.f_backref
     origin.bottomframe.f_backref = current
     #
diff --git a/pypy/module/sys/moduledef.py b/pypy/module/sys/moduledef.py
--- a/pypy/module/sys/moduledef.py
+++ b/pypy/module/sys/moduledef.py
@@ -209,31 +209,6 @@
         w_modules = self.get('modules')
         self.space.setitem(w_modules, w_name, w_module)
 
-    def getdictvalue(self, space, attr):
-        """ specialize access to dynamic exc_* attributes. """
-        value = MixedModule.getdictvalue(self, space, attr)
-        if value is not None:
-            return value
-        if attr == 'exc_type':
-            operror = space.getexecutioncontext().sys_exc_info()
-            if operror is None:
-                return space.w_None
-            else:
-                return operror.w_type
-        elif attr == 'exc_value':
-            operror = space.getexecutioncontext().sys_exc_info()
-            if operror is None:
-                return space.w_None
-            else:
-                return operror.get_w_value(space)
-        elif attr == 'exc_traceback':
-            operror = space.getexecutioncontext().sys_exc_info()
-            if operror is None:
-                return space.w_None
-            else:
-                return operror.get_w_traceback(space)
-        return None
-
     def get_flag(self, name):
         space = self.space
         return space.int_w(space.getattr(self.get('flags'), space.newtext(name)))
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -187,13 +187,6 @@
     else:
         return exc_info_without_tb(space, operror)
 
-def exc_clear(space):
-    """Clear global information on the current exception.  Subsequent calls
-to exc_info() will return (None,None,None) until another exception is
-raised and caught in the current thread or the execution stack returns to a
-frame where another exception is being handled."""
-    space.getexecutioncontext().clear_sys_exc_info()
-
 def settrace(space, w_func):
     """Set the global debug tracing function.  It will be called on each
 function call.  See the debugger chapter in the library manual."""


More information about the pypy-commit mailing list