]> granicus.if.org Git - python/commitdiff
warnings.catch_warnings() now returns a list or None instead of the custom
authorBrett Cannon <bcannon@gmail.com>
Tue, 9 Sep 2008 00:49:16 +0000 (00:49 +0000)
committerBrett Cannon <bcannon@gmail.com>
Tue, 9 Sep 2008 00:49:16 +0000 (00:49 +0000)
WarningsRecorder object. This makes the API simpler to use as no special object
must be learned.

Closes issue 3781.
Review by Benjamin Peterson.

24 files changed:
Doc/library/warnings.rst
Lib/asynchat.py
Lib/bsddb/test/test_early_close.py
Lib/mimetools.py
Lib/test/test___all__.py
Lib/test/test_exceptions.py
Lib/test/test_hmac.py
Lib/test/test_import.py
Lib/test/test_macostools.py
Lib/test/test_pep352.py
Lib/test/test_py3kwarn.py
Lib/test/test_random.py
Lib/test/test_re.py
Lib/test/test_struct.py
Lib/test/test_structmembers.py
Lib/test/test_sundry.py
Lib/test/test_support.py
Lib/test/test_symtable.py
Lib/test/test_urllib.py
Lib/test/test_urllibnet.py
Lib/test/test_userstring.py
Lib/test/test_warnings.py
Lib/warnings.py
Misc/NEWS

index 68bc26102c56515c41dbd3d134622d5a5e528479..e9d018280f5e914a0880a96e3dbada910ef232ee 100644 (file)
@@ -158,6 +158,67 @@ ImportWarning can also be enabled explicitly in Python code using::
    warnings.simplefilter('default', ImportWarning)
 
 
+.. _warning-suppress:
+
+Temporarily Suppressing Warnings
+--------------------------------
+
+If you are using code that you know will raise a warning, such some deprecated
+function, but do not want to see the warning, then suppress the warning using
+the :class:`catch_warnings` context manager::
+
+    import warnings
+
+    def fxn():
+        warnings.warn("deprecated", DeprecationWarning)
+
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore")
+        fxn()
+
+While within the context manager all warnings will simply be ignored. This
+allows you to use known-deprecated code without having to see the warning while
+not suppressing the warning for other code that might not be aware of its use
+of deprecated code.
+
+
+.. _warning-testing:
+
+Testing Warnings
+----------------
+
+To test warnings raised by code, use the :class:`catch_warnings` context
+manager. With it you can temporarily mutate the warnings filter to facilitate
+your testing. For instance, do the following to capture all raised warnings to
+check::
+
+    import warnings
+
+    def fxn():
+        warnings.warn("deprecated", DeprecationWarning)
+
+    with warnings.catch_warnings(record=True) as w:
+        # Cause all warnings to always be triggered.
+        warnings.simplefilter("always")
+        # Trigger a warning.
+        fxn()
+        # Verify some things
+        assert len(w) == 1
+        assert isinstance(w[-1].category, DeprecationWarning)
+        assert "deprecated" in str(w[-1].message)
+
+One can also cause all warnings to be exceptions by using ``error`` instead of
+``always``. One thing to be aware of is that if a warning has already been
+raised because of a ``once``/``default`` rule, then no matter what filters are
+set the warning will not be seen again unless the warnings registry related to
+the warning has been cleared.
+
+Once the context manager exits, the warnings filter is restored to its state
+when the context was entered. This prevents tests from changing the warnings
+filter in unexpected ways between tests and leading to indeterminate test
+results.
+
+
 .. _warning-functions:
 
 Available Functions
@@ -264,31 +325,22 @@ Available Functions
    and calls to :func:`simplefilter`.
 
 
-Available Classes
------------------
-
-.. class:: catch_warnings([\*, record=False[, module=None]])
-
-    A context manager that guards the warnings filter from being permanently
-    mutated. The manager returns an instance of :class:`WarningsRecorder`. The 
-    *record* argument specifies whether warnings that would typically be
-    handled by :func:`showwarning` should instead be recorded by the
-    :class:`WarningsRecorder` instance. This argument is typically set when
-    testing for expected warnings behavior. The *module* argument may be a
-    module object that is to be used instead of the :mod:`warnings` module.
-    This argument should only be set when testing the :mod:`warnings` module 
-    or some similar use-case.
+Available Context Managers
+--------------------------
 
-    Typical usage of the context manager is like so::
+.. class:: catch_warnings([\*, record=False, module=None])
 
-        def fxn():
-            warn("fxn is deprecated", DeprecationWarning)
-            return "spam spam bacon spam"
+    A context manager that copies and, upon exit, restores the warnings filter.
+    If the *record* argument is False (the default) the context manager returns
+    :class:`None`. If *record* is true, a list is returned that is populated
+    with objects as seen by a custom :func:`showwarning` function (which also
+    suppresses output to ``sys.stdout``). Each object has attributes with the
+    same names as the arguments to :func:`showwarning`.
 
-        # The function 'fxn' is known to raise a DeprecationWarning.
-        with catch_warnings() as w:
-            warnings.filterwarning('ignore', 'fxn is deprecated', DeprecationWarning)
-            fxn()  # DeprecationWarning is temporarily suppressed.
+    The *module* argument takes a module that will be used instead of the
+    module returned when you import :mod:`warnings` whose filter will be
+    protected. This arguments exists primarily for testing the :mod:`warnings`
+    module itself.
 
     .. note::
 
@@ -297,19 +349,3 @@ Available Classes
 
     .. versionadded:: 2.6
 
-
-.. class:: WarningsRecorder()
-
-    A subclass of :class:`list` that stores all warnings passed to
-    :func:`showwarning` when returned by a :class:`catch_warnings` context
-    manager created with its *record* argument set to ``True``. Each recorded
-    warning is represented by an object whose attributes correspond to the
-    arguments to :func:`showwarning`. As a convenience, a
-    :class:`WarningsRecorder` instance has the attributes of the last
-    recorded warning set on the :class:`WarningsRecorder` instance as well.
-
-    .. method:: reset()
-
-        Delete all recorded warnings.
-
-    .. versionadded:: 2.6
index a97de93f27053edc6a95610872a36552a205b50a..911833d58ced7a779cb8f93aaec4d42556820023 100644 (file)
@@ -50,7 +50,6 @@ import socket
 import asyncore
 from collections import deque
 from sys import py3kwarning
