[pypy-commit] pypy py3.6: Merged in py3.6-exc-info-2 (pull request #686)
rlamy
pypy.commits at gmail.com
Thu Dec 12 08:01:43 EST 2019
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.6
Changeset: r98277:357a713081c3
Date: 2019-12-12 12:59 +0000
http://bitbucket.org/pypy/pypy/changeset/357a713081c3/
Log: Merged in py3.6-exc-info-2 (pull request #686)
Fix handling of sys.exc_info() in generators
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -34,7 +34,6 @@
# time it is the exception caught by the topmost 'except ... as e:'
# app-level block.
self.sys_exc_operror = None
- self.previous_operror_stack = []
self.w_tracefunc = None
self.is_tracing = 0
self.compiler = space.createcompiler()
@@ -248,15 +247,7 @@
# NOTE: the result is not the wrapped sys.exc_info() !!!
"""
- 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
+ return self.sys_exc_operror
def set_sys_exc_info(self, operror):
self.sys_exc_operror = operror
@@ -277,26 +268,6 @@
operror = OperationError(w_type, w_value, tb)
self.set_sys_exc_info(operror)
- def enter_error_stack_item(self, saved_operr):
- # 'sys_exc_operror' should be logically considered as the last
- # item on the stack, so pushing a new item has the following effect:
- self.previous_operror_stack.append(self.sys_exc_operror)
- self.sys_exc_operror = saved_operr
-
- def leave_error_stack_item(self):
- result = self.sys_exc_operror
- self.sys_exc_operror = self.previous_operror_stack.pop()
- return result
-
- 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
@@ -119,7 +119,10 @@
"can't send non-None value to a just-started %s",
self.KIND)
ec = space.getexecutioncontext()
- ec.enter_error_stack_item(self.saved_operr)
+ 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
self.running = True
try:
w_result = frame.execute_frame(w_arg_or_err)
@@ -140,7 +143,9 @@
# 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 and 3.6.
- self.saved_operr = ec.leave_error_stack_item()
+ if frame._any_except_or_finally_handler():
+ self.saved_operr = ec.sys_exc_info()
+ ec.set_sys_exc_info(current_exc_info)
return w_result
def get_delegate(self):
diff --git a/pypy/interpreter/test/apptest_generator.py b/pypy/interpreter/test/apptest_generator.py
--- a/pypy/interpreter/test/apptest_generator.py
+++ b/pypy/interpreter/test/apptest_generator.py
@@ -1,5 +1,7 @@
from pytest import raises, skip
+import sys
+
def test_generator():
def f():
yield 1
@@ -462,7 +464,6 @@
assert closed == [True]
def test_exc_info_in_generator():
- import sys
def g():
try:
raise ValueError
@@ -533,8 +534,35 @@
try:
raise IndexError
except IndexError:
- assert next(gen) is 1
- assert next(gen) is 2
+ assert next(gen) == 1
+ assert next(gen) == 2
+
+def test_except_gen_except():
+ def gen():
+ try:
+ assert sys.exc_info()[0] is None
+ yield
+ # we are called from "except ValueError:", TypeError must
+ # inherit ValueError in its context
+ raise TypeError()
+ except TypeError as exc:
+ assert sys.exc_info()[0] is TypeError
+ assert type(exc.__context__) is ValueError
+ # here we are still called from the "except ValueError:"
+ assert sys.exc_info()[0] is ValueError
+ yield
+ assert sys.exc_info()[0] is None
+ yield "done"
+
+ g = gen()
+ next(g)
+ try:
+ raise ValueError
+ except Exception:
+ next(g)
+
+ assert next(g) == "done"
+ assert sys.exc_info() == (None, None, None)
def test_multiple_invalid_sends():
def mygen():
@@ -793,13 +821,9 @@
yield from map(operator.truediv, [2, 3], [4, 0])
gen = f()
assert next(gen) == 0.5
- try:
+ with raises(ZeroDivisionError) as excinfo:
next(gen)
- except ZeroDivisionError as e:
- assert e.__context__ is not None
- assert isinstance(e.__context__, ValueError)
- else:
- assert False, "should have raised"
+ assert isinstance(excinfo.value.__context__, ValueError)
def test_past_generator_stop():
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_error_state = pre_switch(sthread)
+ saved_exception = pre_switch(sthread)
h = sthread.new(new_stacklet_callback)
- post_switch(sthread, h, saved_error_state)
+ post_switch(sthread, h, saved_exception)
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_error_state = pre_switch(sthread)
+ saved_exception = pre_switch(sthread)
h = sthread.switch(global_state.destination.h)
- return post_switch(sthread, h, saved_error_state)
+ return post_switch(sthread, h, saved_exception)
@unwrap_spec(w_value = WrappedDefault(None),
w_to = WrappedDefault(None))
@@ -257,9 +257,11 @@
return self.h
def pre_switch(sthread):
- return sthread.ec.fetch_and_clear_error_stack_state()
+ saved_exception = sthread.ec.sys_exc_info()
+ sthread.ec.set_sys_exc_info(None)
+ return saved_exception
-def post_switch(sthread, h, saved_error_state):
+def post_switch(sthread, h, saved_exception):
origin = global_state.origin
self = global_state.destination
global_state.origin = None
@@ -268,7 +270,7 @@
#
current = sthread.ec.topframeref
sthread.ec.topframeref = self.bottomframe.f_backref
- sthread.ec.restore_error_stack_state(saved_error_state)
+ sthread.ec.set_sys_exc_info(saved_exception)
self.bottomframe.f_backref = origin.bottomframe.f_backref
origin.bottomframe.f_backref = current
#
More information about the pypy-commit
mailing list