[pypy-commit] pypy py3.5: Don't wrap codec exceptions when they have an attribute or more arguments.
amauryfa
pypy.commits at gmail.com
Sat Nov 5 16:23:25 EDT 2016
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.5
Changeset: r88148:9abb6079ac04
Date: 2016-11-05 17:27 +0100
http://bitbucket.org/pypy/pypy/changeset/9abb6079ac04/
Log: Don't wrap codec exceptions when they have an attribute or more
arguments.
Move the code to errors.py because it relies on implementation
details.
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -344,6 +344,42 @@
finally:
self._context_recorded = True
+ # 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,
+ # and no other attribute.
+ # Otherwise the same OperationError is returned.
+ def try_set_from_cause(self, space, message):
+ from pypy.module.exceptions.interp_exceptions import W_BaseException
+ self.normalize_exception(space)
+ w_value = self.get_w_value(space)
+ if not isinstance(w_value, W_BaseException):
+ return self
+ exc = w_value
+ # "args" should be empty or contain a single string
+ if len(exc.args_w) == 0:
+ pass
+ elif len(exc.args_w) == 1:
+ if not space.isinstance_w(exc.args_w[0], space.w_unicode):
+ return self
+ else:
+ return self
+ # No instance attribute.
+ if exc.w_dict and space.is_true(exc.w_dict):
+ return self
+ # Try to create the new exception.
+ 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)
+ # Copy the traceback, but it does not escape.
+ new_error.set_traceback(self._application_traceback)
+ except OperationError:
+ # Return the original error
+ return self
+ return new_error
+
def _break_context_cycle(space, w_value, w_context):
"""Break reference cycles in the __context__ chain.
diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -415,23 +415,11 @@
state.codec_error_registry[error] = space.wrap(interp2app(globals()[name]))
-# A simplified version of the incredibly complex CPython function
-# _PyErr_TrySetFromCause, which returns a new exception with another
-# error message. Subclasses of UnicodeErrors are returned inchanged,
-# but this is only a side-effect: they cannot be constructed with a
-# simple message.
def _wrap_codec_error(space, operr, action, encoding):
- w_exc = operr.get_w_value(space)
- try:
- new_operr = oefmt(space.type(w_exc),
- "%s with '%s' codec failed (%T: %S)",
- action, encoding, w_exc, w_exc)
- new_operr.w_cause = w_exc
- new_operr.normalize_exception(space)
- except OperationError:
- # Return the original error
- return operr
- return new_operr
+ # Note that UnicodeErrors are not wrapped and returned as is,
+ # "thanks to" a limitation of try_set_from_cause.
+ message = "%s with '%s' codec failed" % (action, encoding)
+ return operr.try_set_from_cause(space, message)
def _call_codec(space, w_decoder, w_obj, action, encoding, errors):
try:
diff --git a/pypy/module/_codecs/test/test_codecs.py b/pypy/module/_codecs/test/test_codecs.py
--- a/pypy/module/_codecs/test/test_codecs.py
+++ b/pypy/module/_codecs/test/test_codecs.py
@@ -380,11 +380,12 @@
import _codecs
def search_function(encoding):
def f(input, errors="strict"):
- raise RuntimeError('should be wrapped')
+ raise to_raise
if encoding == 'test.failingenc':
return (f, f, None, None)
return None
_codecs.register(search_function)
+ to_raise = RuntimeError('should be wrapped')
exc = raises(RuntimeError, b"hello".decode, "test.failingenc")
assert str(exc.value) == (
"decoding with 'test.failingenc' codec failed "
@@ -393,6 +394,14 @@
assert str(exc.value) == (
"encoding with 'test.failingenc' codec failed "
"(RuntimeError: should be wrapped)")
+ #
+ to_raise.attr = "don't wrap"
+ exc = raises(RuntimeError, u"hello".encode, "test.failingenc")
+ assert exc.value == to_raise
+ #
+ to_raise = RuntimeError("Should", "Not", "Wrap")
+ exc = raises(RuntimeError, u"hello".encode, "test.failingenc")
+ assert exc.value == to_raise
def test_cpytest_decode(self):
import codecs
More information about the pypy-commit
mailing list