-from test.test_support import catch_warning
 from warnings import filterwarnings, catch_warnings
 
 class async_chat (asyncore.dispatcher):
index 3d3396cb5b6f6129e1060606e3d1671258256fb1..cc69e47a316170d6a276f56d8a85ca668a8e2910 100644 (file)
@@ -168,9 +168,9 @@ class DBEnvClosedEarlyCrash(unittest.TestCase):
         self.assertEquals(("XXX", "yyy"), c1.first())
         import warnings
         # Not interested in warnings about implicit close.
-        warnings.simplefilter("ignore")
-        txn.commit()
-        warnings.resetwarnings()
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore")
+            txn.commit()
         self.assertRaises(db.DBCursorClosedError, c2.first)
 
     if db.version() > (4,3,0) :
index fc5a2a5f18613a3c1d1c057d9e4e4f965d12bbc7..71ca8f8593f2b64d08ddeb02a38dee1fef827f1c 100644 (file)
@@ -5,7 +5,7 @@ import os
 import sys
 import tempfile
 from warnings import filterwarnings, catch_warnings
-with catch_warnings(record=False):
+with catch_warnings():
     if sys.py3kwarning:
         filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
     import rfc822
index 9bd00836da282416378d47180a4c03719df3da8c..0a8c5d652bf045bb148b3018f8878f0f173551fc 100644 (file)
@@ -1,5 +1,5 @@
 import unittest
-from test.test_support import run_unittest, catch_warning
+from test.test_support import run_unittest
 import sys
 import warnings
 
@@ -9,7 +9,7 @@ class AllTest(unittest.TestCase):
 
     def check_all(self, modname):
         names = {}
-        with catch_warning():
+        with warnings.catch_warnings():
             warnings.filterwarnings("ignore", ".* (module|package)",
                                     DeprecationWarning)
             try:
index 0576b6249f27efee45207a472b2b05955acbf85d..06a23781c5ddd097fbf67fbe22f12fde54dc156e 100644 (file)
@@ -4,9 +4,9 @@ import os
 import sys
 import unittest
 import pickle, cPickle
+import warnings
 
-from test.test_support import (TESTFN, unlink, run_unittest,
-                                catch_warning, captured_output)
+from test.test_support import TESTFN, unlink, run_unittest, captured_output
 from test.test_pep352 import ignore_message_warning
 
 # XXX This is not really enough, each *operation* should be tested!
@@ -274,7 +274,7 @@ class ExceptionTests(unittest.TestCase):
         except NameError:
             pass
 
-        with catch_warning():
+        with warnings.catch_warnings():
             ignore_message_warning()
             for exc, args, expected in exceptionList:
                 try:
index c57ac7f61e5a6a83e8f9febed48bc0ad13897acf..d97583fb43266fa40ed42122d2684b2f1768c10b 100644 (file)
@@ -211,7 +211,7 @@ class TestVectorsTestCase(unittest.TestCase):
             def digest(self):
                 return self._x.digest()
 
-        with test_support.catch_warning():
+        with warnings.catch_warnings():
             warnings.simplefilter('error', RuntimeWarning)
             try:
                 hmac.HMAC('a', 'b', digestmod=MockCrazyHash)
index ed9c7af40619e65f5f2865eae19cad8458ccda7c..644a473b12b88e4010798b985c72ab1ae4293bea 100644 (file)
@@ -5,7 +5,7 @@ import shutil
 import sys
 import py_compile
 import warnings
-from test.test_support import unlink, TESTFN, unload, run_unittest, catch_warning
+from test.test_support import unlink, TESTFN, unload, run_unittest
 
 
 def remove_files(name):
@@ -215,7 +215,7 @@ class ImportTest(unittest.TestCase):
         self.assert_(y is test.test_support, y.__name__)
 
     def test_import_initless_directory_warning(self):
-        with catch_warning():
+        with warnings.catch_warnings():
             # Just a random non-package directory we always expect to be
             # somewhere in sys.path...
             warnings.simplefilter('error', ImportWarning)
@@ -279,17 +279,17 @@ class RelativeImport(unittest.TestCase):
         check_relative()
         # Check relative fails with only __package__ wrong
         ns = dict(__package__='foo', __name__='test.notarealmodule')
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             check_absolute()
-            self.assert_('foo' in str(w.message))
-            self.assertEqual(w.category, RuntimeWarning)
+            self.assert_('foo' in str(w[-1].message))
+            self.assertEqual(w[-1].category, RuntimeWarning)
         self.assertRaises(SystemError, check_relative)
         # Check relative fails with __package__ and __name__ wrong
         ns = dict(__package__='foo', __name__='notarealpkg.notarealmodule')
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             check_absolute()
-            self.assert_('foo' in str(w.message))
-            self.assertEqual(w.category, RuntimeWarning)
+            self.assert_('foo' in str(w[-1].message))
+            self.assertEqual(w[-1].category, RuntimeWarning)
         self.assertRaises(SystemError, check_relative)
         # Check both fail with package set to a non-string
         ns = dict(__package__=object())
index da982d0bacd70929deadaaa9d9dd8acb94bcec2a..5c83d28c47cc7ca36d4a9aa73e6d80527bcd34be 100644 (file)
@@ -52,7 +52,7 @@ class TestMacostools(unittest.TestCase):
     def test_touched(self):
         # This really only tests that nothing unforeseen happens.
         import warnings
-        with test_support.catch_warning():
+        with warnings.catch_warnings():
             warnings.filterwarnings('ignore', 'macostools.touched*',
                                     DeprecationWarning)
             macostools.touched(test_support.TESTFN)
index 1867b9ed6339222084be70f3b6ffca1340943bdd..e33552809f456144cce4ee4d999d9464f3e8d88c 100644 (file)
@@ -2,7 +2,7 @@ import unittest
 import __builtin__
 import exceptions
 import warnings
-from test.test_support import run_unittest, catch_warning
+from test.test_support import run_unittest
 import os
 from platform import system as platform_system
 
@@ -22,7 +22,7 @@ class ExceptionClassTests(unittest.TestCase):
         self.failUnless(issubclass(Exception, object))
 
     def verify_instance_interface(self, ins):
