diff -r e8447da8791d Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py Sat Sep 06 20:38:23 2014 +1000 +++ b/Lib/test/test_codecs.py Sat Sep 06 22:31:16 2014 +1000 @@ -1,8 +1,10 @@ import codecs import contextlib +import gc import io import locale import sys +import traceback import unittest import warnings import encodings @@ -2578,6 +2580,22 @@ return _TEST_CODECS.get(codec_name) codecs.register(_get_test_codec) # Returns None, not usable as a decorator +def _walk_tracebacks(exc): + tb = exc.__traceback__ + if tb is not None: + yield tb + cause = exc.__cause__ + if cause is not None: + yield from _walk_tracebacks(cause) + context = exc.__context__ + if context is not None: + yield from _walk_tracebacks(context) + +def _clear_exc_frames(exc): + for tb in _walk_tracebacks(exc): + traceback.clear_frames(tb) + + class ExceptionChainingTest(unittest.TestCase): def setUp(self): @@ -2602,7 +2620,14 @@ self.obj_to_raise = RuntimeError def tearDown(self): - _TEST_CODECS.pop(self.codec_name, None) + entry = _TEST_CODECS.pop(self.codec_name, None) + encodings._cache.pop(self.codec_name, None) + if entry is not None: + # Hack to get at "codec_search_cache" in the interpreter state + for ref in gc.get_referrers(entry): + if isinstance(ref, dict): + ref.pop(self.codec_name, None) + def set_codec(self, encode, decode): codec_info = codecs.CodecInfo(encode, decode, @@ -2617,14 +2642,12 @@ yield caught self.assertIsInstance(caught.exception.__cause__, exc_type) self.assertIsNotNone(caught.exception.__cause__.__traceback__) - - def raise_obj(self, *args, **kwds): - # Helper to dynamically change the object raised by a test codec - raise self.obj_to_raise + _clear_exc_frames(caught.exception) def check_wrapped(self, obj_to_raise, msg, exc_type=RuntimeError): - self.obj_to_raise = obj_to_raise - self.set_codec(self.raise_obj, self.raise_obj) + def raise_obj(self, *args, **kwds): + raise obj_to_raise() + self.set_codec(raise_obj, raise_obj) with self.assertWrapped("encoding", exc_type, msg): "str_input".encode(self.codec_name) with self.assertWrapped("encoding", exc_type, msg): @@ -2635,27 +2658,32 @@ codecs.decode(b"bytes input", self.codec_name) def test_raise_by_type(self): - self.check_wrapped(RuntimeError, "") + self.check_wrapped(lambda: RuntimeError, "") def test_raise_by_value(self): msg = "This should be wrapped" - self.check_wrapped(RuntimeError(msg), msg) + self.check_wrapped(lambda: RuntimeError(msg), msg) + + class RuntimeErrorWithSlots(RuntimeError): + __slots__ = () def test_raise_grandchild_subclass_exact_size(self): msg = "This should be wrapped" - class MyRuntimeError(RuntimeError): - __slots__ = () - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) + self.check_wrapped(lambda: self.RuntimeErrorWithSlots(msg), msg, + self.RuntimeErrorWithSlots) + + + class RuntimeErrorWithWeakrefs(RuntimeError): + pass def test_raise_subclass_with_weakref_support(self): msg = "This should be wrapped" - class MyRuntimeError(RuntimeError): - pass - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) + self.check_wrapped(lambda: self.RuntimeErrorWithWeakrefs(msg), msg, + self.RuntimeErrorWithWeakrefs) def check_not_wrapped(self, obj_to_raise, msg): def raise_obj(*args, **kwds): - raise obj_to_raise + raise obj_to_raise() self.set_codec(raise_obj, raise_obj) with self.assertRaisesRegex(RuntimeError, msg): "str input".encode(self.codec_name) @@ -2666,30 +2694,34 @@ with self.assertRaisesRegex(RuntimeError, msg): codecs.decode(b"bytes input", self.codec_name) + class CustomInit(RuntimeError): + def __init__(self): + pass + def test_init_override_is_not_wrapped(self): - class CustomInit(RuntimeError): - def __init__(self): - pass - self.check_not_wrapped(CustomInit, "") + self.check_not_wrapped(lambda: self.CustomInit, "") + + class CustomNew(RuntimeError): + def __new__(cls): + return super().__new__(cls) def test_new_override_is_not_wrapped(self): - class CustomNew(RuntimeError): - def __new__(cls): - return super().__new__(cls) - self.check_not_wrapped(CustomNew, "") + self.check_not_wrapped(lambda: self.CustomNew, "") def test_instance_attribute_is_not_wrapped(self): msg = "This should NOT be wrapped" - exc = RuntimeError(msg) - exc.attr = 1 - self.check_not_wrapped(exc, "^{}$".format(msg)) + def func(): + exc = RuntimeError(msg) + exc.attr = 1 + return exc + self.check_not_wrapped(func, "^{}$".format(msg)) def test_non_str_arg_is_not_wrapped(self): - self.check_not_wrapped(RuntimeError(1), "1") + self.check_not_wrapped(lambda: RuntimeError(1), "1") def test_multiple_args_is_not_wrapped(self): msg_re = r"^\('a', 'b', 'c'\)$" - self.check_not_wrapped(RuntimeError('a', 'b', 'c'), msg_re) + self.check_not_wrapped(lambda: RuntimeError('a', 'b', 'c'), msg_re) # http://bugs.python.org/issue19609 def test_codec_lookup_failure_not_wrapped(self):