Author: Amaury Forgeot d'Arc <amaur...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit