Move test.test_support.catch_warning() to the warnings module, rename it

catch_warnings(), and clean up the API.

While expanding the test suite, a bug was found where a warning about the
'line' argument to showwarning() was not letting functions with '*args' go
without a warning.

Closes issue 3602.
Code review by Benjamin Peterson.
This commit is contained in:
Brett Cannon 2008-09-02 01:25:16 +00:00
parent 86533776c2
commit 1eaf0742d8
11 changed files with 208 additions and 126 deletions

View file

@ -18,7 +18,7 @@ __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", "WarningMessage", "catch_warning", "CleanImport",
"open_urlresource", "catch_warning", "CleanImport",
"EnvironmentVarGuard", "captured_output",
"captured_stdout", "TransientResource", "transient_internet",
"run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest",
@ -381,71 +381,8 @@ def open_urlresource(url):
return open(fn)
class WarningMessage(object):
"Holds the result of a single showwarning() call"
_WARNING_DETAILS = "message category filename lineno line".split()
def __init__(self, message, category, filename, lineno, line=None):
for attr in self._WARNING_DETAILS:
setattr(self, attr, locals()[attr])
self._category_name = category.__name__ if category else None
def __str__(self):
return ("{message : %r, category : %r, filename : %r, lineno : %s, "
"line : %r}" % (self.message, self._category_name,
self.filename, self.lineno, self.line))
class WarningRecorder(object):
"Records the result of any showwarning calls"
def __init__(self):
self.warnings = []
self._set_last(None)
def _showwarning(self, message, category, filename, lineno,
file=None, line=None):
wm = WarningMessage(message, category, filename, lineno, line)
self.warnings.append(wm)
self._set_last(wm)
def _set_last(self, last_warning):
if last_warning is None:
for attr in WarningMessage._WARNING_DETAILS:
setattr(self, attr, None)
else:
for attr in WarningMessage._WARNING_DETAILS:
setattr(self, attr, getattr(last_warning, attr))
def reset(self):
self.warnings = []
self._set_last(None)
def __str__(self):
return '[%s]' % (', '.join(map(str, self.warnings)))
@contextlib.contextmanager
def catch_warning(module=warnings, record=True):
"""Guard the warnings filter from being permanently changed and
optionally record the details of any warnings that are issued.
Use like this:
with catch_warning() as w:
warnings.warn("foo")
assert str(w.message) == "foo"
"""
original_filters = module.filters
original_showwarning = module.showwarning
if record:
recorder = WarningRecorder()
module.showwarning = recorder._showwarning
else:
recorder = None
try:
# Replace the filters with a copy of the original
module.filters = module.filters[:]
yield recorder
finally:
module.showwarning = original_showwarning
module.filters = original_filters
return warnings.catch_warnings(record=record, module=module)
class CleanImport(object):