diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-13 12:25:08 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2008-07-13 12:25:08 (GMT) |
commit | b130493834e5bd807ab80dcd8b417d7623baca24 (patch) | |
tree | 3842a93fe70989950ba9db64bc8d4a5543286e59 /Lib | |
parent | 628b1b3659d9db96210cb599579b79625eed1488 (diff) | |
download | cpython-b130493834e5bd807ab80dcd8b417d7623baca24.zip cpython-b130493834e5bd807ab80dcd8b417d7623baca24.tar.gz cpython-b130493834e5bd807ab80dcd8b417d7623baca24.tar.bz2 |
Make test.test_support.catch_warnings more robust as discussed on python-dev. Also add explicit tests for it to test_warnings. (forward port of r64910 from trunk)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/support.py | 71 | ||||
-rw-r--r-- | Lib/test/test_struct.py | 11 | ||||
-rw-r--r-- | Lib/test/test_warnings.py | 42 |
3 files changed, 90 insertions, 34 deletions
diff --git a/Lib/test/support.py b/Lib/test/support.py index c6ce760..d026984 100644 --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -368,36 +368,49 @@ def open_urlresource(url, *args, **kw): class WarningMessage(object): - "Holds the result of the latest showwarning() call" + "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.message = None - self.category = None - self.filename = None - self.lineno = None - - def _showwarning(self, message, category, filename, lineno, file=None, - line=None): - self.message = message - self.category = category - self.filename = filename - self.lineno = lineno - self.line = line + 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._showwarning(*((None,)*6)) + self.warnings = [] + self._set_last(None) def __str__(self): - return ("{message : %r, category : %r, filename : %r, lineno : %s, " - "line : %r}" % (self.message, - self.category.__name__ if self.category else None, - self.filename, self.lineno, self.line)) - + 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 record the - data of the last warning that has been issued. + """Guard the warnings filter from being permanently changed and + optionally record the details of any warnings that are issued. Use like this: @@ -405,13 +418,17 @@ def catch_warning(module=warnings, record=True): warnings.warn("foo") assert str(w.message) == "foo" """ - original_filters = module.filters[:] + original_filters = module.filters original_showwarning = module.showwarning if record: - warning_obj = WarningMessage() - module.showwarning = warning_obj._showwarning + recorder = WarningRecorder() + module.showwarning = recorder._showwarning + else: + recorder = None try: - yield warning_obj if record else None + # Replace the filters with a copy of the original + module.filters = module.filters[:] + yield recorder finally: module.showwarning = original_showwarning module.filters = original_filters @@ -421,7 +438,7 @@ class CleanImport(object): """Context manager to force import to return a new module reference. This is useful for testing module-level behaviours, such as - the emission of a DepreciationWarning on import. + the emission of a DeprecationWarning on import. Use like this: diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index bce8fdc..6dc0e8d 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -35,12 +35,9 @@ def with_warning_restore(func): @wraps(func) def decorator(*args, **kw): with catch_warning(): - # Grrr, we need this function to warn every time. Without removing - # the warningregistry, running test_tarfile then test_struct would fail - # on 64-bit platforms. - globals = func.__globals__ - if '__warningregistry__' in globals: - del globals['__warningregistry__'] + # We need this function to warn every time, so stick an + # unqualifed 'always' at the head of the filter list + warnings.simplefilter("always") warnings.filterwarnings("error", category=DeprecationWarning) return func(*args, **kw) return decorator @@ -53,7 +50,7 @@ def deprecated_err(func, *args): pass except DeprecationWarning: if not PY_STRUCT_OVERFLOW_MASKING: - raise TestFailed("%s%s expected to raise struct.error" % ( + raise TestFailed("%s%s expected to raise DeprecationWarning" % ( func.__name__, args)) else: raise TestFailed("%s%s did not raise error" % ( diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index 1e17313..b6634c0 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -487,6 +487,47 @@ class CWarningsDisplayTests(BaseTest, WarningsDisplayTests): class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests): module = py_warnings +class WarningsSupportTests(object): + """Test the warning tools from test support module""" + + def test_catch_warning_restore(self): + wmod = self.module + orig_filters = wmod.filters + orig_showwarning = wmod.showwarning + with support.catch_warning(wmod): + wmod.filters = wmod.showwarning = object() + self.assert_(wmod.filters is orig_filters) + self.assert_(wmod.showwarning is orig_showwarning) + with support.catch_warning(wmod, record=False): + wmod.filters = wmod.showwarning = object() + self.assert_(wmod.filters is orig_filters) + self.assert_(wmod.showwarning is orig_showwarning) + + def test_catch_warning_recording(self): + wmod = self.module + with support.catch_warning(wmod) as w: + self.assertEqual(w.warnings, []) + wmod.simplefilter("always") + wmod.warn("foo") + self.assertEqual(str(w.message), "foo") + wmod.warn("bar") + self.assertEqual(str(w.message), "bar") + self.assertEqual(str(w.warnings[0].message), "foo") + self.assertEqual(str(w.warnings[1].message), "bar") + w.reset() + self.assertEqual(w.warnings, []) + orig_showwarning = wmod.showwarning + with support.catch_warning(wmod, record=False) as w: + self.assert_(w is None) + self.assert_(wmod.showwarning is orig_showwarning) + + +class CWarningsSupportTests(BaseTest, WarningsSupportTests): + module = c_warnings + +class PyWarningsSupportTests(BaseTest, WarningsSupportTests): + module = py_warnings + def test_main(): py_warnings.onceregistry.clear() @@ -498,6 +539,7 @@ def test_main(): CWCmdLineTests, PyWCmdLineTests, _WarningsTests, CWarningsDisplayTests, PyWarningsDisplayTests, + CWarningsSupportTests, PyWarningsSupportTests, ) |