From e6dae6c655bf1e5542f8d3821e2710e9fc0b5762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Walter=20D=C3=B6rwald?= Date: Tue, 3 Apr 2007 18:33:29 +0000 Subject: Implement a contextmanager test.test_support.catch_warning that can be used to catch the last warning issued by the warning framework. Change test_warnings.py and test_structmembers.py to use this new contextmanager. --- Lib/test/test_structmembers.py | 39 +++++----- Lib/test/test_support.py | 36 +++++++++ Lib/test/test_warnings.py | 162 +++++++++++++++++------------------------ Misc/NEWS | 3 + 4 files changed, 129 insertions(+), 111 deletions(-) diff --git a/Lib/test/test_structmembers.py b/Lib/test/test_structmembers.py index 5dc2175..33fc776 100644 --- a/Lib/test/test_structmembers.py +++ b/Lib/test/test_structmembers.py @@ -4,7 +4,7 @@ from _testcapi import test_structmembersType, \ INT_MAX, INT_MIN, UINT_MAX, \ LONG_MAX, LONG_MIN, ULONG_MAX -import warnings, exceptions, unittest, test.test_warnings +import warnings, exceptions, unittest from test import test_support ts=test_structmembersType(1,2,3,4,5,6,7,8,9.99999,10.1010101010) @@ -39,34 +39,39 @@ class ReadWriteTests(unittest.TestCase): ts.T_ULONG=ULONG_MAX self.assertEquals(ts.T_ULONG, ULONG_MAX) -class TestWarnings(test.test_warnings.CatchWarningTest): - def has_warned(self): - self.assertEqual(test.test_warnings.msg.category, - exceptions.RuntimeWarning.__name__) +class TestWarnings(unittest.TestCase): + def has_warned(self, w): + self.assert_(w.category is RuntimeWarning) def test_byte_max(self): - ts.T_BYTE=CHAR_MAX+1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_BYTE=CHAR_MAX+1 + self.has_warned(w) def test_byte_min(self): - ts.T_BYTE=CHAR_MIN-1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_BYTE=CHAR_MIN-1 + self.has_warned(w) def test_ubyte_max(self): - ts.T_UBYTE=UCHAR_MAX+1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_UBYTE=UCHAR_MAX+1 + self.has_warned(w) def test_short_max(self): - ts.T_SHORT=SHRT_MAX+1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_SHORT=SHRT_MAX+1 + self.has_warned(w) def test_short_min(self): - ts.T_SHORT=SHRT_MIN-1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_SHORT=SHRT_MIN-1 + self.has_warned(w) def test_ushort_max(self): - ts.T_USHORT=USHRT_MAX+1 - self.has_warned() + with test_support.catch_warning() as w: + ts.T_USHORT=USHRT_MAX+1 + self.has_warned(w) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index b04a9a0..7e24395 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -282,6 +282,42 @@ def guard_warnings_filter(): finally: warnings.filters = original_filters +class WarningMessage(object): + "Holds the result of the latest showwarning() call" + def __init__(self): + self.message = None + self.category = None + self.filename = None + self.lineno = None + + def _showwarning(self, message, category, filename, lineno, file=None): + self.message = message + self.category = category + self.filename = filename + self.lineno = lineno + +@contextlib.contextmanager +def catch_warning(): + """ + Guard the warnings filter from being permanently changed and record the + data of the last warning that has been issued. + + Use like this: + + with catch_warning as w: + warnings.warn("foo") + assert str(w.message) == "foo" + """ + warning = WarningMessage() + original_filters = warnings.filters[:] + original_showwarning = warnings.showwarning + warnings.showwarning = warning._showwarning + try: + yield warning + finally: + warnings.showwarning = original_showwarning + warnings.filters = original_filters + class EnvironmentVarGuard(object): """Class to help protect the environment variable properly. Can be used as diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index f6c9339..283806f 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -5,121 +5,95 @@ from test import test_support import warning_tests -# The warnings module isn't easily tested, because it relies on module -# globals to store configuration information. setUp() and tearDown() -# preserve the current settings to avoid bashing them while running tests. - -# To capture the warning messages, a replacement for showwarning() is -# used to save warning information in a global variable. - -class WarningMessage: - "Holds results of latest showwarning() call" - pass - -def showwarning(message, category, filename, lineno, file=None): - msg.message = str(message) - msg.category = category.__name__ - msg.filename = os.path.basename(filename) - msg.lineno = lineno - -class CatchWarningTest(unittest.TestCase): - # base class used for catching warnings issued by the - # warning framework (this is reused by test_structmembers.py) - +class TestModule(unittest.TestCase): def setUp(self): - global msg - msg = WarningMessage() - self._filters = warnings.filters[:] - self._showwarning = warnings.showwarning - warnings.showwarning = showwarning - self.ignored = [w[2].__name__ for w in self._filters + self.ignored = [w[2].__name__ for w in warnings.filters if w[0]=='ignore' and w[1] is None and w[3] is None] - def tearDown(self): - warnings.filters = self._filters[:] - warnings.showwarning = self._showwarning - -class TestModule(CatchWarningTest): - def test_warn_default_category(self): - for i in range(4): - text = 'multi %d' %i # Different text on each call - warnings.warn(text) - self.assertEqual(msg.message, text) - self.assertEqual(msg.category, 'UserWarning') + with test_support.catch_warning() as w: + for i in range(4): + text = 'multi %d' %i # Different text on each call + warnings.warn(text) + self.assertEqual(str(w.message), text) + self.assert_(w.category is UserWarning) def test_warn_specific_category(self): - text = 'None' - for category in [DeprecationWarning, FutureWarning, - PendingDeprecationWarning, RuntimeWarning, - SyntaxWarning, UserWarning, Warning]: - if category.__name__ in self.ignored: - text = 'filtered out' + category.__name__ - warnings.warn(text, category) - self.assertNotEqual(msg.message, text) - else: - text = 'unfiltered %s' % category.__name__ - warnings.warn(text, category) - self.assertEqual(msg.message, text) - self.assertEqual(msg.category, category.__name__) + with test_support.catch_warning() as w: + text = 'None' + for category in [DeprecationWarning, FutureWarning, + PendingDeprecationWarning, RuntimeWarning, + SyntaxWarning, UserWarning, Warning]: + if category.__name__ in self.ignored: + text = 'filtered out' + category.__name__ + warnings.warn(text, category) + self.assertNotEqual(w.message, text) + else: + text = 'unfiltered %s' % category.__name__ + warnings.warn(text, category) + self.assertEqual(str(w.message), text) + self.assert_(w.category is category) def test_filtering(self): + with test_support.catch_warning() as w: + warnings.filterwarnings("error", "", Warning, "", 0) + self.assertRaises(UserWarning, warnings.warn, 'convert to error') - warnings.filterwarnings("error", "", Warning, "", 0) - self.assertRaises(UserWarning, warnings.warn, 'convert to error') - - warnings.resetwarnings() - text = 'handle normally' - warnings.warn(text) - self.assertEqual(msg.message, text) - self.assertEqual(msg.category, 'UserWarning') + warnings.resetwarnings() + text = 'handle normally' + warnings.warn(text) + self.assertEqual(str(w.message), text) + self.assert_(w.category is UserWarning) - warnings.filterwarnings("ignore", "", Warning, "", 0) - text = 'filtered out' - warnings.warn(text) - self.assertNotEqual(msg.message, text) + warnings.filterwarnings("ignore", "", Warning, "", 0) + text = 'filtered out' + warnings.warn(text) + self.assertNotEqual(str(w.message), text) - warnings.resetwarnings() - warnings.filterwarnings("error", "hex*", Warning, "", 0) - self.assertRaises(UserWarning, warnings.warn, 'hex/oct') - text = 'nonmatching text' - warnings.warn(text) - self.assertEqual(msg.message, text) - self.assertEqual(msg.category, 'UserWarning') + warnings.resetwarnings() + warnings.filterwarnings("error", "hex*", Warning, "", 0) + self.assertRaises(UserWarning, warnings.warn, 'hex/oct') + text = 'nonmatching text' + warnings.warn(text) + self.assertEqual(str(w.message), text) + self.assert_(w.category is UserWarning) def test_options(self): # Uses the private _setoption() function to test the parsing # of command-line warning arguments - self.assertRaises(warnings._OptionError, - warnings._setoption, '1:2:3:4:5:6') - self.assertRaises(warnings._OptionError, - warnings._setoption, 'bogus::Warning') - self.assertRaises(warnings._OptionError, - warnings._setoption, 'ignore:2::4:-5') - warnings._setoption('error::Warning::0') - self.assertRaises(UserWarning, warnings.warn, 'convert to error') + with test_support.guard_warnings_filter(): + self.assertRaises(warnings._OptionError, + warnings._setoption, '1:2:3:4:5:6') + self.assertRaises(warnings._OptionError, + warnings._setoption, 'bogus::Warning') + self.assertRaises(warnings._OptionError, + warnings._setoption, 'ignore:2::4:-5') + warnings._setoption('error::Warning::0') + self.assertRaises(UserWarning, warnings.warn, 'convert to error') def test_filename(self): - warning_tests.inner("spam1") - self.assertEqual(msg.filename, "warning_tests.py") - warning_tests.outer("spam2") - self.assertEqual(msg.filename, "warning_tests.py") + with test_support.catch_warning() as w: + warning_tests.inner("spam1") + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + warning_tests.outer("spam2") + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") def test_stacklevel(self): # Test stacklevel argument # make sure all messages are different, so the warning won't be skipped - warning_tests.inner("spam3", stacklevel=1) - self.assertEqual(msg.filename, "warning_tests.py") - warning_tests.outer("spam4", stacklevel=1) - self.assertEqual(msg.filename, "warning_tests.py") - - warning_tests.inner("spam5", stacklevel=2) - self.assertEqual(msg.filename, "test_warnings.py") - warning_tests.outer("spam6", stacklevel=2) - self.assertEqual(msg.filename, "warning_tests.py") - - warning_tests.inner("spam7", stacklevel=9999) - self.assertEqual(msg.filename, "sys") + with test_support.catch_warning() as w: + warning_tests.inner("spam3", stacklevel=1) + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + warning_tests.outer("spam4", stacklevel=1) + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + + warning_tests.inner("spam5", stacklevel=2) + self.assertEqual(os.path.basename(w.filename), "test_warnings.py") + warning_tests.outer("spam6", stacklevel=2) + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + + warning_tests.inner("spam7", stacklevel=9999) + self.assertEqual(os.path.basename(w.filename), "sys") def test_main(verbose=None): diff --git a/Misc/NEWS b/Misc/NEWS index 8ef7acb..d8f51bc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -713,6 +713,9 @@ Tests - Fix bsddb test_basics.test06_Transactions to check the version number properly. +- test.test_support.catch_warning is a new context manager that can be used + to catch the warnings issued by the warning framework. + Tools ----- -- cgit v0.12