Index: Lib/test/test_support.py =================================================================== --- Lib/test/test_support.py (revision 77953) +++ Lib/test/test_support.py (working copy) @@ -16,6 +16,7 @@ import unittest import importlib import UserDict +import re __all__ = ["Error", "TestFailed", "ResourceDenied", "import_module", "verbose", "use_resources", "max_memuse", "record_original_stdout", @@ -23,8 +24,8 @@ "is_resource_enabled", "requires", "find_unused_port", "bind_port", "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", "findfile", "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", @@ -466,23 +467,91 @@ 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) -@contextlib.contextmanager -def check_warnings(): +def _filterwarnings(filters, lazy=False): + # clear the warning registry of the calling module + frame = sys._getframe(2) + registry = frame.f_globals.get('__warningregistry__') + if registry: + registry.clear() with warnings.catch_warnings(record=True) as w: 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 lazy: + # 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(*filters, **kwargs): + """Context manager to silence warnings. + + Accept 2-tuples as positional arguments: + ("message regexp", WarningCategory) + + Optional argument: + - if 'lazy' is True, it does not fail if a filter catch nothing + (default False) + + Without argument, it defaults to: + check_warnings(("", Warning), lazy=False) + """ + if not filters: + filters = (("", Warning),) + return _filterwarnings(filters, kwargs.get('lazy')) + +@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 'lazy' is True, it does not fail if a filter catch nothing + (default False) + + Without argument, it defaults to: + check_py3k_warnings(("", DeprecationWarning), lazy=False) + """ + if sys.py3kwarning: + if not filters: + filters = (("", DeprecationWarning),) + return _filterwarnings(filters, kwargs.get('lazy')) + else: + # Dummy generator + return ([] for _ in '_') class CleanImport(object): """Context manager to force import to return a new module reference. @@ -713,7 +782,6 @@ MAX_Py_ssize_t = sys.maxsize def set_memlimit(limit): - import re global max_memuse global real_max_memuse sizes = {