warnings.catch_warnings() now returns a list or None instead of the custom

WarningsRecorder object. This makes the API simpler to use as no special object
must be learned.

Closes issue 3781.
Review by Benjamin Peterson.
This commit is contained in:
Brett Cannon 2008-09-09 00:49:16 +00:00
parent 631be01252
commit 672237dc6c
24 changed files with 268 additions and 253 deletions

View 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
-----------------
Available Context Managers
--------------------------
.. class:: catch_warnings([\*, record=False[, module=None]])
.. 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.
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`.
Typical usage of the context manager is like so::
def fxn():
warn("fxn is deprecated", DeprecationWarning)
return "spam spam bacon spam"
# 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

View 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):

View 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) :

View 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

View 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:

View 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:

View 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)

View 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())

View 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)

View 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"

View 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)

View 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)

View 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

View 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")

View 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)

View 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

View 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.

View 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")

View 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(

View 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,

View File

@ -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)

View 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,

View 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.
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 '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().
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

View File

@ -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.