[pypy-commit] pypy py3.5: Add operror.chain_exception(), to add a __context__ from rpython code.
amauryfa
pypy.commits at gmail.com
Sun Nov 13 14:44:23 EST 2016
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.5
Changeset: r88363:e1ddd470a8ac
Date: 2016-11-12 20:45 +0100
http://bitbucket.org/pypy/pypy/changeset/e1ddd470a8ac/
Log: Add operror.chain_exception(), to add a __context__ from rpython
code.
But this can call normalize_exception() more often. Move w_cause out
of normalize_exception(), to not overwrite the "suppress_context"
flag.
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -33,12 +33,10 @@
_w_value = None
_application_traceback = None
_context_recorded = False
- w_cause = None
- def __init__(self, w_type, w_value, tb=None, w_cause=None):
+ def __init__(self, w_type, w_value, tb=None):
self.setup(w_type, w_value)
self._application_traceback = tb
- self.w_cause = w_cause
def setup(self, w_type, w_value=None):
assert w_type is not None
@@ -215,13 +213,6 @@
# raise Type, X: assume X is the constructor argument
w_value = space.call_function(w_type, w_value)
w_type = self._exception_getclass(space, w_value)
- if self.w_cause:
- # ensure w_cause is of a valid type
- if space.is_none(self.w_cause):
- pass
- else:
- self._exception_getclass(space, self.w_cause, "exception causes")
- space.setattr(w_value, space.wrap("__cause__"), self.w_cause)
if self._application_traceback:
from pypy.interpreter.pytraceback import PyTraceback
from pypy.module.exceptions.interp_exceptions import W_BaseException
@@ -318,6 +309,17 @@
tb.frame.mark_as_escaped()
return tb
+ def set_cause(self, space, w_cause):
+ if w_cause is None:
+ return
+ # ensure w_cause is of a valid type
+ if space.is_none(w_cause):
+ pass
+ else:
+ self._exception_getclass(space, w_cause, "exception causes")
+ w_value = self.get_w_value(space)
+ space.setattr(w_value, space.wrap("__cause__"), w_cause)
+
def set_traceback(self, traceback):
"""Set the current traceback."""
self._application_traceback = traceback
@@ -340,15 +342,20 @@
last = frame._exc_info_unroll(space)
try:
if last is not None:
- self.normalize_exception(space)
- w_value = self.get_w_value(space)
- w_last = last.get_w_value(space)
- if not space.is_w(w_value, w_last):
- _break_context_cycle(space, w_value, w_last)
- space.setattr(w_value, space.wrap('__context__'), w_last)
+ self.chain_exceptions(space, last)
finally:
self._context_recorded = True
+ def chain_exceptions(self, space, context):
+ """Attach another OperationError as __context__."""
+ self.normalize_exception(space)
+ w_value = self.get_w_value(space)
+ context.normalize_exception(space)
+ w_context = context.get_w_value(space)
+ if not space.is_w(w_value, w_context):
+ _break_context_cycle(space, w_value, w_context)
+ space.setattr(w_value, space.wrap('__context__'), w_context)
+
# A simplified version of _PyErr_TrySetFromCause, which returns a
# new exception of the same class, but with another error message.
# This only works for exceptions which have just a single message,
@@ -376,8 +383,8 @@
try:
new_error = oefmt(space.type(w_value),
"%s (%T: %S)", message, w_value, w_value)
- new_error.w_cause = w_value
new_error.normalize_exception(space)
+ new_error.set_cause(space, w_value)
# Copy the traceback, but it does not escape.
new_error.set_traceback(self._application_traceback)
except OperationError:
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -224,8 +224,8 @@
consts.CO_ITERABLE_COROUTINE):
e2 = OperationError(space.w_RuntimeError,
space.wrap("%s raised StopIteration" %
- self.KIND),
- w_cause=e.get_w_value(space))
+ self.KIND))
+ e2.chain_exceptions(space, e)
e2.record_context(space, self.frame)
raise e2
else:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -707,8 +707,9 @@
w_value = space.call_function(w_type)
else:
w_type = space.type(w_value)
- operror = OperationError(w_type, w_value, w_cause=w_cause)
+ operror = OperationError(w_type, w_value)
operror.normalize_exception(space)
+ operror.set_cause(space, w_cause)
tb = space.getattr(w_value, space.wrap('__traceback__'))
if not space.is_w(tb, space.w_None):
operror.set_traceback(tb)
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -302,21 +302,19 @@
with self.lock:
if self._closed(space):
return
- w_flush_exception = None
+ flush_operr = None
try:
space.call_method(self, "flush")
except OperationError as e:
- w_flush_exception = e.get_w_value(space)
+ flush_operr = e
raise
finally:
with self.lock:
try:
space.call_method(self.w_raw, "close")
except OperationError as e:
- if w_flush_exception:
- space.setattr(e.get_w_value(space),
- space.wrap('__context__'),
- w_flush_exception)
+ if flush_operr:
+ e.chain_exceptions(space, flush_operr)
raise
def _dealloc_warn_w(self, space, w_source):
More information about the pypy-commit
mailing list