From 5d4c998bfe1f938ece20c9a24a887154969ccae1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 6 Aug 2019 14:04:07 +0300 Subject: [PATCH 1/3] bpo-32912: Revert warnings for invalid escape sequences. DeprecationWarning will continue to be emitted for invalid escape sequences in string and bytes literals in 3.8. SyntaxWarning will be emitted in 3.9. --- Doc/reference/lexical_analysis.rst | 7 +--- Doc/whatsnew/3.8.rst | 5 --- Lib/test/test_fstring.py | 2 +- Lib/test/test_string_literals.py | 37 +++++++++++++++++-- .../2019-08-06-14-03-59.bpo-32912.UDwSMJ.rst | 3 ++ Python/ast.c | 6 +-- 6 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-08-06-14-03-59.bpo-32912.UDwSMJ.rst diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index cc1b2f57a70e3b..10cb5e4baf24f5 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -594,11 +594,8 @@ escape sequences only recognized in string literals fall into the category of unrecognized escapes for bytes literals. .. versionchanged:: 3.6 - Unrecognized escape sequences produce a :exc:`DeprecationWarning`. - - .. versionchanged:: 3.8 - Unrecognized escape sequences produce a :exc:`SyntaxWarning`. In - some future version of Python they will be a :exc:`SyntaxError`. + Unrecognized escape sequences produce a DeprecationWarning. In + Python 3.9 they will be a SyntaxError. Even in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result; for example, ``r"\""`` is a valid string diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 9f70582745147b..83caa2cc5abc43 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -414,11 +414,6 @@ Other Language Changes and :keyword:`return` statements. (Contributed by David Cuthbert and Jordan Chapman in :issue:`32117`.) -* A backslash-character pair that is not a valid escape sequence generates - a :exc:`DeprecationWarning` since Python 3.6. In Python 3.8 it generates - a :exc:`SyntaxWarning` instead. - (Contributed by Serhiy Storchaka in :issue:`32912`.) - * The compiler now produces a :exc:`SyntaxWarning` in some cases when a comma is missed before tuple or list. For example:: diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index fb761441fcee5c..49663923e7f5aa 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -649,7 +649,7 @@ def test_backslashes_in_string_part(self): self.assertEqual(f'2\x203', '2 3') self.assertEqual(f'\x203', ' 3') - with self.assertWarns(SyntaxWarning): # invalid escape sequence + with self.assertWarns(DeprecationWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') self.assertEqual(f'\\{6*7}', '\\42') diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py index 5961d591c44803..0cea2edc32afa2 100644 --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -32,6 +32,7 @@ import shutil import tempfile import unittest +import warnings TEMPLATE = r"""# coding: %s @@ -110,10 +111,24 @@ def test_eval_str_invalid_escape(self): for b in range(1, 128): if b in b"""\n\r"'01234567NU\\abfnrtuvx""": continue - with self.assertWarns(SyntaxWarning): + with self.assertWarns(DeprecationWarning): self.assertEqual(eval(r"'\%c'" % b), '\\' + chr(b)) - self.check_syntax_warning("'''\n\\z'''") + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('error', category=DeprecationWarning) + with self.assertRaises(SyntaxError) as cm: + eval("'''\n\\z'''") + exc = cm.exception + self.assertEqual(w, []) + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) def test_eval_str_raw(self): self.assertEqual(eval(""" r'x' """), 'x') @@ -145,10 +160,24 @@ def test_eval_bytes_invalid_escape(self): for b in range(1, 128): if b in b"""\n\r"'01234567\\abfnrtvx""": continue - with self.assertWarns(SyntaxWarning): + with self.assertWarns(DeprecationWarning): self.assertEqual(eval(r"b'\%c'" % b), b'\\' + bytes([b])) - self.check_syntax_warning("b'''\n\\z'''") + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=DeprecationWarning) + eval("b'''\n\\z'''") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('error', category=DeprecationWarning) + with self.assertRaises(SyntaxError) as cm: + eval("b'''\n\\z'''") + exc = cm.exception + self.assertEqual(w, []) + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) def test_eval_bytes_raw(self): self.assertEqual(eval(""" br'x' """), b'x') diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-08-06-14-03-59.bpo-32912.UDwSMJ.rst b/Misc/NEWS.d/next/Core and Builtins/2019-08-06-14-03-59.bpo-32912.UDwSMJ.rst new file mode 100644 index 00000000000000..e18d8adfbee9e6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-08-06-14-03-59.bpo-32912.UDwSMJ.rst @@ -0,0 +1,3 @@ +Reverted :issue:`32912`: emitting :exc:`SyntaxWarning` instead of +:exc:`DeprecationWarning` for invalid escape sequences in string and bytes +literals. diff --git a/Python/ast.c b/Python/ast.c index f6c2049ae2cfdf..9947824de7446c 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -4674,12 +4674,12 @@ warn_invalid_escape_sequence(struct compiling *c, const node *n, if (msg == NULL) { return -1; } - if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, + if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, c->c_filename, LINENO(n), NULL, NULL) < 0) { - if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { - /* Replace the SyntaxWarning exception with a SyntaxError + if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { + /* Replace the DeprecationWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); ast_error(c, n, "%U", msg); From 1775d3f935670f440e829c80d172470cf0fdc406 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 7 Aug 2019 09:34:42 +0300 Subject: [PATCH 2/3] Fix a typo. --- Doc/reference/lexical_analysis.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 10cb5e4baf24f5..204b9a504c98f3 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -594,8 +594,8 @@ escape sequences only recognized in string literals fall into the category of unrecognized escapes for bytes literals. .. versionchanged:: 3.6 - Unrecognized escape sequences produce a DeprecationWarning. In - Python 3.9 they will be a SyntaxError. + Unrecognized escape sequences produce a :exc:`DeprecationWarning`. In + Python 3.9 they will be a :exc:`SyntaxWarning`. Even in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result; for example, ``r"\""`` is a valid string From 3f58e3fc8d6e3da46b33ed65308d1a376fd69211 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 8 Aug 2019 15:09:27 -0700 Subject: [PATCH 3/3] update the wording to not promise 3.9 and mention that SyntaxError will happen after SyntaxWarning. we're being non-specific on purpose here as we haven't worked out the plan to make this happen without causing end user pain yet. right now most code owners do not see the DeprecationWarning but when turned into a SyntaxWarning, _users_ of libraries see it more often than owners. So it is a negative experience all around. --- Doc/reference/lexical_analysis.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 204b9a504c98f3..7e1e17edb2d8da 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -595,7 +595,8 @@ unrecognized escapes for bytes literals. .. versionchanged:: 3.6 Unrecognized escape sequences produce a :exc:`DeprecationWarning`. In - Python 3.9 they will be a :exc:`SyntaxWarning`. + a future Python version they will be a :exc:`SyntaxWarning` and + eventually a :exc:`SyntaxError`. Even in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result; for example, ``r"\""`` is a valid string