summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/warnings.rst110
-rw-r--r--Lib/test/test___all__.py4
-rw-r--r--Lib/test/test_hmac.py2
-rw-r--r--Lib/test/test_import.py4
-rw-r--r--Lib/test/test_re.py2
-rw-r--r--Lib/test/test_struct.py4
-rw-r--r--Lib/test/test_structmembers.py14
-rw-r--r--Lib/test/test_sundry.py2
-rw-r--r--Lib/test/test_warnings.py142
-rw-r--r--Lib/warnings.py46
10 files changed, 193 insertions, 137 deletions
diff --git a/Doc/library/warnings.rst b/Doc/library/warnings.rst
index e3d3b5b..f9d01b2 100644
--- a/Doc/library/warnings.rst
+++ b/Doc/library/warnings.rst
@@ -160,6 +160,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
@@ -248,31 +309,22 @@ Available Functions
and calls to :func:`simplefilter`.
-Available Classes
------------------
+Available Context Managers
+--------------------------
.. 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.
-
- Typical usage of the context manager is like so::
-
- 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.
.. versionadded:: 2.6
@@ -280,19 +332,3 @@ Available Classes
Constructor arguments turned into keyword-only arguments.
-
-.. 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
diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py
index ba8f75b..052cc20 100644
--- a/Lib/test/test___all__.py
+++ b/Lib/test/test___all__.py
@@ -1,5 +1,5 @@
import unittest
-from test.support import run_unittest, catch_warning
+from test.support import run_unittest
import sys
import warnings
@@ -8,7 +8,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:
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
index 43953cf..f7ac8ef 100644
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -211,7 +211,7 @@ class TestVectorsTestCase(unittest.TestCase):
def digest(self):
return self._x.digest()
- with support.catch_warning():
+ with warnings.catch_warnings():
warnings.simplefilter('error', RuntimeWarning)
try:
hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
index aa65c7a..0dbbbf0 100644
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -6,7 +6,7 @@ import sys
import py_compile
import warnings
import imp
-from test.support import unlink, TESTFN, unload, run_unittest, catch_warning
+from test.support import unlink, TESTFN, unload, run_unittest
def remove_files(name):
@@ -153,7 +153,7 @@ class ImportTest(unittest.TestCase):
self.assert_(y is 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)
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index 17370bb..6ee84c6 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -1,7 +1,7 @@
import sys
sys.path = ['.'] + sys.path
-from test.support import verbose, run_unittest, catch_warning
+from test.support import verbose, run_unittest
import re
from re import Scanner
import sys, os, traceback
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 6dc0e8d..00219b8 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -4,7 +4,7 @@ import struct
import warnings
from functools import wraps
-from test.support import TestFailed, verbose, run_unittest, catch_warning
+from 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")
diff --git a/Lib/test/test_structmembers.py b/Lib/test/test_structmembers.py
index d6c9fea..878223a 100644
--- a/Lib/test/test_structmembers.py
+++ b/Lib/test/test_structmembers.py
@@ -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 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 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 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 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 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 support.catch_warning() as w:
+ with warnings.catch_warnings(record=True) as w:
ts.T_USHORT = USHRT_MAX+1
self.has_warned(w)
diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py
index a99d2c0..6b425c6 100644
--- a/Lib/test/test_sundry.py
+++ b/Lib/test/test_sundry.py
@@ -7,7 +7,7 @@ import warnings
class TestUntestedModules(unittest.TestCase):
def test_at_least_import_untested_modules(self):
- with support.catch_warning():
+ with warnings.catch_warnings(record=True):
import aifc
import bdb
import cgitb
diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py
index 087bf3d..199e6fc 100644
--- a/Lib/test/test_warnings.py
+++ b/Lib/test/test_warnings.py
@@ -72,64 +72,69 @@ class FilterTests(object):
"""Testing the filtering functionality."""
def test_error(self):
- with 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 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 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 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 range(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 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 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 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 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 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,12 +202,13 @@ class WarnTests(unittest.TestCase):
"""Test warnings.warn() and warnings.warn_explicit()."""
def test_message(self):
- with 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)
# Issue 3639
def test_warn_nonstandard_types(self):
@@ -210,35 +218,45 @@ class WarnTests(unittest.TestCase):
self.module.warn(ob)
# Don't directly compare objects since
# ``Warning() != Warning()``.
- self.assertEquals(str(w.message), str(UserWarning(ob)))
+ self.assertEquals(str(w[-1].message), str(UserWarning(ob)))
def test_filename(self):
with warnings_state(self.module):
- with 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 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,
@@ -247,9 +265,10 @@ class WarnTests(unittest.TestCase):
try:
del warning_tests.__file__
with warnings_state(self.module):
- with 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
@@ -264,9 +283,10 @@ class WarnTests(unittest.TestCase):
del warning_tests.__file__
warning_tests.__name__ = '__main__'
with warnings_state(self.module):
- with 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
@@ -282,9 +302,10 @@ class WarnTests(unittest.TestCase):
warning_tests.__name__ = '__main__'
del sys.argv
with warnings_state(self.module):
- with 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
@@ -302,9 +323,10 @@ class WarnTests(unittest.TestCase):
warning_tests.__name__ = '__main__'
sys.argv = ['']
with warnings_state(self.module):
- with 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
@@ -337,7 +359,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 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,
@@ -362,7 +384,7 @@ class _WarningsTests(BaseTest):
def test_filter(self):
# Everything should function even if 'filters' is not in warnings.
- with 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')
@@ -377,21 +399,22 @@ class _WarningsTests(BaseTest):
try:
original_registry = self.module.onceregistry
__warningregistry__ = {}
- with 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)
@@ -402,7 +425,7 @@ class _WarningsTests(BaseTest):
def test_showwarning_missing(self):
# Test that showwarning() missing is okay.
text = 'del showwarning test'
- with support.catch_warning(self.module):
+ with original_warnings.catch_warnings(module=self.module):
self.module.filterwarnings("always", category=UserWarning)
del self.module.showwarning
with support.captured_output('stderr') as stream:
@@ -423,7 +446,7 @@ class _WarningsTests(BaseTest):
def test_show_warning_output(self):
# With showarning() missing, make sure that output is okay.
text = 'test show_warning'
- with support.catch_warning(self.module):
+ with original_warnings.catch_warnings(module=self.module):
self.module.filterwarnings("always", category=UserWarning)
del self.module.showwarning
with support.captured_output('stderr') as stream:
@@ -494,6 +517,7 @@ class CWarningsDisplayTests(BaseTest, WarningsDisplayTests):
class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests):
module = py_warnings
+
class CatchWarningTests(BaseTest):
"""Test catch_warnings()."""
@@ -517,12 +541,12 @@ class CatchWarningTests(BaseTest):
self.assertEqual(w, [])
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 support.catch_warning(module=wmod, record=False) as w:
diff --git a/Lib/warnings.py b/Lib/warnings.py
index 566e0b9..0e147db 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -7,7 +7,7 @@ import linecache
import sys
__all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
- "resetwarnings"]
+ "resetwarnings", "catch_warnings"]
def showwarning(message, category, filename, lineno, file=None, line=None):
@@ -274,28 +274,20 @@ class WarningMessage(object):
self.filename, self.lineno, self.line))
-class WarningsRecorder(list):
-
- """Record the result of various showwarning() calls."""
-
- def showwarning(self, *args, **kwargs):
- self.append(WarningMessage(*args, **kwargs))
-
- def __getattr__(self, attr):
- return getattr(self[-1], 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.
"""
@@ -307,17 +299,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