summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorent Xicluna <florent.xicluna@gmail.com>2010-03-13 15:26:44 (GMT)
committerFlorent Xicluna <florent.xicluna@gmail.com>2010-03-13 15:26:44 (GMT)
commitb14930cd93e74cae3b7370262c6dcc7c28e0e712 (patch)
treedaca91cb5ed347957f3ad629ff9be93f0f1af4a4
parent8142d8d7515b10cfc10fc332fcce34bac1e6d52e (diff)
downloadcpython-b14930cd93e74cae3b7370262c6dcc7c28e0e712.zip
cpython-b14930cd93e74cae3b7370262c6dcc7c28e0e712.tar.gz
cpython-b14930cd93e74cae3b7370262c6dcc7c28e0e712.tar.bz2
Only the parts which are relevant for 3.x branch.
Merged revisions 78757-78758,78769,78815 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r78757 | florent.xicluna | 2010-03-07 13:14:25 +0100 (dim, 07 mar 2010) | 2 lines Fix some py3k warnings in the standard library. ........ r78758 | florent.xicluna | 2010-03-07 13:18:33 +0100 (dim, 07 mar 2010) | 4 lines Issue #7849: Now the utility ``check_warnings`` verifies if the warnings are effectively raised. A new utility ``check_py3k_warnings`` deals with py3k warnings. ........ r78769 | florent.xicluna | 2010-03-07 20:14:12 +0100 (dim, 07 mar 2010) | 2 lines Refresh the documentation for the test.test_support module. ........ r78815 | florent.xicluna | 2010-03-09 20:57:01 +0100 (mar, 09 mar 2010) | 2 lines #7772: Fix test_py3kwarn. Now the test suite could pass with "-3" flag. ........
-rw-r--r--Doc/library/test.rst64
-rw-r--r--Lib/_pyio.py15
-rw-r--r--Lib/test/support.py72
-rw-r--r--Lib/test/test_fileio.py2
-rw-r--r--Misc/NEWS3
5 files changed, 122 insertions, 34 deletions
diff --git a/Doc/library/test.rst b/Doc/library/test.rst
index cc7ff4d..d8dd46c 100644
--- a/Doc/library/test.rst
+++ b/Doc/library/test.rst
@@ -130,13 +130,13 @@ guidelines to be followed:
self.func(self.arg)
class AcceptLists(TestFuncAcceptsSequences):
- arg = [1,2,3]
+ arg = [1, 2, 3]
class AcceptStrings(TestFuncAcceptsSequences):
arg = 'abc'
class AcceptTuples(TestFuncAcceptsSequences):
- arg = (1,2,3)
+ arg = (1, 2, 3)
.. seealso::
@@ -198,16 +198,9 @@ This module defines the following exceptions:
methods.
-.. exception:: TestSkipped
-
- Subclass of :exc:`TestFailed`. Raised when a test is skipped. This occurs when a
- needed resource (such as a network connection) is not available at the time of
- testing.
-
-
.. exception:: ResourceDenied
- Subclass of :exc:`TestSkipped`. Raised when a resource (such as a network
+ Subclass of :exc:`unittest.SkipTest`. Raised when a resource (such as a network
connection) is not available. Raised by the :func:`requires` function.
The :mod:`test.support` module defines the following constants:
@@ -227,7 +220,7 @@ The :mod:`test.support` module defines the following constants:
.. data:: TESTFN
- Set to the path that a temporary file may be created at. Any temporary that is
+ Set to the name that a temporary file could use. Any temporary file that is
created should be closed and unlinked (removed).
The :mod:`test.support` module defines the following functions:
@@ -235,21 +228,21 @@ The :mod:`test.support` module defines the following functions:
.. function:: forget(module_name)
- Removes the module named *module_name* from ``sys.modules`` and deletes any
+ Remove the module named *module_name* from ``sys.modules`` and deletes any
byte-compiled files of the module.
.. function:: is_resource_enabled(resource)
- Returns :const:`True` if *resource* is enabled and available. The list of
+ Return :const:`True` if *resource* is enabled and available. The list of
available resources is only set when :mod:`test.regrtest` is executing the
tests.
.. function:: requires(resource, msg=None)
- Raises :exc:`ResourceDenied` if *resource* is not available. *msg* is the
- argument to :exc:`ResourceDenied` if it is raised. Always returns true if called
+ Raise :exc:`ResourceDenied` if *resource* is not available. *msg* is the
+ argument to :exc:`ResourceDenied` if it is raised. Always returns True if called
by a function whose ``__name__`` is ``'__main__'``. Used when tests are executed
by :mod:`test.regrtest`.
@@ -277,14 +270,24 @@ The :mod:`test.support` module defines the following functions:
This will run all tests defined in the named module.
-.. function:: check_warnings()
+.. function:: check_warnings(*filters, quiet=False)
A convenience wrapper for ``warnings.catch_warnings()`` that makes
it easier to test that a warning was correctly raised with a single
assertion. It is approximately equivalent to calling
``warnings.catch_warnings(record=True)``.
- The main difference is that on entry to the context manager, a
+ It accepts 2-tuples ``("message regexp", WarningCategory)`` as positional
+ arguments. When the optional keyword argument ``quiet`` is True, it does
+ not fail if a filter catches nothing. Without argument, it defaults to::
+
+ check_warnings(("", Warning), quiet=False)
+
+ The main difference is that it verifies the warnings raised. If some filter
+ did not catch any warning, the test fails. If some warnings are not caught,
+ the test fails, too. To disable these checks, use argument ``quiet=True``.
+
+ Another significant difference is that on entry to the context manager, a
:class:`WarningRecorder` instance is returned instead of a simple list.
The underlying warnings list is available via the recorder object's
:attr:`warnings` attribute, while the attributes of the last raised
@@ -294,19 +297,34 @@ The :mod:`test.support` module defines the following functions:
A :meth:`reset` method is also provided on the recorder object. This
method simply clears the warning list.
- The context manager is used like this::
+ The context manager may be used like this::
+
+ import warnings
+
+ with check_warnings():
+ exec('assert(False, "Hey!")')
+ warnings.warn(UserWarning("Hide me!"))
- with check_warnings() as w:
+ with check_warnings(("assertion is always true", SyntaxWarning),
+ ("", UserWarning)):
+ exec('assert(False, "Hey!")')
+ warnings.warn(UserWarning("Hide me!"))
+
+ with check_warnings(quiet=True) as w:
warnings.simplefilter("always")
warnings.warn("foo")
- assert str(w.message) == "foo"
+ assert str(w.args[0]) == "foo"
warnings.warn("bar")
- assert str(w.message) == "bar"
- assert str(w.warnings[0].message) == "foo"
- assert str(w.warnings[1].message) == "bar"
+ assert str(w.args[0]) == "bar"
+ assert str(w.warnings[0].args[0]) == "foo"
+ assert str(w.warnings[1].args[0]) == "bar"
w.reset()
assert len(w.warnings) == 0
+ .. versionchanged:: 2.7
+ The test fails when the context manager do not catch any warning.
+ New optional attributes ``*filters`` and ``quiet``.
+
.. function:: captured_stdout()
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index 8960ce9..c58548e 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -828,7 +828,7 @@ class BytesIO(BufferedIOBase):
if self.closed:
raise ValueError("seek on closed file")
try:
- pos = pos.__index__()
+ pos.__index__
except AttributeError as err:
raise TypeError("an integer is required") from err
if whence == 0:
@@ -853,8 +853,13 @@ class BytesIO(BufferedIOBase):
raise ValueError("truncate on closed file")
if pos is None:
pos = self._pos
- elif pos < 0:
- raise ValueError("negative truncate position %r" % (pos,))
+ else:
+ try:
+ pos.__index__
+ except AttributeError as err:
+ raise TypeError("an integer is required") from err
+ if pos < 0:
+ raise ValueError("negative truncate position %r" % (pos,))
del self._buffer[pos:]
return pos
@@ -1803,6 +1808,10 @@ class TextIOWrapper(TextIOBase):
if n is None:
n = -1
decoder = self._decoder or self._get_decoder()
+ try:
+ n.__index__
+ except AttributeError as err:
+ raise TypeError("an integer is required") from err
if n < 0:
# Read everything.
result = (self._get_decoded_chars() +
diff --git a/Lib/test/support.py b/Lib/test/support.py
index bf49bab..769f94a 100644
--- a/Lib/test/support.py
+++ b/Lib/test/support.py
@@ -16,6 +16,7 @@ import warnings
import unittest
import importlib
import collections
+import re
__all__ = ["Error", "TestFailed", "ResourceDenied", "import_module",
"verbose", "use_resources", "max_memuse", "record_original_stdout",
@@ -464,22 +465,80 @@ class WarningsRecorder(object):
entry to the warnings.catch_warnings() context manager.
"""
def __init__(self, warnings_list):
- self.warnings = warnings_list
+ self._warnings = warnings_list
+ self._last = 0
def __getattr__(self, attr):
- if self.warnings:
- return getattr(self.warnings[-1], attr)
+ if len(self._warnings) > self._last:
+ return getattr(self._warnings[-1], attr)
elif attr in warnings.WarningMessage._WARNING_DETAILS:
return None
raise AttributeError("%r has no attribute %r" % (self, attr))
+ @property
+ def warnings(self):
+ return self._warnings[self._last:]
+
def reset(self):
- del self.warnings[:]
+ self._last = len(self._warnings)
-@contextlib.contextmanager
-def check_warnings():
+
+def _filterwarnings(filters, quiet=False):
+ """Catch the warnings, then check if all the expected
+ warnings have been raised and re-raise unexpected warnings.
+ If 'quiet' is True, only re-raise the unexpected warnings.
+ """
+ # Clear the warning registry of the calling module
+ # in order to re-raise the warnings.
+ frame = sys._getframe(2)
+ registry = frame.f_globals.get('__warningregistry__')
+ if registry:
+ registry.clear()
with warnings.catch_warnings(record=True) as w:
+ # Set filter "always" to record all warnings. Because
+ # test_warnings swap the module, we need to look up in
+ # the sys.modules dictionary.
+ sys.modules['warnings'].simplefilter("always")
yield WarningsRecorder(w)
+ # Filter the recorded warnings
+ reraise = [warning.message for warning in w]
+ missing = []
+ for msg, cat in filters:
+ seen = False
+ for exc in reraise[:]:
+ message = str(exc)
+ # Filter out the matching messages
+ if (re.match(msg, message, re.I) and
+ issubclass(exc.__class__, cat)):
+ seen = True
+ reraise.remove(exc)
+ if not seen and not quiet:
+ # This filter caught nothing
+ missing.append((msg, cat.__name__))
+ if reraise:
+ raise AssertionError("unhandled warning %r" % reraise[0])
+ if missing:
+ raise AssertionError("filter (%r, %s) did not catch any warning" %
+ missing[0])
+
+
+@contextlib.contextmanager
+def check_warnings(*filters, **kwargs):
+ """Context manager to silence warnings.
+
+ Accept 2-tuples as positional arguments:
+ ("message regexp", WarningCategory)
+
+ Optional argument:
+ - if 'quiet' is True, it does not fail if a filter catches nothing
+ (default False)
+
+ Without argument, it defaults to:
+ check_warnings(("", Warning), quiet=False)
+ """
+ if not filters:
+ filters = (("", Warning),)
+ return _filterwarnings(filters, kwargs.get('quiet'))
class CleanImport(object):
@@ -714,7 +773,6 @@ _4G = 4 * _1G
MAX_Py_ssize_t = sys.maxsize
def set_memlimit(limit):
- import re
global max_memuse
global real_max_memuse
sizes = {
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index 8348f6e..fd27512 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -390,7 +390,7 @@ class OtherFileTests(unittest.TestCase):
self.assertRaises(TypeError, _FileIO, "1", 0, 0)
def testWarnings(self):
- with check_warnings() as w:
+ with check_warnings(quiet=True) as w:
self.assertEqual(w.warnings, [])
self.assertRaises(TypeError, _FileIO, [])
self.assertEqual(w.warnings, [])
diff --git a/Misc/NEWS b/Misc/NEWS
index e40100b..14d27f1 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -869,6 +869,9 @@ Documentation
Tests
-----
+- Issue #7849: Now the utility ``check_warnings`` verifies if the warnings are
+ effectively raised.
+
- The four path modules (genericpath, macpath, ntpath, posixpath) share a
common TestCase for some tests: test_genericpath.CommonTest.