-        with catch_warning():
+        with warnings.catch_warnings():
             ignore_message_warning()
             for attr in ("args", "message", "__str__", "__repr__",
                             "__getitem__"):
@@ -95,7 +95,7 @@ class ExceptionClassTests(unittest.TestCase):
         # Make sure interface works properly when given a single argument
         arg = "spam"
         exc = Exception(arg)
-        with catch_warning():
+        with warnings.catch_warnings():
             ignore_message_warning()
             results = ([len(exc.args), 1], [exc.args[0], arg],
                     [exc.message, arg],
@@ -109,7 +109,7 @@ class ExceptionClassTests(unittest.TestCase):
         arg_count = 3
         args = tuple(range(arg_count))
         exc = Exception(*args)
-        with catch_warning():
+        with warnings.catch_warnings():
             ignore_message_warning()
             results = ([len(exc.args), arg_count], [exc.args, args],
                     [exc.message, ''], [str(exc), str(args)],
@@ -121,7 +121,7 @@ class ExceptionClassTests(unittest.TestCase):
     def test_interface_no_arg(self):
         # Make sure that with no args that interface is correct
         exc = Exception()
-        with catch_warning():
+        with warnings.catch_warnings():
             ignore_message_warning()
             results = ([len(exc.args), 0], [exc.args, tuple()],
                     [exc.message, ''],
@@ -132,7 +132,7 @@ class ExceptionClassTests(unittest.TestCase):
 
     def test_message_deprecation(self):
         # As of Python 2.6, BaseException.message is deprecated.
-        with catch_warning():
+        with warnings.catch_warnings():
             warnings.resetwarnings()
             warnings.filterwarnings('error')
 
@@ -219,7 +219,7 @@ class UsageTests(unittest.TestCase):
 
     def test_catch_string(self):
         # Catching a string should trigger a DeprecationWarning.
-        with catch_warning():
+        with warnings.catch_warnings():
             warnings.resetwarnings()
             warnings.filterwarnings("error")
             str_exc = "spam"
index 780de740676e5e845c93599a36716f730cc9f0d2..aa1ecbb588bebd80b0fba62bbd626c113e59faed 100644 (file)
@@ -1,7 +1,6 @@
 import unittest
 import sys
-from test.test_support import (catch_warning, CleanImport,
-                               TestSkipped, run_unittest)
+from test.test_support import CleanImport, TestSkipped, run_unittest
 import warnings
 
 from contextlib import nested
@@ -13,11 +12,11 @@ if not sys.py3kwarning:
 class TestPy3KWarnings(unittest.TestCase):
 
     def assertWarning(self, _, warning, expected_message):
-        self.assertEqual(str(warning.message), expected_message)
+        self.assertEqual(str(warning[-1].message), expected_message)
 
     def test_backquote(self):
         expected = 'backquote not supported in 3.x; use repr()'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             exec "`2`" in {}
         self.assertWarning(None, w, expected)
 
@@ -28,71 +27,55 @@ class TestPy3KWarnings(unittest.TestCase):
             exec expr in {'f' : f}
 
         expected = "assignment to True or False is forbidden in 3.x"
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             safe_exec("True = False")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("False = True")
             self.assertWarning(None, w, expected)
-            w.reset()
             try:
                 safe_exec("obj.False = True")
             except NameError: pass
             self.assertWarning(None, w, expected)
-            w.reset()
             try:
                 safe_exec("obj.True = False")
             except NameError: pass
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("def False(): pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("def True(): pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("class False: pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("class True: pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("def f(True=43): pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("def f(False=None): pass")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("f(False=True)")
             self.assertWarning(None, w, expected)
-            w.reset()
             safe_exec("f(True=1)")
             self.assertWarning(None, w, expected)
 
 
     def test_type_inequality_comparisons(self):
         expected = 'type inequality comparisons not supported in 3.x'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(int < str, w, expected)
-            w.reset()
             self.assertWarning(type < object, w, expected)
 
     def test_object_inequality_comparisons(self):
         expected = 'comparing unequal types not supported in 3.x'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(str < [], w, expected)
-            w.reset()
             self.assertWarning(object() < (1, 2), w, expected)
 
     def test_dict_inequality_comparisons(self):
         expected = 'dict inequality comparisons not supported in 3.x'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning({} < {2:3}, w, expected)
-            w.reset()
             self.assertWarning({} <= {}, w, expected)
-            w.reset()
             self.assertWarning({} > {2:3}, w, expected)
-            w.reset()
             self.assertWarning({2:3} >= {}, w, expected)
 
     def test_cell_inequality_comparisons(self):
@@ -103,9 +86,8 @@ class TestPy3KWarnings(unittest.TestCase):
             return g
         cell0, = f(0).func_closure
         cell1, = f(1).func_closure
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(cell0 == cell1, w, expected)
-            w.reset()
             self.assertWarning(cell0 < cell1, w, expected)
 
     def test_code_inequality_comparisons(self):
@@ -114,13 +96,10 @@ class TestPy3KWarnings(unittest.TestCase):
             pass
         def g(x):
             pass
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(f.func_code < g.func_code, w, expected)
-            w.reset()
             self.assertWarning(f.func_code <= g.func_code, w, expected)
-            w.reset()
             self.assertWarning(f.func_code >= g.func_code, w, expected)
-            w.reset()
             self.assertWarning(f.func_code > g.func_code, w, expected)
 
     def test_builtin_function_or_method_comparisons(self):
@@ -128,13 +107,10 @@ class TestPy3KWarnings(unittest.TestCase):
                     'inequality comparisons not supported in 3.x')
         func = eval
         meth = {}.get
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(func < meth, w, expected)
-            w.reset()
             self.assertWarning(func > meth, w, expected)
-            w.reset()
             self.assertWarning(meth <= func, w, expected)
-            w.reset()
             self.assertWarning(meth >= func, w, expected)
 
     def test_sort_cmp_arg(self):
@@ -142,18 +118,15 @@ class TestPy3KWarnings(unittest.TestCase):
         lst = range(5)
         cmp = lambda x,y: -1
 
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(lst.sort(cmp=cmp), w, expected)
-            w.reset()
             self.assertWarning(sorted(lst, cmp=cmp), w, expected)
-            w.reset()
             self.assertWarning(lst.sort(cmp), w, expected)
-            w.reset()
             self.assertWarning(sorted(lst, cmp), w, expected)
 
     def test_sys_exc_clear(self):
         expected = 'sys.exc_clear() not supported in 3.x; use except clauses'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(sys.exc_clear(), w, expected)
 
     def test_methods_members(self):
@@ -162,17 +135,17 @@ class TestPy3KWarnings(unittest.TestCase):
             __methods__ = ['a']
             __members__ = ['b']
         c = C()
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(dir(c), w, expected)
 
     def test_softspace(self):
         expected = 'file.softspace not supported in 3.x'
         with file(__file__) as f:
-            with catch_warning() as w:
+            with warnings.catch_warnings(record=True) as w:
                 self.assertWarning(f.softspace, w, expected)
             def set():
                 f.softspace = 0
-            with catch_warning() as w:
+            with warnings.catch_warnings(record=True) as w:
                 self.assertWarning(set(), w, expected)
 
     def test_slice_methods(self):
@@ -188,60 +161,59 @@ class TestPy3KWarnings(unittest.TestCase):
         expected = "in 3.x, __{0}slice__ has been removed; use __{0}item__"
 
         for obj in (Spam(), Egg()):
-            with catch_warning() as w:
+            with warnings.catch_warnings(record=True) as w:
                 self.assertWarning(obj[1:2], w, expected.format('get'))
-                w.reset()
                 del obj[3:4]
                 self.assertWarning(None, w, expected.format('del'))
-                w.reset()
                 obj[4:5] = "eggs"
                 self.assertWarning(None, w, expected.format('set'))
 
     def test_tuple_parameter_unpacking(self):
         expected = "tuple parameter unpacking has been removed in 3.x"
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             exec "def f((a, b)): pass"
             self.assertWarning(None, w, expected)
 
     def test_buffer(self):
         expected = 'buffer() not supported in 3.x'
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             self.assertWarning(buffer('a'), w, expected)
 
     def test_file_xreadlines(self):
         expected = ("f.xreadlines() not supported in 3.x, "
                     "try 'for line in f' instead")
         with file(__file__) as f:
-            with catch_warning() as w:
+            with warnings.catch_warnings(record=True) as w:
                 self.assertWarning(f.xreadlines(), w, expected)
 
     def test_hash_inheritance(self):
-        with catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             # With object as the base class
             class WarnOnlyCmp(object):
                 def __cmp__(self, other): pass
             self.assertEqual(len(w), 1)
             self.assertWarning(None, w,
                  "Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class WarnOnlyEq(object):
                 def __eq__(self, other): pass
             self.assertEqual(len(w), 1)
             self.assertWarning(None, w,
                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class WarnCmpAndEq(object):
                 def __cmp__(self, other): pass
                 def __eq__(self, other): pass
             self.assertEqual(len(w), 2)
-            self.assertWarning(None, w[-2],
+            self.assertWarning(None, w[:1],
                  "Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
             self.assertWarning(None, w,
                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class NoWarningOnlyHash(object):
                 def __hash__(self): pass
             self.assertEqual(len(w), 0)
+            del w[:]
             # With an intermediate class in the heirarchy
             class DefinesAllThree(object):
                 def __cmp__(self, other): pass
@@ -252,22 +224,22 @@ class TestPy3KWarnings(unittest.TestCase):
             self.assertEqual(len(w), 1)
             self.assertWarning(None, w,
                  "Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class WarnOnlyEq(DefinesAllThree):
                 def __eq__(self, other): pass
             self.assertEqual(len(w), 1)
             self.assertWarning(None, w,
                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class WarnCmpAndEq(DefinesAllThree):
                 def __cmp__(self, other): pass
                 def __eq__(self, other): pass
             self.assertEqual(len(w), 2)
-            self.assertWarning(None, w[-2],
+            self.assertWarning(None, w[:1],
                  "Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
             self.assertWarning(None, w,
                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
-            w.reset()
+            del w[:]
             class NoWarningOnlyHash(DefinesAllThree):
                 def __hash__(self): pass
             self.assertEqual(len(w), 0)
@@ -310,7 +282,7 @@ class TestStdlibRemovals(unittest.TestCase):
     def check_removal(self, module_name, optional=False):
         """Make sure the specified module, when imported, raises a
         DeprecationWarning and specifies itself in the message."""
-        with nested(CleanImport(module_name), catch_warning(record=False)):
+        with nested(CleanImport(module_name), warnings.catch_warnings()):
             warnings.filterwarnings("error", ".+ removed",
                                     DeprecationWarning, __name__)
             try:
@@ -348,36 +320,36 @@ class TestStdlibRemovals(unittest.TestCase):
         def dumbo(where, names, args): pass
         for path_mod in ("ntpath", "macpath", "os2emxpath", "posixpath"):
             mod = __import__(path_mod)
-            with catch_warning() as w:
+            with warnings.catch_warnings(record=True) as w:
                 mod.walk("crashers", dumbo, None)
-            self.assertEquals(str(w.message), msg)
+            self.assertEquals(str(w[-1].message), msg)
 
     def test_commands_members(self):
         import commands
         members = {"mk2arg" : 2, "mkarg" : 1, "getstatus" : 1}
         for name, arg_count in members.items():
-            with catch_warning(record=False):
+            with warnings.catch_warnings():
                 warnings.filterwarnings("error")
                 func = getattr(commands, name)
                 self.assertRaises(DeprecationWarning, func, *([None]*arg_count))
 
     def test_reduce_move(self):
         from operator import add
-        with catch_warning(record=False):
+        with warnings.catch_warnings():
             warnings.filterwarnings("error", "reduce")
             self.assertRaises(DeprecationWarning, reduce, add, range(10))
 
     def test_mutablestring_removal(self):
         # UserString.MutableString has been removed in 3.0.
         import UserString
-        with catch_warning(record=False):
+        with warnings.catch_warnings():
             warnings.filterwarnings("error", ".*MutableString",
                                     DeprecationWarning)
             self.assertRaises(DeprecationWarning, UserString.MutableString)
 
 
 def test_main():
-    with catch_warning():
+    with warnings.catch_warnings():
         warnings.simplefilter("always")
         run_unittest(TestPy3KWarnings,
                      TestStdlibRemovals)
index 4d570d0728804d5d4f1b1890dc83977dcf88487a..d82d391fe3e7dbefd21507efd8e6cef5b6fc7ef1 100644 (file)
@@ -191,7 +191,7 @@ class WichmannHill_TestBasicOps(TestBasicOps):
 
     def test_bigrand(self):
         # Verify warnings are raised when randrange is too large for random()
-        with test_support.catch_warning():
+        with warnings.catch_warnings():
             warnings.filterwarnings("error", "Underlying random")
             self.assertRaises(UserWarning, self.gen.randrange, 2**60)
 
index 1da3205e7293e4bcd861bae82e7d2d7b6be21255..70bd88623d6000918960456163f4a3619396f00a 100644 (file)
@@ -1,7 +1,7 @@
 import sys
 sys.path = ['.'] + sys.path
 
-from test.test_support import verbose, run_unittest, catch_warning
+from test.test_support import verbose, run_unittest
 import re
 from re import Scanner
 import sys, os, traceback
@@ -447,7 +447,7 @@ class ReTests(unittest.TestCase):
         self.pickle_test(cPickle)
         # old pickles expect the _compile() reconstructor in sre module
         import warnings
-        with catch_warning():
+        with warnings.catch_warnings():
             warnings.filterwarnings("ignore", "The sre module is deprecated",
                                     DeprecationWarning)
             from sre import _compile
index ec4a2dbc43eac81007827b892164be6bc8e73056..232bffc275ba74cba95b45b40c7ae3c02980a0fc 100644 (file)
@@ -4,7 +4,7 @@ import struct
 import warnings
 
 from functools import wraps
-from test.test_support import TestFailed, verbose, run_unittest, catch_warning
+from test.test_support import TestFailed, verbose, run_unittest
 
 import sys
 ISBIGENDIAN = sys.byteorder == "big"
@@ -34,7 +34,7 @@ def bigendian_to_native(value):
 def with_warning_restore(func):
     @wraps(func)
     def decorator(*args, **kw):
-        with catch_warning():
+        with warnings.catch_warnings():
             # We need this function to warn every time, so stick an
             # unqualifed 'always' at the head of the filter list
             warnings.simplefilter("always")
index 6c1a947fe3f1959ed4fd492fe2bc0b4b0d7a4eaf..e0e7e5613001c85b70f723765f2a4f608aa03d59 100644 (file)
@@ -66,35 +66,35 @@ class ReadWriteTests(unittest.TestCase):
 
 class TestWarnings(unittest.TestCase):
     def has_warned(self, w):
-        self.assertEqual(w.category, RuntimeWarning)
+        self.assertEqual(w[-1].category, RuntimeWarning)
 
     def test_byte_max(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_BYTE = CHAR_MAX+1
             self.has_warned(w)
 
     def test_byte_min(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_BYTE = CHAR_MIN-1
             self.has_warned(w)
 
     def test_ubyte_max(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_UBYTE = UCHAR_MAX+1
             self.has_warned(w)
 
     def test_short_max(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_SHORT = SHRT_MAX+1
             self.has_warned(w)
 
     def test_short_min(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_SHORT = SHRT_MIN-1
             self.has_warned(w)
 
     def test_ushort_max(self):
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             ts.T_USHORT = USHRT_MAX+1
             self.has_warned(w)
 
index 404a405de5ec87bf0d920ed0f510aa79b05216a3..49ec12c944ac0b4d0ea74bb2a733ea6e2da9f42e 100644 (file)
@@ -8,7 +8,7 @@ import warnings
 
 class TestUntestedModules(unittest.TestCase):
     def test_at_least_import_untested_modules(self):
-        with test_support.catch_warning():
+        with warnings.catch_warnings(record=True):
             import CGIHTTPServer
             import aifc
             import audiodev
index 695bd6d0c3aeb8645ff7e63b9bbf1e2eafafe023..0bf22cf35dbb80dae694e3a65e48349bff57dbc1 100644 (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", "catch_warning", "CleanImport",
+           "open_urlresource", "CleanImport",
            "EnvironmentVarGuard", "captured_output",
            "captured_stdout", "TransientResource", "transient_internet",
            "run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest",
@@ -52,7 +52,7 @@ class ResourceDenied(TestSkipped):
 def import_module(name, deprecated=False):
     """Import the module to be tested, raising TestSkipped if it is not
     available."""
-    with catch_warning(record=False):
+    with warnings.catch_warnings():
         if deprecated:
             warnings.filterwarnings("ignore", ".+ (module|package)",
                                     DeprecationWarning)
@@ -381,10 +381,6 @@ def open_urlresource(url):
     return open(fn)
 
 
-def catch_warning(module=warnings, record=True):
-    return warnings.catch_warnings(record=record, module=module)
-
-
 class CleanImport(object):
     """Context manager to force import to return a new module reference.
 
index 05b237a97a20ddfd3e75ee949a585018ceb43679..b20f2b4e0e92768c5276705e3dfa3cabdcc157f7 100644 (file)
@@ -44,7 +44,7 @@ def find_block(block, name):
 
 class SymtableTest(unittest.TestCase):
 
-    with test_support.catch_warning(record=False):
+    with warnings.catch_warnings():
         # Ignore warnings about "from blank import *"
         warnings.simplefilter("ignore", SyntaxWarning)
         top = symtable.symtable(TEST_CODE, "?", "exec")
@@ -60,16 +60,16 @@ class SymtableTest(unittest.TestCase):
         def check(w, msg):
             self.assertEqual(str(w.message), msg)
         sym = self.top.lookup("glob")
-        with test_support.catch_warning() as w:
+        with warnings.catch_warnings(record=True) as w:
             warnings.simplefilter("always", DeprecationWarning)
             self.assertFalse(sym.is_vararg())
-            check(w, "is_vararg() is obsolete and will be removed")
-            w.reset()
+            check(w[-1].message, "is_vararg() is obsolete and will be removed")
             self.assertFalse(sym.is_keywordarg())
-            check(w, "is_keywordarg() is obsolete and will be removed")
-            w.reset()
+            check(w[-1].message,
+                    "is_keywordarg() is obsolete and will be removed")
             self.assertFalse(sym.is_in_tuple())
-            check(w, "is_in_tuple() is obsolete and will be removed")
+            check(w[-1].message,
+                    "is_in_tuple() is obsolete and will be removed")
 
     def test_type(self):
         self.assertEqual(self.top.get_type(), "module")
index 1dcbbedd707f47a114c4958ee170c0af1efb8a9a..7b351b8996b4f79af10e0118a9b50ed9e523cff1 100644 (file)
@@ -641,7 +641,7 @@ class Pathname_Tests(unittest.TestCase):
 
 def test_main():
     import warnings
-    with test_support.catch_warning(record=False):
+    with warnings.catch_warnings():
         warnings.filterwarnings('ignore', ".*urllib\.urlopen.*Python 3.0",
                                 DeprecationWarning)
         test_support.run_unittest(
index 0404b77ac37180aa88abcbeb9c61383c895b04f0..58fe282d3111379c851e7ecc658796c612a18393 100644 (file)
@@ -182,8 +182,8 @@ class urlretrieveNetworkTests(unittest.TestCase):
 
 def test_main():
     test_support.requires('network')
-    from warnings import filterwarnings
-    with test_support.catch_warning(record=False):
+    from warnings import filterwarnings, catch_warnings
+    with catch_warnings():
         filterwarnings('ignore', '.*urllib\.urlopen.*Python 3.0',
                         DeprecationWarning)
         test_support.run_unittest(URLTimeoutTest,
index cae610ef73e08dd90a3c4649e0d6c40c06eb6871..4bb0c4573644b8d376c4da22dadf83cd7674065d 100755 (executable)
@@ -135,7 +135,7 @@ class MutableStringTest(UserStringTest):
         self.assertEqual(s, "")
 
 def test_main():
-    with test_support.catch_warning(record=False):
+    with warnings.catch_warnings():
         warnings.filterwarnings("ignore", ".*MutableString",
                                 DeprecationWarning)
         test_support.run_unittest(UserStringTest, MutableStringTest)
index 9980f2497d66bb804d6040342c281c24eb36e013..388b5e9d3a6b0e870fbafe959be4b9c0a984b26e 100644 (file)
@@ -72,64 +72,69 @@ class FilterTests(object):
     """Testing the filtering functionality."""
 
     def test_error(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("error", category=UserWarning)
             self.assertRaises(UserWarning, self.module.warn,
                                 "FilterTests.test_error")
 
     def test_ignore(self):
-        with test_support.catch_warning(module=self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("ignore", category=UserWarning)
             self.module.warn("FilterTests.test_ignore", UserWarning)
             self.assertEquals(len(w), 0)
 
     def test_always(self):
-        with test_support.catch_warning(module=self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("always", category=UserWarning)
             message = "FilterTests.test_always"
             self.module.warn(message, UserWarning)
-            self.assert_(message, w.message)
+            self.assert_(message, w[-1].message)
             self.module.warn(message, UserWarning)
-            self.assert_(w.message, message)
+            self.assert_(w[-1].message, message)
 
     def test_default(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("default", category=UserWarning)
             message = UserWarning("FilterTests.test_default")
             for x in xrange(2):
                 self.module.warn(message, UserWarning)
                 if x == 0:
-                    self.assertEquals(w.message, message)
-                    w.reset()
+                    self.assertEquals(w[-1].message, message)
+                    del w[:]
                 elif x == 1:
-                    self.assert_(not len(w), "unexpected warning: " + str(w))
+                    self.assertEquals(len(w), 0)
                 else:
                     raise ValueError("loop variant unhandled")
 
     def test_module(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("module", category=UserWarning)
             message = UserWarning("FilterTests.test_module")
             self.module.warn(message, UserWarning)
-            self.assertEquals(w.message, message)
-            w.reset()
+            self.assertEquals(w[-1].message, message)
+            del w[:]
             self.module.warn(message, UserWarning)
-            self.assert_(not len(w), "unexpected message: " + str(w))
+            self.assertEquals(len(w), 0)
 
     def test_once(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("once", category=UserWarning)
             message = UserWarning("FilterTests.test_once")
             self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                     42)
-            self.assertEquals(w.message, message)
-            w.reset()
+            self.assertEquals(w[-1].message, message)
+            del w[:]
             self.module.warn_explicit(message, UserWarning, "test_warnings.py",
                                     13)
             self.assertEquals(len(w), 0)
@@ -138,19 +143,20 @@ class FilterTests(object):
             self.assertEquals(len(w), 0)
 
     def test_inheritance(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("error", category=Warning)
             self.assertRaises(UserWarning, self.module.warn,
                                 "FilterTests.test_inheritance", UserWarning)
 
     def test_ordering(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.resetwarnings()
             self.module.filterwarnings("ignore", category=UserWarning)
             self.module.filterwarnings("error", category=UserWarning,
                                         append=True)
-            w.reset()
+            del w[:]
             try:
                 self.module.warn("FilterTests.test_ordering", UserWarning)
             except UserWarning:
@@ -160,28 +166,29 @@ class FilterTests(object):
     def test_filterwarnings(self):
         # Test filterwarnings().
         # Implicitly also tests resetwarnings().
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             self.module.filterwarnings("error", "", Warning, "", 0)
             self.assertRaises(UserWarning, self.module.warn, 'convert to error')
 
             self.module.resetwarnings()
             text = 'handle normally'
             self.module.warn(text)
-            self.assertEqual(str(w.message), text)
-            self.assert_(w.category is UserWarning)
+            self.assertEqual(str(w[-1].message), text)
+            self.assert_(w[-1].category is UserWarning)
 
             self.module.filterwarnings("ignore", "", Warning, "", 0)
             text = 'filtered out'
             self.module.warn(text)
-            self.assertNotEqual(str(w.message), text)
+            self.assertNotEqual(str(w[-1].message), text)
 
             self.module.resetwarnings()
             self.module.filterwarnings("error", "hex*", Warning, "", 0)
             self.assertRaises(UserWarning, self.module.warn, 'hex/oct')
             text = 'nonmatching text'
             self.module.warn(text)
-            self.assertEqual(str(w.message), text)
-            self.assert_(w.category is UserWarning)
+            self.assertEqual(str(w[-1].message), text)
+            self.assert_(w[-1].category is UserWarning)
 
 class CFilterTests(BaseTest, FilterTests):
     module = c_warnings
@@ -195,40 +202,51 @@ class WarnTests(unittest.TestCase):
     """Test warnings.warn() and warnings.warn_explicit()."""
 
     def test_message(self):
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(record=True,
+                module=self.module) as w:
             for i in range(4):
                 text = 'multi %d' %i  # Different text on each call.
                 self.module.warn(text)
-                self.assertEqual(str(w.message), text)
-                self.assert_(w.category is UserWarning)
+                self.assertEqual(str(w[-1].message), text)
+                self.assert_(w[-1].category is UserWarning)
 
     def test_filename(self):
         with warnings_state(self.module):
-            with test_support.catch_warning(self.module) as w:
+            with original_warnings.catch_warnings(record=True,
+                    module=self.module) as w:
                 warning_tests.inner("spam1")
-                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "warning_tests.py")
                 warning_tests.outer("spam2")
-                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "warning_tests.py")
 
     def test_stacklevel(self):
         # Test stacklevel argument
         # make sure all messages are different, so the warning won't be skipped
         with warnings_state(self.module):
-            with test_support.catch_warning(self.module) as w:
+            with original_warnings.catch_warnings(record=True,
+                    module=self.module) as w:
                 warning_tests.inner("spam3", stacklevel=1)
-                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "warning_tests.py")
                 warning_tests.outer("spam4", stacklevel=1)
-                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "warning_tests.py")
 
                 warning_tests.inner("spam5", stacklevel=2)
-                self.assertEqual(os.path.basename(w.filename), "test_warnings.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "test_warnings.py")
                 warning_tests.outer("spam6", stacklevel=2)
-                self.assertEqual(os.path.basename(w.filename), "warning_tests.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "warning_tests.py")
                 warning_tests.outer("spam6.5", stacklevel=3)
-                self.assertEqual(os.path.basename(w.filename), "test_warnings.py")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "test_warnings.py")
 
                 warning_tests.inner("spam7", stacklevel=9999)
-                self.assertEqual(os.path.basename(w.filename), "sys")
+                self.assertEqual(os.path.basename(w[-1].filename),
+                                    "sys")
 
     def test_missing_filename_not_main(self):
         # If __file__ is not specified and __main__ is not the module name,
@@ -237,9 +255,10 @@ class WarnTests(unittest.TestCase):
         try:
             del warning_tests.__file__
             with warnings_state(self.module):
-                with test_support.catch_warning(self.module) as w:
+                with original_warnings.catch_warnings(record=True,
+                        module=self.module) as w:
                     warning_tests.inner("spam8", stacklevel=1)
-                    self.assertEqual(w.filename, warning_tests.__name__)
+                    self.assertEqual(w[-1].filename, warning_tests.__name__)
         finally:
             warning_tests.__file__ = filename
 
@@ -254,9 +273,10 @@ class WarnTests(unittest.TestCase):
             del warning_tests.__file__
             warning_tests.__name__ = '__main__'
             with warnings_state(self.module):
-                with test_support.catch_warning(self.module) as w:
+                with original_warnings.catch_warnings(record=True,
+                        module=self.module) as w:
                     warning_tests.inner('spam9', stacklevel=1)
-                    self.assertEqual(w.filename, sys.argv[0])
+                    self.assertEqual(w[-1].filename, sys.argv[0])
         finally:
             warning_tests.__file__ = filename
             warning_tests.__name__ = module_name
@@ -272,9 +292,10 @@ class WarnTests(unittest.TestCase):
             warning_tests.__name__ = '__main__'
             del sys.argv
             with warnings_state(self.module):
-                with test_support.catch_warning(self.module) as w:
+                with original_warnings.catch_warnings(record=True,
+                        module=self.module) as w:
                     warning_tests.inner('spam10', stacklevel=1)
-                    self.assertEqual(w.filename, '__main__')
+                    self.assertEqual(w[-1].filename, '__main__')
         finally:
             warning_tests.__file__ = filename
             warning_tests.__name__ = module_name
@@ -292,9 +313,10 @@ class WarnTests(unittest.TestCase):
             warning_tests.__name__ = '__main__'
             sys.argv = ['']
             with warnings_state(self.module):
-                with test_support.catch_warning(self.module) as w:
+                with original_warnings.catch_warnings(record=True,
+                        module=self.module) as w:
                     warning_tests.inner('spam11', stacklevel=1)
-                    self.assertEqual(w.filename, '__main__')
+                    self.assertEqual(w[-1].filename, '__main__')
         finally:
             warning_tests.__file__ = file_name
             warning_tests.__name__ = module_name
@@ -328,7 +350,7 @@ class WCmdLineTests(unittest.TestCase):
     def test_improper_input(self):
         # Uses the private _setoption() function to test the parsing
         # of command-line warning arguments
-        with test_support.catch_warning(self.module):
+        with original_warnings.catch_warnings(module=self.module):
             self.assertRaises(self.module._OptionError,
                               self.module._setoption, '1:2:3:4:5:6')
             self.assertRaises(self.module._OptionError,
@@ -353,7 +375,7 @@ class _WarningsTests(BaseTest):
 
     def test_filter(self):
         # Everything should function even if 'filters' is not in warnings.
-        with test_support.catch_warning(self.module) as w:
+        with original_warnings.catch_warnings(module=self.module) as w:
             self.module.filterwarnings("error", "", Warning, "", 0)
             self.assertRaises(UserWarning, self.module.warn,
                                 'convert to error')
@@ -368,21 +390,22 @@ class _WarningsTests(BaseTest):
         try:
             original_registry = self.module.onceregistry
             __warningregistry__ = {}
-            with test_support.catch_warning(self.module) as w:
+            with original_warnings.catch_warnings(record=True,
+                    module=self.module) as w:
                 self.module.resetwarnings()
                 self.module.filterwarnings("once", category=UserWarning)
                 self.module.warn_explicit(message, UserWarning, "file", 42)
-                self.failUnlessEqual(w.message, message)
-                w.reset()
+                self.failUnlessEqual(w[-1].message, message)
+                del w[:]
                 self.module.warn_explicit(message, UserWarning, "file", 42)
                 self.assertEquals(len(w), 0)
                 # Test the resetting of onceregistry.
                 self.module.onceregistry = {}
                 __warningregistry__ = {}
                 self.module.warn('onceregistry test')
-                self.failUnlessEqual(w.message.args, message.args)
+                self.failUnlessEqual(w[-1].message.args, message.args)
                 # Removal of onceregistry is okay.
-                w.reset()
+                del w[:]
                 del self.module.onceregistry
                 __warningregistry__ = {}
                 self.module.warn_explicit(message, UserWarning, "file", 42)
@@ -393,7 +416,7 @@ class _WarningsTests(BaseTest):
     def test_showwarning_missing(self):
         # Test that showwarning() missing is okay.
         text = 'del showwarning test'
-        with test_support.catch_warning(self.module):
+        with original_warnings.catch_warnings(module=self.module):
             self.module.filterwarnings("always", category=UserWarning)
             del self.module.showwarning
             with test_support.captured_output('stderr') as stream:
@@ -414,7 +437,7 @@ class _WarningsTests(BaseTest):
     def test_show_warning_output(self):
         # With showarning() missing, make sure that output is okay.
         text = 'test show_warning'
-        with test_support.catch_warning(self.module):
+        with original_warnings.catch_warnings(module=self.module):
             self.module.filterwarnings("always", category=UserWarning)
             del self.module.showwarning
             with test_support.captured_output('stderr') as stream:
@@ -486,7 +509,6 @@ class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests):
     module = py_warnings
 
 
-
 class CatchWarningTests(BaseTest):
 
     """Test catch_warnings()."""
@@ -511,12 +533,12 @@ class CatchWarningTests(BaseTest):
             self.assertRaises(AttributeError, getattr, w, 'message')
             wmod.simplefilter("always")
             wmod.warn("foo")
-            self.assertEqual(str(w.message), "foo")
+            self.assertEqual(str(w[-1].message), "foo")
             wmod.warn("bar")
-            self.assertEqual(str(w.message), "bar")
+            self.assertEqual(str(w[-1].message), "bar")
             self.assertEqual(str(w[0].message), "foo")
             self.assertEqual(str(w[1].message), "bar")
-            w.reset()
+            del w[:]
             self.assertEqual(w, [])
         orig_showwarning = wmod.showwarning
         with wmod.catch_warnings(module=wmod, record=False) as w:
@@ -545,7 +567,7 @@ class ShowwarningDeprecationTests(BaseTest):
     def test_deprecation(self):
         # message, category, filename, lineno[, file[, line]]
         args = ("message", UserWarning, "file name", 42)
-        with test_support.catch_warning(module=self.module):
+        with original_warnings.catch_warnings(module=self.module):
             self.module.filterwarnings("error", category=DeprecationWarning)
             self.module.showwarning = self.bad_showwarning
             self.assertRaises(DeprecationWarning, self.module.warn_explicit,
index 9ec04be274b97fc9d7cb87921e182152bf5bfe1d..04e7b5878c6255bcfcd461da0734e5f1b1e298bc 100644 (file)
@@ -8,7 +8,7 @@ import sys
 import types
 
 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
-           "resetwarnings"]
+           "resetwarnings", "catch_warnings"]
 
 
 def warnpy3k(message, category=None, stacklevel=1):
@@ -304,37 +304,20 @@ class WarningMessage(object):
                                     self.filename, self.lineno, self.line))
 
 
-class WarningsRecorder(list):
-
-    """Record the result of various showwarning() calls."""
-
-    # Explicitly stated arguments so as to not trigger DeprecationWarning
-    # about adding 'line'.
-    def showwarning(self, *args, **kwargs):
-        self.append(WarningMessage(*args, **kwargs))
-
-    def __getattr__(self, attr):
-        """Return attributes from the last caught warning, or raise
-        AttributeError."""
-        try:
-            return getattr(self[-1], attr)
-        except IndexError:
-            raise AttributeError("no recorded warning to read "
-                                    "{0!r} attribute from".format(attr))
-
-
-    def reset(self):
-        del self[:]
-
-
 class catch_warnings(object):
 
-    """Guard the warnings filter from being permanently changed and optionally
-    record the details of any warnings that are issued.
+    """A context manager that copies and restores the warnings filter upon
+    exiting the context.
+
+    The 'record' argument specifies whether warnings should be captured by a
+    custom implementation of warnings.showwarning() and be appended to a list
+    returned by the context manager. Otherwise None is returned by the context
+    manager. The objects appended to the list are arguments whose attributes
+    mirror the arguments to showwarning().
 
-    Context manager returns an instance of warnings.WarningRecorder which is a
-    list of WarningMessage instances. Attributes on WarningRecorder are
-    redirected to the last created WarningMessage instance.
+    The 'module' argument is to specify an alternative module to the module
+    named 'warnings' and imported under that name. This argument is only useful
+    when testing the warnings module itself.
 
     """
 
@@ -346,17 +329,21 @@ class catch_warnings(object):
         keyword-only.
 
         """
-        self._recorder = WarningsRecorder() if record else None
+        self._record = record
         self._module = sys.modules['warnings'] if module is None else module
 
     def __enter__(self):
         self._filters = self._module.filters
         self._module.filters = self._filters[:]
         self._showwarning = self._module.showwarning
-        if self._recorder is not None:
-            self._recorder.reset()  # In case the instance is being reused.
-            self._module.showwarning = self._recorder.showwarning
-        return self._recorder
+        if self._record:
+            log = []
+            def showwarning(*args, **kwargs):
+                log.append(WarningMessage(*args, **kwargs))
+            self._module.showwarning = showwarning
+            return log
+        else:
+            return None
 
     def __exit__(self, *exc_info):
         self._module.filters = self._filters
index b2da2c5993a38769c0f3d29a3e9a664bb4f5eaf3..b7da5f1b89040e6c79df007a3825ca225f876c1c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -60,6 +60,9 @@ C-API
 Library
 -------
 
+- Issue 3781: Clean up the API for warnings.catch_warnings() by having it
+  return a list or None rather than a custom object.
+
 - Issue #1638033: Cookie.Morsel gained the httponly attribute.
 
 - Issue #3535: zipfile couldn't read some zip files larger than 2GB.