mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
Move test.test_support.catch_warning() to the warnings module, rename it
catch_warnings(), and clean up the API. While expanding the test suite, a bug was found where a warning about the 'line' argument to showwarning() was not letting functions with '*args' go without a warning. Closes issue 3602. Code review by Benjamin Peterson.
This commit is contained in:
parent
86533776c2
commit
1eaf0742d8
11 changed files with 208 additions and 126 deletions
|
@ -263,3 +263,53 @@ Available Functions
|
||||||
:func:`filterwarnings`, including that of the :option:`-W` command line options
|
:func:`filterwarnings`, including that of the :option:`-W` command line options
|
||||||
and calls to :func:`simplefilter`.
|
and calls to :func:`simplefilter`.
|
||||||
|
|
||||||
|
|
||||||
|
Available Classes
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. class:: catch_warnings([record=False[, module=None]])
|
||||||
|
|
||||||
|
A context manager that guards the warnings filter from being permanentally
|
||||||
|
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"
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In Python 3.0, the arguments to the constructor for
|
||||||
|
:class:`catch_warnings` are keyword-only arguments.
|
||||||
|
|
||||||
|
.. 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
|
||||||
|
|
|
@ -73,9 +73,9 @@ __all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import socket # For gethostbyaddr()
|
import socket # For gethostbyaddr()
|
||||||
from test.test_support import catch_warning
|
from warnings import filterwarnings, catch_warnings
|
||||||
from warnings import filterwarnings
|
with catch_warnings():
|
||||||
with catch_warning(record=False):
|
if sys.py3kwarning:
|
||||||
filterwarnings("ignore", ".*mimetools has been removed",
|
filterwarnings("ignore", ".*mimetools has been removed",
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
import mimetools
|
import mimetools
|
||||||
|
|
|
@ -49,8 +49,9 @@ you - by calling your self.found_terminator() method.
|
||||||
import socket
|
import socket
|
||||||
import asyncore
|
import asyncore
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from sys import py3kwarning
|
||||||
from test.test_support import catch_warning
|
from test.test_support import catch_warning
|
||||||
from warnings import filterwarnings
|
from warnings import filterwarnings, catch_warnings
|
||||||
|
|
||||||
class async_chat (asyncore.dispatcher):
|
class async_chat (asyncore.dispatcher):
|
||||||
"""This is an abstract class. You must derive from this class, and add
|
"""This is an abstract class. You must derive from this class, and add
|
||||||
|
@ -218,7 +219,8 @@ class async_chat (asyncore.dispatcher):
|
||||||
# handle classic producer behavior
|
# handle classic producer behavior
|
||||||
obs = self.ac_out_buffer_size
|
obs = self.ac_out_buffer_size
|
||||||
try:
|
try:
|
||||||
with catch_warning(record=False):
|
with catch_warnings():
|
||||||
|
if py3kwarning:
|
||||||
filterwarnings("ignore", ".*buffer", DeprecationWarning)
|
filterwarnings("ignore", ".*buffer", DeprecationWarning)
|
||||||
data = buffer(first, 0, obs)
|
data = buffer(first, 0, obs)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|
|
@ -39,12 +39,13 @@ import sys
|
||||||
import os
|
import os
|
||||||
import urllib
|
import urllib
|
||||||
import UserDict
|
import UserDict
|
||||||
from test.test_support import catch_warning
|
from warnings import filterwarnings, catch_warnings
|
||||||
from warnings import filterwarnings
|
with catch_warnings():
|
||||||
with catch_warning(record=False):
|
if sys.py3kwarning:
|
||||||
filterwarnings("ignore", ".*mimetools has been removed",
|
filterwarnings("ignore", ".*mimetools has been removed",
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
import mimetools
|
import mimetools
|
||||||
|
if sys.py3kwarning:
|
||||||
filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
|
filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
|
||||||
import rfc822
|
import rfc822
|
||||||
|
|
||||||
|
|
|
@ -67,10 +67,11 @@ Req-sent-unread-response _CS_REQ_SENT <response_class>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
from sys import py3kwarning
|
||||||
from urlparse import urlsplit
|
from urlparse import urlsplit
|
||||||
import warnings
|
import warnings
|
||||||
from test.test_support import catch_warning
|
with warnings.catch_warnings():
|
||||||
with catch_warning(record=False):
|
if py3kwarning:
|
||||||
warnings.filterwarnings("ignore", ".*mimetools has been removed",
|
warnings.filterwarnings("ignore", ".*mimetools has been removed",
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
import mimetools
|
import mimetools
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from test.test_support import catch_warning
|
from warnings import filterwarnings, catch_warnings
|
||||||
from warnings import filterwarnings
|
with catch_warnings(record=False):
|
||||||
with catch_warning(record=False):
|
if sys.py3kwarning:
|
||||||
filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
|
filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
|
||||||
import rfc822
|
import rfc822
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ __all__ = ["Error", "TestFailed", "TestSkipped", "ResourceDenied", "import_modul
|
||||||
"is_resource_enabled", "requires", "find_unused_port", "bind_port",
|
"is_resource_enabled", "requires", "find_unused_port", "bind_port",
|
||||||
"fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ",
|
"fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ",
|
||||||
"findfile", "verify", "vereq", "sortdict", "check_syntax_error",
|
"findfile", "verify", "vereq", "sortdict", "check_syntax_error",
|
||||||
"open_urlresource", "WarningMessage", "catch_warning", "CleanImport",
|
"open_urlresource", "catch_warning", "CleanImport",
|
||||||
"EnvironmentVarGuard", "captured_output",
|
"EnvironmentVarGuard", "captured_output",
|
||||||
"captured_stdout", "TransientResource", "transient_internet",
|
"captured_stdout", "TransientResource", "transient_internet",
|
||||||
"run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest",
|
"run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest",
|
||||||
|
@ -381,71 +381,8 @@ def open_urlresource(url):
|
||||||
return open(fn)
|
return open(fn)
|
||||||
|
|
||||||
|
|
||||||
class WarningMessage(object):
|
|
||||||
"Holds the result of a single showwarning() call"
|
|
||||||
_WARNING_DETAILS = "message category filename lineno line".split()
|
|
||||||
def __init__(self, message, category, filename, lineno, line=None):
|
|
||||||
for attr in self._WARNING_DETAILS:
|
|
||||||
setattr(self, attr, locals()[attr])
|
|
||||||
self._category_name = category.__name__ if category else None
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return ("{message : %r, category : %r, filename : %r, lineno : %s, "
|
|
||||||
"line : %r}" % (self.message, self._category_name,
|
|
||||||
self.filename, self.lineno, self.line))
|
|
||||||
|
|
||||||
class WarningRecorder(object):
|
|
||||||
"Records the result of any showwarning calls"
|
|
||||||
def __init__(self):
|
|
||||||
self.warnings = []
|
|
||||||
self._set_last(None)
|
|
||||||
|
|
||||||
def _showwarning(self, message, category, filename, lineno,
|
|
||||||
file=None, line=None):
|
|
||||||
wm = WarningMessage(message, category, filename, lineno, line)
|
|
||||||
self.warnings.append(wm)
|
|
||||||
self._set_last(wm)
|
|
||||||
|
|
||||||
def _set_last(self, last_warning):
|
|
||||||
if last_warning is None:
|
|
||||||
for attr in WarningMessage._WARNING_DETAILS:
|
|
||||||
setattr(self, attr, None)
|
|
||||||
else:
|
|
||||||
for attr in WarningMessage._WARNING_DETAILS:
|
|
||||||
setattr(self, attr, getattr(last_warning, attr))
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.warnings = []
|
|
||||||
self._set_last(None)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '[%s]' % (', '.join(map(str, self.warnings)))
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def catch_warning(module=warnings, record=True):
|
def catch_warning(module=warnings, record=True):
|
||||||
"""Guard the warnings filter from being permanently changed and
|
return warnings.catch_warnings(record=record, module=module)
|
||||||
optionally record the details of any warnings that are issued.
|
|
||||||
|
|
||||||
Use like this:
|
|
||||||
|
|
||||||
with catch_warning() as w:
|
|
||||||
warnings.warn("foo")
|
|
||||||
assert str(w.message) == "foo"
|
|
||||||
"""
|
|
||||||
original_filters = module.filters
|
|
||||||
original_showwarning = module.showwarning
|
|
||||||
if record:
|
|
||||||
recorder = WarningRecorder()
|
|
||||||
module.showwarning = recorder._showwarning
|
|
||||||
else:
|
|
||||||
recorder = None
|
|
||||||
try:
|
|
||||||
# Replace the filters with a copy of the original
|
|
||||||
module.filters = module.filters[:]
|
|
||||||
yield recorder
|
|
||||||
finally:
|
|
||||||
module.showwarning = original_showwarning
|
|
||||||
module.filters = original_filters
|
|
||||||
|
|
||||||
|
|
||||||
class CleanImport(object):
|
class CleanImport(object):
|
||||||
|
|
|
@ -79,20 +79,19 @@ class FilterTests(object):
|
||||||
"FilterTests.test_error")
|
"FilterTests.test_error")
|
||||||
|
|
||||||
def test_ignore(self):
|
def test_ignore(self):
|
||||||
with test_support.catch_warning(self.module) as w:
|
with test_support.catch_warning(module=self.module) as w:
|
||||||
self.module.resetwarnings()
|
self.module.resetwarnings()
|
||||||
self.module.filterwarnings("ignore", category=UserWarning)
|
self.module.filterwarnings("ignore", category=UserWarning)
|
||||||
self.module.warn("FilterTests.test_ignore", UserWarning)
|
self.module.warn("FilterTests.test_ignore", UserWarning)
|
||||||
self.assert_(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
|
|
||||||
def test_always(self):
|
def test_always(self):
|
||||||
with test_support.catch_warning(self.module) as w:
|
with test_support.catch_warning(module=self.module) as w:
|
||||||
self.module.resetwarnings()
|
self.module.resetwarnings()
|
||||||
self.module.filterwarnings("always", category=UserWarning)
|
self.module.filterwarnings("always", category=UserWarning)
|
||||||
message = "FilterTests.test_always"
|
message = "FilterTests.test_always"
|
||||||
self.module.warn(message, UserWarning)
|
self.module.warn(message, UserWarning)
|
||||||
self.assert_(message, w.message)
|
self.assert_(message, w.message)
|
||||||
w.message = None # Reset.
|
|
||||||
self.module.warn(message, UserWarning)
|
self.module.warn(message, UserWarning)
|
||||||
self.assert_(w.message, message)
|
self.assert_(w.message, message)
|
||||||
|
|
||||||
|
@ -107,7 +106,7 @@ class FilterTests(object):
|
||||||
self.assertEquals(w.message, message)
|
self.assertEquals(w.message, message)
|
||||||
w.reset()
|
w.reset()
|
||||||
elif x == 1:
|
elif x == 1:
|
||||||
self.assert_(not w.message, "unexpected warning: " + str(w))
|
self.assert_(not len(w), "unexpected warning: " + str(w))
|
||||||
else:
|
else:
|
||||||
raise ValueError("loop variant unhandled")
|
raise ValueError("loop variant unhandled")
|
||||||
|
|
||||||
|
@ -120,7 +119,7 @@ class FilterTests(object):
|
||||||
self.assertEquals(w.message, message)
|
self.assertEquals(w.message, message)
|
||||||
w.reset()
|
w.reset()
|
||||||
self.module.warn(message, UserWarning)
|
self.module.warn(message, UserWarning)
|
||||||
self.assert_(not w.message, "unexpected message: " + str(w))
|
self.assert_(not len(w), "unexpected message: " + str(w))
|
||||||
|
|
||||||
def test_once(self):
|
def test_once(self):
|
||||||
with test_support.catch_warning(self.module) as w:
|
with test_support.catch_warning(self.module) as w:
|
||||||
|
@ -133,10 +132,10 @@ class FilterTests(object):
|
||||||
w.reset()
|
w.reset()
|
||||||
self.module.warn_explicit(message, UserWarning, "test_warnings.py",
|
self.module.warn_explicit(message, UserWarning, "test_warnings.py",
|
||||||
13)
|
13)
|
||||||
self.assert_(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
|
self.module.warn_explicit(message, UserWarning, "test_warnings2.py",
|
||||||
42)
|
42)
|
||||||
self.assert_(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
|
|
||||||
def test_inheritance(self):
|
def test_inheritance(self):
|
||||||
with test_support.catch_warning(self.module) as w:
|
with test_support.catch_warning(self.module) as w:
|
||||||
|
@ -156,7 +155,7 @@ class FilterTests(object):
|
||||||
self.module.warn("FilterTests.test_ordering", UserWarning)
|
self.module.warn("FilterTests.test_ordering", UserWarning)
|
||||||
except UserWarning:
|
except UserWarning:
|
||||||
self.fail("order handling for actions failed")
|
self.fail("order handling for actions failed")
|
||||||
self.assert_(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
|
|
||||||
def test_filterwarnings(self):
|
def test_filterwarnings(self):
|
||||||
# Test filterwarnings().
|
# Test filterwarnings().
|
||||||
|
@ -317,7 +316,6 @@ class WarnTests(unittest.TestCase):
|
||||||
None, Warning, None, 1, registry=42)
|
None, Warning, None, 1, registry=42)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CWarnTests(BaseTest, WarnTests):
|
class CWarnTests(BaseTest, WarnTests):
|
||||||
module = c_warnings
|
module = c_warnings
|
||||||
|
|
||||||
|
@ -377,7 +375,7 @@ class _WarningsTests(BaseTest):
|
||||||
self.failUnlessEqual(w.message, message)
|
self.failUnlessEqual(w.message, message)
|
||||||
w.reset()
|
w.reset()
|
||||||
self.module.warn_explicit(message, UserWarning, "file", 42)
|
self.module.warn_explicit(message, UserWarning, "file", 42)
|
||||||
self.assert_(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
# Test the resetting of onceregistry.
|
# Test the resetting of onceregistry.
|
||||||
self.module.onceregistry = {}
|
self.module.onceregistry = {}
|
||||||
__warningregistry__ = {}
|
__warningregistry__ = {}
|
||||||
|
@ -388,7 +386,7 @@ class _WarningsTests(BaseTest):
|
||||||
del self.module.onceregistry
|
del self.module.onceregistry
|
||||||
__warningregistry__ = {}
|
__warningregistry__ = {}
|
||||||
self.module.warn_explicit(message, UserWarning, "file", 42)
|
self.module.warn_explicit(message, UserWarning, "file", 42)
|
||||||
self.failUnless(not w.message)
|
self.assertEquals(len(w), 0)
|
||||||
finally:
|
finally:
|
||||||
self.module.onceregistry = original_registry
|
self.module.onceregistry = original_registry
|
||||||
|
|
||||||
|
@ -489,45 +487,45 @@ class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WarningsSupportTests(object):
|
class CatchWarningTests(BaseTest):
|
||||||
"""Test the warning tools from test support module"""
|
|
||||||
|
|
||||||
def test_catch_warning_restore(self):
|
"""Test catch_warnings()."""
|
||||||
|
|
||||||
|
def test_catch_warnings_restore(self):
|
||||||
wmod = self.module
|
wmod = self.module
|
||||||
orig_filters = wmod.filters
|
orig_filters = wmod.filters
|
||||||
orig_showwarning = wmod.showwarning
|
orig_showwarning = wmod.showwarning
|
||||||
with test_support.catch_warning(wmod):
|
with wmod.catch_warnings(record=True, module=wmod):
|
||||||
wmod.filters = wmod.showwarning = object()
|
wmod.filters = wmod.showwarning = object()
|
||||||
self.assert_(wmod.filters is orig_filters)
|
self.assert_(wmod.filters is orig_filters)
|
||||||
self.assert_(wmod.showwarning is orig_showwarning)
|
self.assert_(wmod.showwarning is orig_showwarning)
|
||||||
with test_support.catch_warning(wmod, record=False):
|
with wmod.catch_warnings(module=wmod, record=False):
|
||||||
wmod.filters = wmod.showwarning = object()
|
wmod.filters = wmod.showwarning = object()
|
||||||
self.assert_(wmod.filters is orig_filters)
|
self.assert_(wmod.filters is orig_filters)
|
||||||
self.assert_(wmod.showwarning is orig_showwarning)
|
self.assert_(wmod.showwarning is orig_showwarning)
|
||||||
|
|
||||||
def test_catch_warning_recording(self):
|
def test_catch_warnings_recording(self):
|
||||||
wmod = self.module
|
wmod = self.module
|
||||||
with test_support.catch_warning(wmod) as w:
|
with wmod.catch_warnings(module=wmod, record=True) as w:
|
||||||
self.assertEqual(w.warnings, [])
|
self.assertEqual(w, [])
|
||||||
wmod.simplefilter("always")
|
wmod.simplefilter("always")
|
||||||
wmod.warn("foo")
|
wmod.warn("foo")
|
||||||
self.assertEqual(str(w.message), "foo")
|
self.assertEqual(str(w.message), "foo")
|
||||||
wmod.warn("bar")
|
wmod.warn("bar")
|
||||||
self.assertEqual(str(w.message), "bar")
|
self.assertEqual(str(w.message), "bar")
|
||||||
self.assertEqual(str(w.warnings[0].message), "foo")
|
self.assertEqual(str(w[0].message), "foo")
|
||||||
self.assertEqual(str(w.warnings[1].message), "bar")
|
self.assertEqual(str(w[1].message), "bar")
|
||||||
w.reset()
|
w.reset()
|
||||||
self.assertEqual(w.warnings, [])
|
self.assertEqual(w, [])
|
||||||
orig_showwarning = wmod.showwarning
|
orig_showwarning = wmod.showwarning
|
||||||
with test_support.catch_warning(wmod, record=False) as w:
|
with wmod.catch_warnings(module=wmod, record=False) as w:
|
||||||
self.assert_(w is None)
|
self.assert_(w is None)
|
||||||
self.assert_(wmod.showwarning is orig_showwarning)
|
self.assert_(wmod.showwarning is orig_showwarning)
|
||||||
|
|
||||||
|
class CCatchWarningTests(CatchWarningTests):
|
||||||
class CWarningsSupportTests(BaseTest, WarningsSupportTests):
|
|
||||||
module = c_warnings
|
module = c_warnings
|
||||||
|
|
||||||
class PyWarningsSupportTests(BaseTest, WarningsSupportTests):
|
class PyCatchWarningTests(CatchWarningTests):
|
||||||
module = py_warnings
|
module = py_warnings
|
||||||
|
|
||||||
|
|
||||||
|
@ -539,14 +537,24 @@ class ShowwarningDeprecationTests(BaseTest):
|
||||||
def bad_showwarning(message, category, filename, lineno, file=None):
|
def bad_showwarning(message, category, filename, lineno, file=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ok_showwarning(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_deprecation(self):
|
def test_deprecation(self):
|
||||||
# message, category, filename, lineno[, file[, line]]
|
# message, category, filename, lineno[, file[, line]]
|
||||||
args = ("message", UserWarning, "file name", 42)
|
args = ("message", UserWarning, "file name", 42)
|
||||||
with test_support.catch_warning(self.module):
|
with test_support.catch_warning(module=self.module):
|
||||||
self.module.filterwarnings("error", category=DeprecationWarning)
|
self.module.filterwarnings("error", category=DeprecationWarning)
|
||||||
self.module.showwarning = self.bad_showwarning
|
self.module.showwarning = self.bad_showwarning
|
||||||
self.assertRaises(DeprecationWarning, self.module.warn_explicit,
|
self.assertRaises(DeprecationWarning, self.module.warn_explicit,
|
||||||
*args)
|
*args)
|
||||||
|
self.module.showwarning = self.ok_showwarning
|
||||||
|
try:
|
||||||
|
self.module.warn_explicit(*args)
|
||||||
|
except DeprecationWarning as exc:
|
||||||
|
self.fail('showwarning(*args) should not trigger a '
|
||||||
|
'DeprecationWarning')
|
||||||
|
|
||||||
class CShowwarningDeprecationTests(ShowwarningDeprecationTests):
|
class CShowwarningDeprecationTests(ShowwarningDeprecationTests):
|
||||||
module = c_warnings
|
module = c_warnings
|
||||||
|
@ -559,14 +567,12 @@ class PyShowwarningDeprecationTests(ShowwarningDeprecationTests):
|
||||||
def test_main():
|
def test_main():
|
||||||
py_warnings.onceregistry.clear()
|
py_warnings.onceregistry.clear()
|
||||||
c_warnings.onceregistry.clear()
|
c_warnings.onceregistry.clear()
|
||||||
test_support.run_unittest(CFilterTests,
|
test_support.run_unittest(CFilterTests, PyFilterTests,
|
||||||
PyFilterTests,
|
CWarnTests, PyWarnTests,
|
||||||
CWarnTests,
|
|
||||||
PyWarnTests,
|
|
||||||
CWCmdLineTests, PyWCmdLineTests,
|
CWCmdLineTests, PyWCmdLineTests,
|
||||||
_WarningsTests,
|
_WarningsTests,
|
||||||
CWarningsDisplayTests, PyWarningsDisplayTests,
|
CWarningsDisplayTests, PyWarningsDisplayTests,
|
||||||
CWarningsSupportTests, PyWarningsSupportTests,
|
CCatchWarningTests, PyCatchWarningTests,
|
||||||
CShowwarningDeprecationTests,
|
CShowwarningDeprecationTests,
|
||||||
PyShowwarningDeprecationTests,
|
PyShowwarningDeprecationTests,
|
||||||
)
|
)
|
||||||
|
|
|
@ -272,7 +272,8 @@ def warn_explicit(message, category, filename, lineno,
|
||||||
fxn_code = showwarning.__func__.func_code
|
fxn_code = showwarning.__func__.func_code
|
||||||
if fxn_code:
|
if fxn_code:
|
||||||
args = fxn_code.co_varnames[:fxn_code.co_argcount]
|
args = fxn_code.co_varnames[:fxn_code.co_argcount]
|
||||||
if 'line' not in args:
|
CO_VARARGS = 0x4
|
||||||
|
if 'line' not in args and not fxn_code.co_flags & CO_VARARGS:
|
||||||
showwarning_msg = ("functions overriding warnings.showwarning() "
|
showwarning_msg = ("functions overriding warnings.showwarning() "
|
||||||
"must support the 'line' argument")
|
"must support the 'line' argument")
|
||||||
if message == showwarning_msg:
|
if message == showwarning_msg:
|
||||||
|
@ -283,6 +284,78 @@ def warn_explicit(message, category, filename, lineno,
|
||||||
showwarning(message, category, filename, lineno)
|
showwarning(message, category, filename, lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class WarningMessage(object):
|
||||||
|
|
||||||
|
"""Holds the result of a single showwarning() call."""
|
||||||
|
|
||||||
|
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
|
||||||
|
"line")
|
||||||
|
|
||||||
|
def __init__(self, message, category, filename, lineno, file=None,
|
||||||
|
line=None):
|
||||||
|
local_values = locals()
|
||||||
|
for attr in self._WARNING_DETAILS:
|
||||||
|
setattr(self, attr, local_values[attr])
|
||||||
|
self._category_name = category.__name__ if category else None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ("{message : %r, category : %r, filename : %r, lineno : %s, "
|
||||||
|
"line : %r}" % (self.message, self._category_name,
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, record=False, module=None):
|
||||||
|
"""Specify whether to record warnings and if an alternative module
|
||||||
|
should be used other than sys.modules['warnings'].
|
||||||
|
|
||||||
|
For compatibility with Python 3.0, please consider all arguments to be
|
||||||
|
keyword-only.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._recorder = WarningsRecorder() if record else None
|
||||||
|
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
|
||||||
|
|
||||||
|
def __exit__(self, *exc_info):
|
||||||
|
self._module.filters = self._filters
|
||||||
|
self._module.showwarning = self._showwarning
|
||||||
|
|
||||||
|
|
||||||
# filters contains a sequence of filter 5-tuples
|
# filters contains a sequence of filter 5-tuples
|
||||||
# The components of the 5-tuple are:
|
# The components of the 5-tuple are:
|
||||||
# - an action: error, ignore, always, default, module, or once
|
# - an action: error, ignore, always, default, module, or once
|
||||||
|
|
|
@ -53,6 +53,11 @@ C-API
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue 3602: Moved test.test_support.catch_warning() to
|
||||||
|
warnings.catch_warnings() along with some API cleanup. Expanding the tests
|
||||||
|
for catch_warnings() also led to an improvement in the raising of a
|
||||||
|
DeprecationWarning related to warnings.warn_explicit().
|
||||||
|
|
||||||
- The deprecation warnings for the old camelCase threading API were removed.
|
- The deprecation warnings for the old camelCase threading API were removed.
|
||||||
|
|
||||||
- logging: fixed lack of use of encoding attribute specified on a stream.
|
- logging: fixed lack of use of encoding attribute specified on a stream.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "code.h" /* For DeprecationWarning about adding 'line'. */
|
||||||
#include "frameobject.h"
|
#include "frameobject.h"
|
||||||
|
|
||||||
#define MODULE_NAME "_warnings"
|
#define MODULE_NAME "_warnings"
|
||||||
|
@ -416,11 +417,16 @@ warn_explicit(PyObject *category, PyObject *message,
|
||||||
/* A proper implementation of warnings.showwarning() should
|
/* A proper implementation of warnings.showwarning() should
|
||||||
have at least two default arguments. */
|
have at least two default arguments. */
|
||||||
if ((defaults == NULL) || (PyTuple_Size(defaults) < 2)) {
|
if ((defaults == NULL) || (PyTuple_Size(defaults) < 2)) {
|
||||||
if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1) < 0) {
|
PyCodeObject *code = (PyCodeObject *)
|
||||||
|
PyFunction_GetCode(check_fxn);
|
||||||
|
if (!(code->co_flags & CO_VARARGS)) {
|
||||||
|
if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1) <
|
||||||
|
0) {
|
||||||
Py_DECREF(show_fxn);
|
Py_DECREF(show_fxn);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
|
res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
|
||||||
filename, lineno_obj,
|
filename, lineno_obj,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue