bpo-35798: Add test.support.check_syntax_warning(). (#11895)
It checks that a SyntaxWarning is raised when compile specified statement, that it is raised only once, that it is converted to a SyntaxError when raised as exception, and that both warning and exception objects have corresponding attributes.
This commit is contained in:
parent
ee0f927bd8
commit
e7a4bb554e
|
@ -936,9 +936,24 @@ The :mod:`test.support` module defines the following functions:
|
|||
|
||||
Test for syntax errors in *statement* by attempting to compile *statement*.
|
||||
*testcase* is the :mod:`unittest` instance for the test. *errtext* is the
|
||||
text of the error raised by :exc:`SyntaxError`. If *lineno* is not None,
|
||||
compares to the line of the :exc:`SyntaxError`. If *offset* is not None,
|
||||
compares to the offset of the :exc:`SyntaxError`.
|
||||
regular expression which should match the string representation of the
|
||||
raised :exc:`SyntaxError`. If *lineno* is not ``None``, compares to
|
||||
the line of the exception. If *offset* is not ``None``, compares to
|
||||
the offset of the exception.
|
||||
|
||||
|
||||
.. function:: check_syntax_warning(testcase, statement, errtext='', *, lineno=1, offset=None)
|
||||
|
||||
Test for syntax warning in *statement* by attempting to compile *statement*.
|
||||
Test also that the :exc:`SyntaxWarning` is emitted only once, and that it
|
||||
will be converted to a :exc:`SyntaxError` when turned into error.
|
||||
*testcase* is the :mod:`unittest` instance for the test. *errtext* is the
|
||||
regular expression which should match the string representation of the
|
||||
emitted :exc:`SyntaxWarning` and raised :exc:`SyntaxError`. If *lineno*
|
||||
is not ``None``, compares to the line of the warning and exception.
|
||||
If *offset* is not ``None``, compares to the offset of the exception.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. function:: open_urlresource(url, *args, **kw)
|
||||
|
|
|
@ -86,6 +86,7 @@ __all__ = [
|
|||
# unittest
|
||||
"is_resource_enabled", "requires", "requires_freebsd_version",
|
||||
"requires_linux_version", "requires_mac_ver", "check_syntax_error",
|
||||
"check_syntax_warning",
|
||||
"TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset",
|
||||
"transient_internet", "BasicTestRunner", "run_unittest", "run_doctest",
|
||||
"skip_unless_symlink", "requires_gzip", "requires_bz2", "requires_lzma",
|
||||
|
@ -1113,6 +1114,7 @@ def make_bad_fd():
|
|||
file.close()
|
||||
unlink(TESTFN)
|
||||
|
||||
|
||||
def check_syntax_error(testcase, statement, errtext='', *, lineno=None, offset=None):
|
||||
with testcase.assertRaisesRegex(SyntaxError, errtext) as cm:
|
||||
compile(statement, '<test string>', 'exec')
|
||||
|
@ -1124,6 +1126,33 @@ def check_syntax_error(testcase, statement, errtext='', *, lineno=None, offset=N
|
|||
if offset is not None:
|
||||
testcase.assertEqual(err.offset, offset)
|
||||
|
||||
def check_syntax_warning(testcase, statement, errtext='', *, lineno=1, offset=None):
|
||||
# Test also that a warning is emitted only once.
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('always', SyntaxWarning)
|
||||
compile(statement, '<testcase>', 'exec')
|
||||
testcase.assertEqual(len(warns), 1, warns)
|
||||
|
||||
warn, = warns
|
||||
testcase.assertTrue(issubclass(warn.category, SyntaxWarning), warn.category)
|
||||
if errtext:
|
||||
testcase.assertRegex(str(warn.message), errtext)
|
||||
testcase.assertEqual(warn.filename, '<testcase>')
|
||||
testcase.assertIsNotNone(warn.lineno)
|
||||
if lineno is not None:
|
||||
testcase.assertEqual(warn.lineno, lineno)
|
||||
|
||||
# SyntaxWarning should be converted to SyntaxError when raised,
|
||||
# since the latter contains more information and provides better
|
||||
# error report.
|
||||
with warnings.catch_warnings(record=True) as warns:
|
||||
warnings.simplefilter('error', SyntaxWarning)
|
||||
check_syntax_error(testcase, statement, errtext,
|
||||
lineno=lineno, offset=offset)
|
||||
# No warnings are leaked when a SyntaxError is raised.
|
||||
testcase.assertEqual(warns, [])
|
||||
|
||||
|
||||
def open_urlresource(url, *args, **kw):
|
||||
import urllib.request, urllib.parse
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Python test set -- part 1, grammar.
|
||||
# This just tests whether the parser accepts them all.
|
||||
|
||||
from test.support import check_syntax_error
|
||||
from test.support import check_syntax_error, check_syntax_warning
|
||||
import inspect
|
||||
import unittest
|
||||
import sys
|
||||
|
@ -101,7 +101,7 @@ INVALID_UNDERSCORE_LITERALS = [
|
|||
|
||||
class TokenTests(unittest.TestCase):
|
||||
|
||||
check_syntax_error = check_syntax_error
|
||||
from test.support import check_syntax_error
|
||||
|
||||
def test_backslash(self):
|
||||
# Backslash means line continuation:
|
||||
|
@ -276,7 +276,7 @@ class CNS:
|
|||
|
||||
class GrammarTests(unittest.TestCase):
|
||||
|
||||
check_syntax_error = check_syntax_error
|
||||
from test.support import check_syntax_error, check_syntax_warning
|
||||
|
||||
# single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
|
||||
# XXX can't test in a script -- this rule is only used when interactive
|
||||
|
@ -1109,12 +1109,10 @@ class GrammarTests(unittest.TestCase):
|
|||
else:
|
||||
self.fail("AssertionError not raised by 'assert False'")
|
||||
|
||||
with self.assertWarnsRegex(SyntaxWarning, 'assertion is always true'):
|
||||
compile('assert(x, "msg")', '<testcase>', 'exec')
|
||||
self.check_syntax_warning('assert(x, "msg")',
|
||||
'assertion is always true')
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error', category=SyntaxWarning)
|
||||
with self.assertRaisesRegex(SyntaxError, 'assertion is always true'):
|
||||
compile('assert(x, "msg")', '<testcase>', 'exec')
|
||||
warnings.simplefilter('error', SyntaxWarning)
|
||||
compile('assert x, "msg"', '<testcase>', 'exec')
|
||||
|
||||
|
||||
|
@ -1243,12 +1241,7 @@ class GrammarTests(unittest.TestCase):
|
|||
|
||||
def test_comparison_is_literal(self):
|
||||
def check(test, msg='"is" with a literal'):
|
||||
with self.assertWarnsRegex(SyntaxWarning, msg):
|
||||
compile(test, '<testcase>', 'exec')
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error', category=SyntaxWarning)
|
||||
with self.assertRaisesRegex(SyntaxError, msg):
|
||||
compile(test, '<testcase>', 'exec')
|
||||
self.check_syntax_warning(test, msg)
|
||||
|
||||
check('x is 1')
|
||||
check('x is "thing"')
|
||||
|
@ -1257,7 +1250,7 @@ class GrammarTests(unittest.TestCase):
|
|||
check('x is not 1', '"is not" with a literal')
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error', category=SyntaxWarning)
|
||||
warnings.simplefilter('error', SyntaxWarning)
|
||||
compile('x is None', '<testcase>', 'exec')
|
||||
compile('x is False', '<testcase>', 'exec')
|
||||
compile('x is True', '<testcase>', 'exec')
|
||||
|
@ -1265,12 +1258,7 @@ class GrammarTests(unittest.TestCase):
|
|||
|
||||
def test_warn_missed_comma(self):
|
||||
def check(test):
|
||||
with self.assertWarnsRegex(SyntaxWarning, msg):
|
||||
compile(test, '<testcase>', 'exec')
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error', category=SyntaxWarning)
|
||||
with self.assertRaisesRegex(SyntaxError, msg):
|
||||
compile(test, '<testcase>', 'exec')
|
||||
self.check_syntax_warning(test, msg)
|
||||
|
||||
msg=r'is not callable; perhaps you missed a comma\?'
|
||||
check('[(1, 2) (3, 4)]')
|
||||
|
@ -1342,7 +1330,7 @@ class GrammarTests(unittest.TestCase):
|
|||
check('[[1, 2] [...]]')
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error', category=SyntaxWarning)
|
||||
warnings.simplefilter('error', SyntaxWarning)
|
||||
compile('[(lambda x, y: x) (3, 4)]', '<testcase>', 'exec')
|
||||
compile('[[1, 2] [i]]', '<testcase>', 'exec')
|
||||
compile('[[1, 2] [0]]', '<testcase>', 'exec')
|
||||
|
|
|
@ -63,6 +63,8 @@ def byte(i):
|
|||
|
||||
class TestLiterals(unittest.TestCase):
|
||||
|
||||
from test.support import check_syntax_warning
|
||||
|
||||
def setUp(self):
|
||||
self.save_path = sys.path[:]
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
|
@ -112,21 +114,7 @@ class TestLiterals(unittest.TestCase):
|
|||
with self.assertWarns(SyntaxWarning):
|
||||
self.assertEqual(eval(r"'\%c'" % b), '\\' + chr(b))
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always', category=SyntaxWarning)
|
||||
eval("'''\n\\z'''")
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertEqual(w[0].filename, '<string>')
|
||||
self.assertEqual(w[0].lineno, 1)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('error', category=SyntaxWarning)
|
||||
with self.assertRaises(SyntaxError) as cm:
|
||||
eval("'''\n\\z'''")
|
||||
exc = cm.exception
|
||||
self.assertEqual(w, [])
|
||||
self.assertEqual(exc.filename, '<string>')
|
||||
self.assertEqual(exc.lineno, 1)
|
||||
self.check_syntax_warning("'''\n\\z'''")
|
||||
|
||||
def test_eval_str_raw(self):
|
||||
self.assertEqual(eval(""" r'x' """), 'x')
|
||||
|
@ -161,21 +149,7 @@ class TestLiterals(unittest.TestCase):
|
|||
with self.assertWarns(SyntaxWarning):
|
||||
self.assertEqual(eval(r"b'\%c'" % b), b'\\' + bytes([b]))
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always', category=SyntaxWarning)
|
||||
eval("b'''\n\\z'''")
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertEqual(w[0].filename, '<string>')
|
||||
self.assertEqual(w[0].lineno, 1)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('error', category=SyntaxWarning)
|
||||
with self.assertRaises(SyntaxError) as cm:
|
||||
eval("b'''\n\\z'''")
|
||||
exc = cm.exception
|
||||
self.assertEqual(w, [])
|
||||
self.assertEqual(exc.filename, '<string>')
|
||||
self.assertEqual(exc.lineno, 1)
|
||||
self.check_syntax_warning("b'''\n\\z'''")
|
||||
|
||||
def test_eval_bytes_raw(self):
|
||||
self.assertEqual(eval(""" br'x' """), b'x')
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Added :func:`test.support.check_syntax_warning`.
|
Loading…
Reference in New Issue