diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 6bc681ad815..7e214ebfbf4 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -686,8 +686,9 @@ class CommonTest(unittest.TestCase): EQ("bobobXbobob", "bobobobXbobobob", "replace", "bobob", "bob") EQ("BOBOBOB", "BOBOBOB", "replace", "bob", "bobby") - ba = buffer('a') - bb = buffer('b') + with test_support._check_py3k_warnings(): + ba = buffer('a') + bb = buffer('b') EQ("bbc", "abc", "replace", ba, bb) EQ("aac", "abc", "replace", bb, ba) diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py index d1b3751ef70..7eeef7ba8a2 100644 --- a/Lib/test/test_fileio.py +++ b/Lib/test/test_fileio.py @@ -259,7 +259,7 @@ class OtherFileTests(unittest.TestCase): self.assertRaises(TypeError, _fileio._FileIO, "1", 0, 0) def testWarnings(self): - with check_warnings() as w: + with check_warnings(quiet=True) as w: self.assertEqual(w.warnings, []) self.assertRaises(TypeError, _fileio._FileIO, []) self.assertEqual(w.warnings, []) diff --git a/Lib/test/test_index.py b/Lib/test/test_index.py index 75f24342737..c985569e0df 100644 --- a/Lib/test/test_index.py +++ b/Lib/test/test_index.py @@ -195,8 +195,9 @@ class OverflowTestCase(unittest.TestCase): x = GetItem() self.assertEqual(x[self.pos], self.pos) self.assertEqual(x[self.neg], self.neg) - self.assertEqual(x[self.neg:self.pos], (maxint+minsize, maxsize)) - self.assertEqual(x[self.neg:self.pos:1].indices(maxsize), (0, maxsize, 1)) + with test_support._check_py3k_warnings(): + self.assertEqual(x[self.neg:self.pos], (maxint+minsize, maxsize)) + self.assertEqual(x[self.neg:self.pos:1].indices(maxsize), (0, maxsize, 1)) def test_getitem(self): self._getitem_helper(object) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index d82d391fe3e..937bb4cf381 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -52,10 +52,11 @@ class TestBasicOps(unittest.TestCase): state3 = self.gen.getstate() # s/b distinct from state2 self.assertNotEqual(state2, state3) - self.assertRaises(TypeError, self.gen.jumpahead) # needs an arg - self.assertRaises(TypeError, self.gen.jumpahead, "ick") # wrong type - self.assertRaises(TypeError, self.gen.jumpahead, 2.3) # wrong type - self.assertRaises(TypeError, self.gen.jumpahead, 2, 3) # too many + with test_support._check_py3k_warnings(quiet=True): + self.assertRaises(TypeError, self.gen.jumpahead) # needs an arg + self.assertRaises(TypeError, self.gen.jumpahead, "ick") # wrong type + self.assertRaises(TypeError, self.gen.jumpahead, 2.3) # wrong type + self.assertRaises(TypeError, self.gen.jumpahead, 2, 3) # too many def test_sample(self): # For the entire allowable range of 0 <= k <= N, validate that diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index d4b891e2e40..7400b0dc3a2 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -11,6 +11,7 @@ import os import shutil import warnings import unittest +import re __all__ = ["Error", "TestFailed", "TestSkipped", "ResourceDenied", "import_module", "verbose", "use_resources", "max_memuse", "record_original_stdout", @@ -18,8 +19,8 @@ __all__ = ["Error", "TestFailed", "TestSkipped", "ResourceDenied", "import_modul "is_resource_enabled", "requires", "find_unused_port", "bind_port", "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", "findfile", "verify", "vereq", "sortdict", "check_syntax_error", - "open_urlresource", "check_warnings", "CleanImport", - "EnvironmentVarGuard", "captured_output", + "open_urlresource", "check_warnings", "_check_py3k_warnings", + "CleanImport", "EnvironmentVarGuard", "captured_output", "captured_stdout", "TransientResource", "transient_internet", "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", @@ -406,22 +407,103 @@ class WarningsRecorder(object): entry to the warnings.catch_warnings() context manager. """ def __init__(self, warnings_list): - self.warnings = warnings_list + self._warnings = warnings_list + self._last = 0 def __getattr__(self, attr): - if self.warnings: - return getattr(self.warnings[-1], attr) + if len(self._warnings) > self._last: + return getattr(self._warnings[-1], attr) elif attr in warnings.WarningMessage._WARNING_DETAILS: return None raise AttributeError("%r has no attribute %r" % (self, attr)) + @property + def warnings(self): + return self._warnings[self._last:] + def reset(self): - del self.warnings[:] + self._last = len(self._warnings) + + +def _filterwarnings(filters, quiet=False): + """Catch the warnings, then check if all the expected + warnings have been raised and re-raise unexpected warnings. + If 'quiet' is True, only re-raise the unexpected warnings. + """ + # Clear the warning registry of the calling module + # in order to re-raise the warnings. + frame = sys._getframe(2) + registry = frame.f_globals.get('__warningregistry__') + if registry: + registry.clear() + with warnings.catch_warnings(record=True) as w: + # Disable filters, to record all warnings. Because + # test_warnings swap the module, we need to look up + # in the sys.modules dictionary. + sys.modules['warnings'].resetwarnings() + yield WarningsRecorder(w) + # Filter the recorded warnings + reraise = [warning.message for warning in w] + missing = [] + for msg, cat in filters: + seen = False + for exc in reraise[:]: + message = str(exc) + # Filter out the matching messages + if (re.match(msg, message, re.I) and + issubclass(exc.__class__, cat)): + seen = True + reraise.remove(exc) + if not seen and not quiet: + # This filter caught nothing + missing.append((msg, cat.__name__)) + for exc in reraise: + raise AssertionError("unhandled warning %r" % exc) + for filter in missing: + raise AssertionError("filter (%r, %s) did not caught any warning" % + filter) + @contextlib.contextmanager -def check_warnings(): - with warnings.catch_warnings(record=True) as w: - yield WarningsRecorder(w) +def check_warnings(*filters, **kwargs): + """Context manager to silence warnings. + + Accept 2-tuples as positional arguments: + ("message regexp", WarningCategory) + + Optional argument: + - if 'quiet' is True, it does not fail if a filter catches nothing + (default False) + + Without argument, it defaults to: + check_warnings(("", Warning), quiet=False) + """ + if not filters: + filters = (("", Warning),) + return _filterwarnings(filters, kwargs.get('quiet')) + + +@contextlib.contextmanager +def _check_py3k_warnings(*filters, **kwargs): + """Context manager to silence py3k warnings. + + Accept 2-tuples as positional arguments: + ("message regexp", WarningCategory) + + Optional argument: + - if 'quiet' is True, it does not fail if a filter catches nothing + (default False) + + Without argument, it defaults to: + _check_py3k_warnings(("", DeprecationWarning), quiet=False) + """ + if sys.py3kwarning: + if not filters: + filters = (("", DeprecationWarning),) + else: + # It should not raise any py3k warning + filters = () + return _filterwarnings(filters, kwargs.get('quiet')) class CleanImport(object): @@ -595,7 +677,6 @@ _4G = 4 * _1G MAX_Py_ssize_t = sys.maxsize def set_memlimit(limit): - import re global max_memuse global real_max_memuse sizes = { diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 53c7800c9a3..35134ec81ec 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -511,9 +511,11 @@ class UnicodeTest( ) if not sys.platform.startswith('java'): + with test_support._check_py3k_warnings(): + buf = buffer('character buffers are decoded to unicode') self.assertEqual( unicode( - buffer('character buffers are decoded to unicode'), + buf, 'utf-8', 'strict' ), diff --git a/Misc/NEWS b/Misc/NEWS index cab0a14e608..77e1377e445 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,9 +35,6 @@ Core and Builtins when turned into an exception: in this case the exception simply gets ignored. -- Issue #7372: Fix pstats regression when stripping paths from profile - data generated with the profile module. - - Issue #4108: In urllib.robotparser, if there are multiple 'User-agent: *' entries, consider the first one. @@ -422,6 +419,10 @@ Build Tests ----- +- Issue #7849: Now the utility ``check_warnings`` verifies if the warnings are + effectively raised. A new private utility ``_check_py3k_warnings`` has been + backported to help silencing py3k warnings. + - Issue #8672: Add a zlib test ensuring that an incomplete stream can be handled by a decompressor object without errors (it returns incomplete uncompressed data).