Commit e477318e authored by Walter Dörwald's avatar Walter Dörwald

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.
parent 2ee7bc0d
...@@ -4,7 +4,7 @@ from _testcapi import test_structmembersType, \ ...@@ -4,7 +4,7 @@ from _testcapi import test_structmembersType, \
INT_MAX, INT_MIN, UINT_MAX, \ INT_MAX, INT_MIN, UINT_MAX, \
LONG_MAX, LONG_MIN, ULONG_MAX LONG_MAX, LONG_MIN, ULONG_MAX
import warnings, exceptions, unittest, test.test_warnings import warnings, exceptions, unittest
from test import test_support from test import test_support
ts=test_structmembersType(1,2,3,4,5,6,7,8,9.99999,10.1010101010) ts=test_structmembersType(1,2,3,4,5,6,7,8,9.99999,10.1010101010)
...@@ -39,34 +39,39 @@ class ReadWriteTests(unittest.TestCase): ...@@ -39,34 +39,39 @@ class ReadWriteTests(unittest.TestCase):
ts.T_ULONG=ULONG_MAX ts.T_ULONG=ULONG_MAX
self.assertEquals(ts.T_ULONG, ULONG_MAX) self.assertEquals(ts.T_ULONG, ULONG_MAX)
class TestWarnings(test.test_warnings.CatchWarningTest): class TestWarnings(unittest.TestCase):
def has_warned(self): def has_warned(self, w):
self.assertEqual(test.test_warnings.msg.category, self.assert_(w.category is RuntimeWarning)
exceptions.RuntimeWarning.__name__)
def test_byte_max(self): def test_byte_max(self):
with test_support.catch_warning() as w:
ts.T_BYTE=CHAR_MAX+1 ts.T_BYTE=CHAR_MAX+1
self.has_warned() self.has_warned(w)
def test_byte_min(self): def test_byte_min(self):
with test_support.catch_warning() as w:
ts.T_BYTE=CHAR_MIN-1 ts.T_BYTE=CHAR_MIN-1
self.has_warned() self.has_warned(w)
def test_ubyte_max(self): def test_ubyte_max(self):
with test_support.catch_warning() as w:
ts.T_UBYTE=UCHAR_MAX+1 ts.T_UBYTE=UCHAR_MAX+1
self.has_warned() self.has_warned(w)
def test_short_max(self): def test_short_max(self):
with test_support.catch_warning() as w:
ts.T_SHORT=SHRT_MAX+1 ts.T_SHORT=SHRT_MAX+1
self.has_warned() self.has_warned(w)
def test_short_min(self): def test_short_min(self):
with test_support.catch_warning() as w:
ts.T_SHORT=SHRT_MIN-1 ts.T_SHORT=SHRT_MIN-1
self.has_warned() self.has_warned(w)
def test_ushort_max(self): def test_ushort_max(self):
with test_support.catch_warning() as w:
ts.T_USHORT=USHRT_MAX+1 ts.T_USHORT=USHRT_MAX+1
self.has_warned() self.has_warned(w)
......
...@@ -282,6 +282,42 @@ def guard_warnings_filter(): ...@@ -282,6 +282,42 @@ def guard_warnings_filter():
finally: finally:
warnings.filters = original_filters 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 EnvironmentVarGuard(object):
"""Class to help protect the environment variable properly. Can be used as """Class to help protect the environment variable properly. Can be used as
......
...@@ -5,50 +5,21 @@ from test import test_support ...@@ -5,50 +5,21 @@ from test import test_support
import warning_tests import warning_tests
# The warnings module isn't easily tested, because it relies on module class TestModule(unittest.TestCase):
# 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)
def setUp(self): def setUp(self):
global msg self.ignored = [w[2].__name__ for w in warnings.filters
msg = WarningMessage()
self._filters = warnings.filters[:]
self._showwarning = warnings.showwarning
warnings.showwarning = showwarning
self.ignored = [w[2].__name__ for w in self._filters
if w[0]=='ignore' and w[1] is None and w[3] is None] 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): def test_warn_default_category(self):
with test_support.catch_warning() as w:
for i in range(4): for i in range(4):
text = 'multi %d' %i # Different text on each call text = 'multi %d' %i # Different text on each call
warnings.warn(text) warnings.warn(text)
self.assertEqual(msg.message, text) self.assertEqual(str(w.message), text)
self.assertEqual(msg.category, 'UserWarning') self.assert_(w.category is UserWarning)
def test_warn_specific_category(self): def test_warn_specific_category(self):
with test_support.catch_warning() as w:
text = 'None' text = 'None'
for category in [DeprecationWarning, FutureWarning, for category in [DeprecationWarning, FutureWarning,
PendingDeprecationWarning, RuntimeWarning, PendingDeprecationWarning, RuntimeWarning,
...@@ -56,40 +27,41 @@ class TestModule(CatchWarningTest): ...@@ -56,40 +27,41 @@ class TestModule(CatchWarningTest):
if category.__name__ in self.ignored: if category.__name__ in self.ignored:
text = 'filtered out' + category.__name__ text = 'filtered out' + category.__name__
warnings.warn(text, category) warnings.warn(text, category)
self.assertNotEqual(msg.message, text) self.assertNotEqual(w.message, text)
else: else:
text = 'unfiltered %s' % category.__name__ text = 'unfiltered %s' % category.__name__
warnings.warn(text, category) warnings.warn(text, category)
self.assertEqual(msg.message, text) self.assertEqual(str(w.message), text)
self.assertEqual(msg.category, category.__name__) self.assert_(w.category is category)
def test_filtering(self): def test_filtering(self):
with test_support.catch_warning() as w:
warnings.filterwarnings("error", "", Warning, "", 0) warnings.filterwarnings("error", "", Warning, "", 0)
self.assertRaises(UserWarning, warnings.warn, 'convert to error') self.assertRaises(UserWarning, warnings.warn, 'convert to error')
warnings.resetwarnings() warnings.resetwarnings()
text = 'handle normally' text = 'handle normally'
warnings.warn(text) warnings.warn(text)
self.assertEqual(msg.message, text) self.assertEqual(str(w.message), text)
self.assertEqual(msg.category, 'UserWarning') self.assert_(w.category is UserWarning)
warnings.filterwarnings("ignore", "", Warning, "", 0) warnings.filterwarnings("ignore", "", Warning, "", 0)
text = 'filtered out' text = 'filtered out'
warnings.warn(text) warnings.warn(text)
self.assertNotEqual(msg.message, text) self.assertNotEqual(str(w.message), text)
warnings.resetwarnings() warnings.resetwarnings()
warnings.filterwarnings("error", "hex*", Warning, "", 0) warnings.filterwarnings("error", "hex*", Warning, "", 0)
self.assertRaises(UserWarning, warnings.warn, 'hex/oct') self.assertRaises(UserWarning, warnings.warn, 'hex/oct')
text = 'nonmatching text' text = 'nonmatching text'
warnings.warn(text) warnings.warn(text)
self.assertEqual(msg.message, text) self.assertEqual(str(w.message), text)
self.assertEqual(msg.category, 'UserWarning') self.assert_(w.category is UserWarning)
def test_options(self): def test_options(self):
# Uses the private _setoption() function to test the parsing # Uses the private _setoption() function to test the parsing
# of command-line warning arguments # of command-line warning arguments
with test_support.guard_warnings_filter():
self.assertRaises(warnings._OptionError, self.assertRaises(warnings._OptionError,
warnings._setoption, '1:2:3:4:5:6') warnings._setoption, '1:2:3:4:5:6')
self.assertRaises(warnings._OptionError, self.assertRaises(warnings._OptionError,
...@@ -100,26 +72,28 @@ class TestModule(CatchWarningTest): ...@@ -100,26 +72,28 @@ class TestModule(CatchWarningTest):
self.assertRaises(UserWarning, warnings.warn, 'convert to error') self.assertRaises(UserWarning, warnings.warn, 'convert to error')
def test_filename(self): def test_filename(self):
with test_support.catch_warning() as w:
warning_tests.inner("spam1") warning_tests.inner("spam1")
self.assertEqual(msg.filename, "warning_tests.py") self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
warning_tests.outer("spam2") warning_tests.outer("spam2")
self.assertEqual(msg.filename, "warning_tests.py") self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
def test_stacklevel(self): def test_stacklevel(self):
# Test stacklevel argument # Test stacklevel argument
# make sure all messages are different, so the warning won't be skipped # make sure all messages are different, so the warning won't be skipped
with test_support.catch_warning() as w:
warning_tests.inner("spam3", stacklevel=1) warning_tests.inner("spam3", stacklevel=1)
self.assertEqual(msg.filename, "warning_tests.py") self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
warning_tests.outer("spam4", stacklevel=1) warning_tests.outer("spam4", stacklevel=1)
self.assertEqual(msg.filename, "warning_tests.py") self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
warning_tests.inner("spam5", stacklevel=2) warning_tests.inner("spam5", stacklevel=2)
self.assertEqual(msg.filename, "test_warnings.py") self.assertEqual(os.path.basename(w.filename), "test_warnings.py")
warning_tests.outer("spam6", stacklevel=2) warning_tests.outer("spam6", stacklevel=2)
self.assertEqual(msg.filename, "warning_tests.py") self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
warning_tests.inner("spam7", stacklevel=9999) warning_tests.inner("spam7", stacklevel=9999)
self.assertEqual(msg.filename, "sys") self.assertEqual(os.path.basename(w.filename), "sys")
def test_main(verbose=None): def test_main(verbose=None):
......
...@@ -713,6 +713,9 @@ Tests ...@@ -713,6 +713,9 @@ Tests
- Fix bsddb test_basics.test06_Transactions to check the version - Fix bsddb test_basics.test06_Transactions to check the version
number properly. 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 Tools
----- -----
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment