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.
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 @@
 
 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(str(w.message), text)
+            self.assert_(w.category is UserWarning)
 
-        warnings.resetwarnings()
-        text = 'handle normally'
-        warnings.warn(text)
-        self.assertEqual(msg.message, text)
-        self.assertEqual(msg.category, 'UserWarning')
+            warnings.filterwarnings("ignore", "", Warning, "", 0)
+            text = 'filtered out'
+            warnings.warn(text)
+            self.assertNotEqual(str(w.message), text)
 
-        warnings.filterwarnings("ignore", "", Warning, "", 0)
-        text = 'filtered out'
-        warnings.warn(text)
-        self.assertNotEqual(msg.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")
+        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(msg.filename, "test_warnings.py")
-        warning_tests.outer("spam6", stacklevel=2)
-        self.assertEqual(msg.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(msg.filename, "sys")
+            warning_tests.inner("spam7", stacklevel=9999)
+            self.assertEqual(os.path.basename(w.filename), "sys")
 
 
 def test_main(verbose=None):