From aa576a5d8c295b2d53f8060deb1a25e2b5742f3c Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Wed, 8 Feb 2023 00:46:56 -0500 Subject: [PATCH 01/14] Renamed re.error for clarity, and kept re.error for backward compatibility. Co-authored-by: Matthias Bussonnier --- Doc/library/re.rst | 14 ++++-- Lib/idlelib/searchengine.py | 2 +- Lib/pstats.py | 2 +- Lib/re/__init__.py | 7 +-- Lib/test/test_re.py | 47 ++++++++++--------- ...3-02-08-00-43-29.gh-issue-83162.ufdI9F.rst | 3 ++ Modules/_xxtestfuzz/fuzzer.c | 6 +-- 7 files changed, 46 insertions(+), 35 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst diff --git a/Doc/library/re.rst b/Doc/library/re.rst index b7510b93d75427..ce10ae39ecc22a 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1080,13 +1080,13 @@ Functions Exceptions ^^^^^^^^^^ -.. exception:: error(msg, pattern=None, pos=None) +.. exception:: ReCompileError(msg, pattern=None, pos=None) Exception raised when a string passed to one of the functions here is not a - valid regular expression (for example, it might contain unmatched parentheses) - or when some other error occurs during compilation or matching. It is never an - error if a string contains no match for a pattern. The error instance has - the following additional attributes: + valid regular expression (for example, it might contain unmatched + parentheses) or when some other error occurs during compilation or matching. + It is never an error if a string contains no match for a pattern. The + ``ReCompileError`` instance has the following additional attributes: .. attribute:: msg @@ -1111,6 +1111,10 @@ Exceptions .. versionchanged:: 3.5 Added additional attributes. + .. versionchanged:: 3.12 + ``ReCompileError`` was originally named ``error``; the latter is kept as an alias for + backward compatibility. + .. _re-objects: Regular Expression Objects diff --git a/Lib/idlelib/searchengine.py b/Lib/idlelib/searchengine.py index 0684142f43644a..6b998f63b07efe 100644 --- a/Lib/idlelib/searchengine.py +++ b/Lib/idlelib/searchengine.py @@ -84,7 +84,7 @@ def getprog(self): flags = flags | re.IGNORECASE try: prog = re.compile(pat, flags) - except re.error as e: + except re.ReCompileError as e: self.report_error(pat, e.msg, e.pos) return None return prog diff --git a/Lib/pstats.py b/Lib/pstats.py index 51bcca84188740..045930e89f8d7e 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -329,7 +329,7 @@ def eval_print_amount(self, sel, list, msg): if isinstance(sel, str): try: rex = re.compile(sel) - except re.error: + except re.ReCompileError: msg += " \n" % sel return new_list, msg new_list = [] diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index 4515650a721ac6..6cf09b31a4e7b0 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -117,7 +117,8 @@ U UNICODE For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns. -This module also defines an exception 'error'. +This module also defines exception 'ReCompileError', aliased to 'error' for +backward compatibility. """ @@ -133,7 +134,7 @@ "findall", "finditer", "compile", "purge", "template", "escape", "error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE", - "UNICODE", "NOFLAG", "RegexFlag", + "UNICODE", "NOFLAG", "RegexFlag", "ReCompileError" ] __version__ = "2.2.1" @@ -156,7 +157,7 @@ class RegexFlag: _numeric_repr_ = hex # sre exception -error = _compiler.error +ReCompileError = error = sre_compile.ReCompileError # -------------------------------------------------------------------- # public interface diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 11628a236ade9a..593b40c65effdf 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -47,7 +47,7 @@ def recurse(actual, expect): recurse(actual, expect) def checkPatternError(self, pattern, errmsg, pos=None): - with self.assertRaises(re.error) as cm: + with self.assertRaises(re.ReCompileError) as cm: re.compile(pattern) with self.subTest(pattern=pattern): err = cm.exception @@ -56,7 +56,7 @@ def checkPatternError(self, pattern, errmsg, pos=None): self.assertEqual(err.pos, pos) def checkTemplateError(self, pattern, repl, string, errmsg, pos=None): - with self.assertRaises(re.error) as cm: + with self.assertRaises(re.ReCompileError) as cm: re.sub(pattern, repl, string) with self.subTest(pattern=pattern, repl=repl): err = cm.exception @@ -64,6 +64,9 @@ def checkTemplateError(self, pattern, repl, string, errmsg, pos=None): if pos is not None: self.assertEqual(err.pos, pos) + def test_error_is_ReCompileError_alias(self): + assert re.error is re.ReCompileError + def test_keep_buffer(self): # See bug 14212 b = bytearray(b'x') @@ -152,7 +155,7 @@ def test_basic_re_sub(self): (chr(9)+chr(10)+chr(11)+chr(13)+chr(12)+chr(7)+chr(8))) for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ': with self.subTest(c): - with self.assertRaises(re.error): + with self.assertRaises(re.ReCompileError): self.assertEqual(re.sub('a', '\\' + c, 'a'), '\\' + c) self.assertEqual(re.sub(r'^\s*', 'X', 'test'), 'Xtest') @@ -775,10 +778,10 @@ def test_other_escapes(self): re.purge() # for warnings for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY': with self.subTest(c): - self.assertRaises(re.error, re.compile, '\\%c' % c) + self.assertRaises(re.ReCompileError, re.compile, '\\%c' % c) for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ': with self.subTest(c): - self.assertRaises(re.error, re.compile, '[\\%c]' % c) + self.assertRaises(re.ReCompileError, re.compile, '[\\%c]' % c) def test_named_unicode_escapes(self): # test individual Unicode named escapes @@ -909,14 +912,14 @@ def test_lookbehind(self): self.assertIsNone(re.match(r'(?:(a)|(x))b(?<=(?(1)c|x))c', 'abc')) self.assertTrue(re.match(r'(?:(a)|(x))b(?<=(?(1)b|x))c', 'abc')) # Group used before defined. - self.assertRaises(re.error, re.compile, r'(a)b(?<=(?(2)b|x))(c)') + self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(?(2)b|x))(c)') self.assertIsNone(re.match(r'(a)b(?<=(?(1)c|x))(c)', 'abc')) self.assertTrue(re.match(r'(a)b(?<=(?(1)b|x))(c)', 'abc')) # Group defined in the same lookbehind pattern - self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)\2)(c)') - self.assertRaises(re.error, re.compile, r'(a)b(?<=(?P.)(?P=a))(c)') - self.assertRaises(re.error, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') - self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') + self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(.)\2)(c)') + self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(?P.)(?P=a))(c)') + self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') + self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") @@ -1284,8 +1287,8 @@ def test_sre_byte_literals(self): self.assertTrue(re.match((r"\x%02x" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"\x%02x0" % i).encode(), bytes([i])+b"0")) self.assertTrue(re.match((r"\x%02xz" % i).encode(), bytes([i])+b"z")) - self.assertRaises(re.error, re.compile, br"\u1234") - self.assertRaises(re.error, re.compile, br"\U00012345") + self.assertRaises(re.ReCompileError, re.compile, br"\u1234") + self.assertRaises(re.ReCompileError, re.compile, br"\U00012345") self.assertTrue(re.match(br"\0", b"\000")) self.assertTrue(re.match(br"\08", b"\0008")) self.assertTrue(re.match(br"\01", b"\001")) @@ -1307,8 +1310,8 @@ def test_sre_byte_class_literals(self): self.assertTrue(re.match((r"[\x%02x]" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"[\x%02x0]" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"[\x%02xz]" % i).encode(), bytes([i]))) - self.assertRaises(re.error, re.compile, br"[\u1234]") - self.assertRaises(re.error, re.compile, br"[\U00012345]") + self.assertRaises(re.ReCompileError, re.compile, br"[\u1234]") + self.assertRaises(re.ReCompileError, re.compile, br"[\U00012345]") self.checkPatternError(br"[\567]", r'octal escape value \567 outside of ' r'range 0-0o377', 1) @@ -1640,11 +1643,11 @@ def test_ascii_and_unicode_flag(self): self.assertIsNone(pat.match(b'\xe0')) # Incompatibilities self.assertRaises(ValueError, re.compile, br'\w', re.UNICODE) - self.assertRaises(re.error, re.compile, br'(?u)\w') + self.assertRaises(re.ReCompileError, re.compile, br'(?u)\w') self.assertRaises(ValueError, re.compile, r'\w', re.UNICODE | re.ASCII) self.assertRaises(ValueError, re.compile, r'(?u)\w', re.ASCII) self.assertRaises(ValueError, re.compile, r'(?a)\w', re.UNICODE) - self.assertRaises(re.error, re.compile, r'(?au)\w') + self.assertRaises(re.ReCompileError, re.compile, r'(?au)\w') def test_locale_flag(self): enc = locale.getpreferredencoding() @@ -1685,11 +1688,11 @@ def test_locale_flag(self): self.assertIsNone(pat.match(bletter)) # Incompatibilities self.assertRaises(ValueError, re.compile, '', re.LOCALE) - self.assertRaises(re.error, re.compile, '(?L)') + self.assertRaises(re.ReCompileError, re.compile, '(?L)') self.assertRaises(ValueError, re.compile, b'', re.LOCALE | re.ASCII) self.assertRaises(ValueError, re.compile, b'(?L)', re.ASCII) self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE) - self.assertRaises(re.error, re.compile, b'(?aL)') + self.assertRaises(re.ReCompileError, re.compile, b'(?aL)') def test_scoped_flags(self): self.assertTrue(re.match(r'(?i:a)b', 'Ab')) @@ -2031,7 +2034,7 @@ def test_locale_compiled(self): self.assertIsNone(p4.match(b'\xc5\xc5')) def test_error(self): - with self.assertRaises(re.error) as cm: + with self.assertRaises(re.ReCompileError) as cm: re.compile('(\u20ac))') err = cm.exception self.assertIsInstance(err.pattern, str) @@ -2043,14 +2046,14 @@ def test_error(self): self.assertIn(' at position 3', str(err)) self.assertNotIn(' at position 3', err.msg) # Bytes pattern - with self.assertRaises(re.error) as cm: + with self.assertRaises(re.ReCompileError) as cm: re.compile(b'(\xa4))') err = cm.exception self.assertIsInstance(err.pattern, bytes) self.assertEqual(err.pattern, b'(\xa4))') self.assertEqual(err.pos, 3) # Multiline pattern - with self.assertRaises(re.error) as cm: + with self.assertRaises(re.ReCompileError) as cm: re.compile(""" ( abc @@ -2717,7 +2720,7 @@ def test_re_tests(self): with self.subTest(pattern=pattern, string=s): if outcome == SYNTAX_ERROR: # Expected a syntax error - with self.assertRaises(re.error): + with self.assertRaises(re.ReCompileError): re.compile(pattern) continue diff --git a/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst new file mode 100644 index 00000000000000..a27550112cd9ff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst @@ -0,0 +1,3 @@ +Renamed :exc:`re.error` to :exc:`ReCompileError` for clarity, and kept +:exc:`re.error` for backward compatibility. Patch by Matthias Bussonnier and +Adam Chhina. diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 37d402824853f0..d2ff24ce92e096 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -193,7 +193,7 @@ PyObject* sre_error_exception = NULL; int SRE_FLAG_DEBUG = 0; /* Called by LLVMFuzzerTestOneInput for initialization */ static int init_sre_compile(void) { - /* Import sre_compile.compile and sre.error */ + /* Import sre_compile.compile and sre_constants.ReCompileError */ PyObject* sre_compile_module = PyImport_ImportModule("sre_compile"); if (sre_compile_module == NULL) { return 0; @@ -207,7 +207,7 @@ static int init_sre_compile(void) { if (sre_constants == NULL) { return 0; } - sre_error_exception = PyObject_GetAttrString(sre_constants, "error"); + sre_error_exception = PyObject_GetAttrString(sre_constants, "ReCompileError"); if (sre_error_exception == NULL) { return 0; } @@ -261,7 +261,7 @@ static int fuzz_sre_compile(const char* data, size_t size) { ) { PyErr_Clear(); } - /* Ignore re.error */ + /* Ignore re.ReCompileError */ if (compiled == NULL && PyErr_ExceptionMatches(sre_error_exception)) { PyErr_Clear(); } From e72dce1760dd2288e1c214a6864481de2ea6ab41 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Wed, 8 Feb 2023 01:06:14 -0500 Subject: [PATCH 02/14] GH-83162: Fix deprecated sre_compile to _compiler. --- Lib/re/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index 6cf09b31a4e7b0..0c8602190d02e1 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -157,7 +157,7 @@ class RegexFlag: _numeric_repr_ = hex # sre exception -ReCompileError = error = sre_compile.ReCompileError +ReCompileError = error = _compiler.ReCompileError # -------------------------------------------------------------------- # public interface From 5274810db159a8494a3c54d4b29577c3b9c35a17 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Wed, 8 Feb 2023 01:20:01 -0500 Subject: [PATCH 03/14] GH-83162: Update _compiler and _constants to new exception name. --- Lib/re/_compiler.py | 8 ++++---- Lib/re/_constants.py | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index d8e0d2fdefdcca..77ede4a6cf0ae0 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -102,7 +102,7 @@ def _compile(code, pattern, flags): emit(ANY) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: - raise error("internal: unsupported template operator %r" % (op,)) + raise ReCompileError(f"internal: unsupported template operator {op!r}") if _simple(av[2]): emit(REPEATING_CODES[op][2]) skip = _len(code); emit(0) @@ -150,7 +150,7 @@ def _compile(code, pattern, flags): else: lo, hi = av[1].getwidth() if lo != hi: - raise error("look-behind requires fixed-width pattern") + raise ReCompileError("look-behind requires fixed-width pattern") emit(lo) # look behind _compile(code, av[1], flags) emit(SUCCESS) @@ -209,7 +209,7 @@ def _compile(code, pattern, flags): else: code[skipyes] = _len(code) - skipyes + 1 else: - raise error("internal: unsupported operand type %r" % (op,)) + raise ReCompileError(f"internal: unsupported operand type {op!r}") def _compile_charset(charset, flags, code): # compile charset subprogram @@ -235,7 +235,7 @@ def _compile_charset(charset, flags, code): else: emit(av) else: - raise error("internal: unsupported set operator %r" % (op,)) + raise ReCompileError(f"internal: unsupported set operator {op!r}") emit(FAILURE) def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py index d8718d36075aac..61d97aab01a2e5 100644 --- a/Lib/re/_constants.py +++ b/Lib/re/_constants.py @@ -17,10 +17,10 @@ from _sre import MAXREPEAT, MAXGROUPS -# SRE standard exception (access as sre.error) +# SRE standard exception (access as sre.ReCompileError) # should this really be here? -class error(Exception): +class ReCompileError(Exception): """Exception raised for invalid regular expressions. Attributes: @@ -53,6 +53,9 @@ def __init__(self, msg, pattern=None, pos=None): super().__init__(msg) +# Backward compatibility after renaming in 3.12 +error = ReCompileError + class _NamedIntConstant(int): def __new__(cls, value, name): self = super(_NamedIntConstant, cls).__new__(cls, value) From 0eca4ac8bbaac1ac4aa09ca1bc894ba775af6fb5 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Sun, 28 May 2023 21:21:14 -0400 Subject: [PATCH 04/14] Adding code review commit suggestions, and adding re.error rename to Python 3.13 What's New. --- Doc/library/re.rst | 2 +- Doc/whatsnew/3.13.rst | 6 ++++-- Lib/re/_constants.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index ce10ae39ecc22a..6c1e012b72a22d 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1111,7 +1111,7 @@ Exceptions .. versionchanged:: 3.5 Added additional attributes. - .. versionchanged:: 3.12 + .. versionchanged:: 3.13 ``ReCompileError`` was originally named ``error``; the latter is kept as an alias for backward compatibility. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 45728d1801d20a..78e851c10c6209 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -91,8 +91,10 @@ Improved Modules Optimizations ============= - - +re +-- +* Rename :exc:`re.error` to :exc:`re.ReCompileError` for improved clarity. + :exc:`re.error` is kept for backward compabitility. Deprecated ========== diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py index 61d97aab01a2e5..a0b4a0e4791be0 100644 --- a/Lib/re/_constants.py +++ b/Lib/re/_constants.py @@ -53,7 +53,7 @@ def __init__(self, msg, pattern=None, pos=None): super().__init__(msg) -# Backward compatibility after renaming in 3.12 +# Backward compatibility after renaming in 3.13 error = ReCompileError class _NamedIntConstant(int): From db36a4a1c0810e4d9d01a82830e2b1c6e306734c Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Sun, 28 May 2023 21:34:12 -0400 Subject: [PATCH 05/14] Fixed re.error to be a code directive instead of an exception directive. --- Doc/whatsnew/3.13.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 78e851c10c6209..55825eacaa7336 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -93,8 +93,8 @@ Optimizations re -- -* Rename :exc:`re.error` to :exc:`re.ReCompileError` for improved clarity. - :exc:`re.error` is kept for backward compabitility. +* Rename ``re.error`` to :exc:`re.ReCompileError` for improved clarity. + ``re.error`` is kept for backward compabitility. Deprecated ========== From bc44d0fcd7ecdffca13fd8d53ef1b484d1a61a91 Mon Sep 17 00:00:00 2001 From: achhina Date: Sun, 4 Jun 2023 15:48:41 -0400 Subject: [PATCH 06/14] Update Doc/whatsnew/3.13.rst Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.13.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 55825eacaa7336..1864e8cc24c379 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -93,8 +93,8 @@ Optimizations re -- -* Rename ``re.error`` to :exc:`re.ReCompileError` for improved clarity. - ``re.error`` is kept for backward compabitility. +* Rename :exc:`!re.error` to :exc:`re.ReCompileError` for improved clarity. + :exc:`!re.error` is kept for backward compatibility. Deprecated ========== From a2a81b57cbba228af7c3cbcd777ec8ca6e422cda Mon Sep 17 00:00:00 2001 From: achhina Date: Sun, 4 Jun 2023 15:48:49 -0400 Subject: [PATCH 07/14] Update Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst Co-authored-by: Hugo van Kemenade --- .../Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst index a27550112cd9ff..87dbd2ad4676fa 100644 --- a/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst +++ b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst @@ -1,3 +1,3 @@ -Renamed :exc:`re.error` to :exc:`ReCompileError` for clarity, and kept -:exc:`re.error` for backward compatibility. Patch by Matthias Bussonnier and +Renamed :exc:`!re.error` to :exc:`ReCompileError` for clarity, and kept +:exc:`!re.error` for backward compatibility. Patch by Matthias Bussonnier and Adam Chhina. From f82d18a2c6b0c616a60504feb32af97d64478329 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Tue, 6 Jun 2023 05:38:14 -0400 Subject: [PATCH 08/14] Renamed ReCompileError to PatternError. --- Doc/library/re.rst | 6 +-- Doc/whatsnew/3.13.rst | 2 +- Lib/idlelib/searchengine.py | 2 +- Lib/pstats.py | 2 +- Lib/re/__init__.py | 6 +-- Lib/re/_compiler.py | 8 ++-- Lib/re/_constants.py | 6 +-- Lib/test/test_re.py | 48 +++++++++---------- ...3-02-08-00-43-29.gh-issue-83162.ufdI9F.rst | 2 +- Modules/_xxtestfuzz/fuzzer.c | 6 +-- 10 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 6c1e012b72a22d..7f5c72c9613871 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1080,13 +1080,13 @@ Functions Exceptions ^^^^^^^^^^ -.. exception:: ReCompileError(msg, pattern=None, pos=None) +.. exception:: PatternError(msg, pattern=None, pos=None) Exception raised when a string passed to one of the functions here is not a valid regular expression (for example, it might contain unmatched parentheses) or when some other error occurs during compilation or matching. It is never an error if a string contains no match for a pattern. The - ``ReCompileError`` instance has the following additional attributes: + ``PatternError`` instance has the following additional attributes: .. attribute:: msg @@ -1112,7 +1112,7 @@ Exceptions Added additional attributes. .. versionchanged:: 3.13 - ``ReCompileError`` was originally named ``error``; the latter is kept as an alias for + ``PatternError`` was originally named ``error``; the latter is kept as an alias for backward compatibility. .. _re-objects: diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 53d09695c95e28..075ca14536186c 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -118,7 +118,7 @@ Optimizations re -- -* Rename :exc:`!re.error` to :exc:`re.ReCompileError` for improved clarity. +* Rename :exc:`!re.error` to :exc:`re.PatternError` for improved clarity. :exc:`!re.error` is kept for backward compatibility. Deprecated diff --git a/Lib/idlelib/searchengine.py b/Lib/idlelib/searchengine.py index 6b998f63b07efe..ceb38cfaef900b 100644 --- a/Lib/idlelib/searchengine.py +++ b/Lib/idlelib/searchengine.py @@ -84,7 +84,7 @@ def getprog(self): flags = flags | re.IGNORECASE try: prog = re.compile(pat, flags) - except re.ReCompileError as e: + except re.PatternError as e: self.report_error(pat, e.msg, e.pos) return None return prog diff --git a/Lib/pstats.py b/Lib/pstats.py index 045930e89f8d7e..2f054bb4011e7f 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -329,7 +329,7 @@ def eval_print_amount(self, sel, list, msg): if isinstance(sel, str): try: rex = re.compile(sel) - except re.ReCompileError: + except re.PatternError: msg += " \n" % sel return new_list, msg new_list = [] diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index 0c8602190d02e1..31c7649c1052eb 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -117,7 +117,7 @@ U UNICODE For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns. -This module also defines exception 'ReCompileError', aliased to 'error' for +This module also defines exception 'PatternError', aliased to 'error' for backward compatibility. """ @@ -134,7 +134,7 @@ "findall", "finditer", "compile", "purge", "template", "escape", "error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE", - "UNICODE", "NOFLAG", "RegexFlag", "ReCompileError" + "UNICODE", "NOFLAG", "RegexFlag", "PatternError" ] __version__ = "2.2.1" @@ -157,7 +157,7 @@ class RegexFlag: _numeric_repr_ = hex # sre exception -ReCompileError = error = _compiler.ReCompileError +PatternError = error = _compiler.PatternError # -------------------------------------------------------------------- # public interface diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index 77ede4a6cf0ae0..67a53542d6237e 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -102,7 +102,7 @@ def _compile(code, pattern, flags): emit(ANY) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: - raise ReCompileError(f"internal: unsupported template operator {op!r}") + raise PatternError(f"internal: unsupported template operator {op!r}") if _simple(av[2]): emit(REPEATING_CODES[op][2]) skip = _len(code); emit(0) @@ -150,7 +150,7 @@ def _compile(code, pattern, flags): else: lo, hi = av[1].getwidth() if lo != hi: - raise ReCompileError("look-behind requires fixed-width pattern") + raise PatternError("look-behind requires fixed-width pattern") emit(lo) # look behind _compile(code, av[1], flags) emit(SUCCESS) @@ -209,7 +209,7 @@ def _compile(code, pattern, flags): else: code[skipyes] = _len(code) - skipyes + 1 else: - raise ReCompileError(f"internal: unsupported operand type {op!r}") + raise PatternError(f"internal: unsupported operand type {op!r}") def _compile_charset(charset, flags, code): # compile charset subprogram @@ -235,7 +235,7 @@ def _compile_charset(charset, flags, code): else: emit(av) else: - raise ReCompileError(f"internal: unsupported set operator {op!r}") + raise PatternError(f"internal: unsupported set operator {op!r}") emit(FAILURE) def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py index a0b4a0e4791be0..f652e4c09b2b6f 100644 --- a/Lib/re/_constants.py +++ b/Lib/re/_constants.py @@ -17,10 +17,10 @@ from _sre import MAXREPEAT, MAXGROUPS -# SRE standard exception (access as sre.ReCompileError) +# SRE standard exception (access as sre.error) # should this really be here? -class ReCompileError(Exception): +class PatternError(Exception): """Exception raised for invalid regular expressions. Attributes: @@ -54,7 +54,7 @@ def __init__(self, msg, pattern=None, pos=None): # Backward compatibility after renaming in 3.13 -error = ReCompileError +error = PatternError class _NamedIntConstant(int): def __new__(cls, value, name): diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 593b40c65effdf..734096bab21622 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -47,7 +47,7 @@ def recurse(actual, expect): recurse(actual, expect) def checkPatternError(self, pattern, errmsg, pos=None): - with self.assertRaises(re.ReCompileError) as cm: + with self.assertRaises(re.PatternError) as cm: re.compile(pattern) with self.subTest(pattern=pattern): err = cm.exception @@ -56,7 +56,7 @@ def checkPatternError(self, pattern, errmsg, pos=None): self.assertEqual(err.pos, pos) def checkTemplateError(self, pattern, repl, string, errmsg, pos=None): - with self.assertRaises(re.ReCompileError) as cm: + with self.assertRaises(re.PatternError) as cm: re.sub(pattern, repl, string) with self.subTest(pattern=pattern, repl=repl): err = cm.exception @@ -64,8 +64,8 @@ def checkTemplateError(self, pattern, repl, string, errmsg, pos=None): if pos is not None: self.assertEqual(err.pos, pos) - def test_error_is_ReCompileError_alias(self): - assert re.error is re.ReCompileError + def test_error_is_PatternError_alias(self): + assert re.error is re.PatternError def test_keep_buffer(self): # See bug 14212 @@ -155,7 +155,7 @@ def test_basic_re_sub(self): (chr(9)+chr(10)+chr(11)+chr(13)+chr(12)+chr(7)+chr(8))) for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ': with self.subTest(c): - with self.assertRaises(re.ReCompileError): + with self.assertRaises(re.PatternError): self.assertEqual(re.sub('a', '\\' + c, 'a'), '\\' + c) self.assertEqual(re.sub(r'^\s*', 'X', 'test'), 'Xtest') @@ -778,10 +778,10 @@ def test_other_escapes(self): re.purge() # for warnings for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY': with self.subTest(c): - self.assertRaises(re.ReCompileError, re.compile, '\\%c' % c) + self.assertRaises(re.PatternError, re.compile, '\\%c' % c) for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ': with self.subTest(c): - self.assertRaises(re.ReCompileError, re.compile, '[\\%c]' % c) + self.assertRaises(re.PatternError, re.compile, '[\\%c]' % c) def test_named_unicode_escapes(self): # test individual Unicode named escapes @@ -912,14 +912,14 @@ def test_lookbehind(self): self.assertIsNone(re.match(r'(?:(a)|(x))b(?<=(?(1)c|x))c', 'abc')) self.assertTrue(re.match(r'(?:(a)|(x))b(?<=(?(1)b|x))c', 'abc')) # Group used before defined. - self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(?(2)b|x))(c)') + self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(?(2)b|x))(c)') self.assertIsNone(re.match(r'(a)b(?<=(?(1)c|x))(c)', 'abc')) self.assertTrue(re.match(r'(a)b(?<=(?(1)b|x))(c)', 'abc')) # Group defined in the same lookbehind pattern - self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(.)\2)(c)') - self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(?P.)(?P=a))(c)') - self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') - self.assertRaises(re.ReCompileError, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') + self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)\2)(c)') + self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(?P.)(?P=a))(c)') + self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') + self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") @@ -1287,8 +1287,8 @@ def test_sre_byte_literals(self): self.assertTrue(re.match((r"\x%02x" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"\x%02x0" % i).encode(), bytes([i])+b"0")) self.assertTrue(re.match((r"\x%02xz" % i).encode(), bytes([i])+b"z")) - self.assertRaises(re.ReCompileError, re.compile, br"\u1234") - self.assertRaises(re.ReCompileError, re.compile, br"\U00012345") + self.assertRaises(re.PatternError, re.compile, br"\u1234") + self.assertRaises(re.PatternError, re.compile, br"\U00012345") self.assertTrue(re.match(br"\0", b"\000")) self.assertTrue(re.match(br"\08", b"\0008")) self.assertTrue(re.match(br"\01", b"\001")) @@ -1310,8 +1310,8 @@ def test_sre_byte_class_literals(self): self.assertTrue(re.match((r"[\x%02x]" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"[\x%02x0]" % i).encode(), bytes([i]))) self.assertTrue(re.match((r"[\x%02xz]" % i).encode(), bytes([i]))) - self.assertRaises(re.ReCompileError, re.compile, br"[\u1234]") - self.assertRaises(re.ReCompileError, re.compile, br"[\U00012345]") + self.assertRaises(re.PatternError, re.compile, br"[\u1234]") + self.assertRaises(re.PatternError, re.compile, br"[\U00012345]") self.checkPatternError(br"[\567]", r'octal escape value \567 outside of ' r'range 0-0o377', 1) @@ -1643,11 +1643,11 @@ def test_ascii_and_unicode_flag(self): self.assertIsNone(pat.match(b'\xe0')) # Incompatibilities self.assertRaises(ValueError, re.compile, br'\w', re.UNICODE) - self.assertRaises(re.ReCompileError, re.compile, br'(?u)\w') + self.assertRaises(re.PatternError, re.compile, br'(?u)\w') self.assertRaises(ValueError, re.compile, r'\w', re.UNICODE | re.ASCII) self.assertRaises(ValueError, re.compile, r'(?u)\w', re.ASCII) self.assertRaises(ValueError, re.compile, r'(?a)\w', re.UNICODE) - self.assertRaises(re.ReCompileError, re.compile, r'(?au)\w') + self.assertRaises(re.PatternError, re.compile, r'(?au)\w') def test_locale_flag(self): enc = locale.getpreferredencoding() @@ -1688,11 +1688,11 @@ def test_locale_flag(self): self.assertIsNone(pat.match(bletter)) # Incompatibilities self.assertRaises(ValueError, re.compile, '', re.LOCALE) - self.assertRaises(re.ReCompileError, re.compile, '(?L)') + self.assertRaises(re.PatternError, re.compile, '(?L)') self.assertRaises(ValueError, re.compile, b'', re.LOCALE | re.ASCII) self.assertRaises(ValueError, re.compile, b'(?L)', re.ASCII) self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE) - self.assertRaises(re.ReCompileError, re.compile, b'(?aL)') + self.assertRaises(re.PatternError, re.compile, b'(?aL)') def test_scoped_flags(self): self.assertTrue(re.match(r'(?i:a)b', 'Ab')) @@ -2034,7 +2034,7 @@ def test_locale_compiled(self): self.assertIsNone(p4.match(b'\xc5\xc5')) def test_error(self): - with self.assertRaises(re.ReCompileError) as cm: + with self.assertRaises(re.PatternError) as cm: re.compile('(\u20ac))') err = cm.exception self.assertIsInstance(err.pattern, str) @@ -2046,14 +2046,14 @@ def test_error(self): self.assertIn(' at position 3', str(err)) self.assertNotIn(' at position 3', err.msg) # Bytes pattern - with self.assertRaises(re.ReCompileError) as cm: + with self.assertRaises(re.PatternError) as cm: re.compile(b'(\xa4))') err = cm.exception self.assertIsInstance(err.pattern, bytes) self.assertEqual(err.pattern, b'(\xa4))') self.assertEqual(err.pos, 3) # Multiline pattern - with self.assertRaises(re.ReCompileError) as cm: + with self.assertRaises(re.PatternError) as cm: re.compile(""" ( abc @@ -2720,7 +2720,7 @@ def test_re_tests(self): with self.subTest(pattern=pattern, string=s): if outcome == SYNTAX_ERROR: # Expected a syntax error - with self.assertRaises(re.ReCompileError): + with self.assertRaises(re.PatternError): re.compile(pattern) continue diff --git a/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst index 87dbd2ad4676fa..6074dd7f101a6d 100644 --- a/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst +++ b/Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst @@ -1,3 +1,3 @@ -Renamed :exc:`!re.error` to :exc:`ReCompileError` for clarity, and kept +Renamed :exc:`!re.error` to :exc:`PatternError` for clarity, and kept :exc:`!re.error` for backward compatibility. Patch by Matthias Bussonnier and Adam Chhina. diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index d2ff24ce92e096..b8abae522b2e87 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -193,7 +193,7 @@ PyObject* sre_error_exception = NULL; int SRE_FLAG_DEBUG = 0; /* Called by LLVMFuzzerTestOneInput for initialization */ static int init_sre_compile(void) { - /* Import sre_compile.compile and sre_constants.ReCompileError */ + /* Import sre_compile.compile and sre_constants.PatternError */ PyObject* sre_compile_module = PyImport_ImportModule("sre_compile"); if (sre_compile_module == NULL) { return 0; @@ -207,7 +207,7 @@ static int init_sre_compile(void) { if (sre_constants == NULL) { return 0; } - sre_error_exception = PyObject_GetAttrString(sre_constants, "ReCompileError"); + sre_error_exception = PyObject_GetAttrString(sre_constants, "PatternError"); if (sre_error_exception == NULL) { return 0; } @@ -261,7 +261,7 @@ static int fuzz_sre_compile(const char* data, size_t size) { ) { PyErr_Clear(); } - /* Ignore re.ReCompileError */ + /* Ignore re.PatternError */ if (compiled == NULL && PyErr_ExceptionMatches(sre_error_exception)) { PyErr_Clear(); } From 7b0509833092ee3a4181d7687b28e7f233ea2879 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Tue, 6 Jun 2023 05:44:21 -0400 Subject: [PATCH 09/14] Rename re.error to re.PatternError in idelib relpace.py. --- Lib/idlelib/replace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py index ca83173877ad1d..fc847d079acc17 100644 --- a/Lib/idlelib/replace.py +++ b/Lib/idlelib/replace.py @@ -120,7 +120,7 @@ def _replace_expand(self, m, repl): if self.engine.isre(): try: new = m.expand(repl) - except re.error: + except re.PatternError: self.engine.report_error(repl, 'Invalid Replace Expression') new = None else: From 2e3bcefc7d6e129169c49b89b621e979218a1e01 Mon Sep 17 00:00:00 2001 From: achhina Date: Wed, 7 Jun 2023 05:44:39 -0400 Subject: [PATCH 10/14] Update Modules/_xxtestfuzz/fuzzer.c Co-authored-by: Terry Jan Reedy --- Modules/_xxtestfuzz/fuzzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index b8abae522b2e87..4e9d80ccdbbed6 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -193,7 +193,7 @@ PyObject* sre_error_exception = NULL; int SRE_FLAG_DEBUG = 0; /* Called by LLVMFuzzerTestOneInput for initialization */ static int init_sre_compile(void) { - /* Import sre_compile.compile and sre_constants.PatternError */ + /* Import sre_compile.compile and sre.error */ PyObject* sre_compile_module = PyImport_ImportModule("sre_compile"); if (sre_compile_module == NULL) { return 0; From 6b0bee21dd9633900386c7a429a3967eca5e5ed2 Mon Sep 17 00:00:00 2001 From: achhina Date: Wed, 7 Jun 2023 05:45:13 -0400 Subject: [PATCH 11/14] Update Modules/_xxtestfuzz/fuzzer.c Co-authored-by: Terry Jan Reedy --- Modules/_xxtestfuzz/fuzzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 4e9d80ccdbbed6..0950a467572245 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -207,7 +207,7 @@ static int init_sre_compile(void) { if (sre_constants == NULL) { return 0; } - sre_error_exception = PyObject_GetAttrString(sre_constants, "PatternError"); + sre_error_exception = PyObject_GetAttrString(sre_constants, "error"); if (sre_error_exception == NULL) { return 0; } From 09e942b9073b5e31ac774d93402f76874c30f486 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Wed, 7 Jun 2023 05:47:09 -0400 Subject: [PATCH 12/14] Reverted patch for fuzzer.c. --- Modules/_xxtestfuzz/fuzzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 0950a467572245..37d402824853f0 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -261,7 +261,7 @@ static int fuzz_sre_compile(const char* data, size_t size) { ) { PyErr_Clear(); } - /* Ignore re.PatternError */ + /* Ignore re.error */ if (compiled == NULL && PyErr_ExceptionMatches(sre_error_exception)) { PyErr_Clear(); } From 1d3d4727a39a09b7024de7c969b5c20169e162f6 Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Sun, 3 Dec 2023 11:58:18 -0500 Subject: [PATCH 13/14] GH-83162: Unwrap paragraph. --- Doc/library/re.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index cde08cb9bdcd3a..26498db7103165 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1096,10 +1096,10 @@ Exceptions .. exception:: PatternError(msg, pattern=None, pos=None) Exception raised when a string passed to one of the functions here is not a - valid regular expression (for example, it might contain unmatched - parentheses) or when some other error occurs during compilation or matching. - It is never an error if a string contains no match for a pattern. The - ``PatternError`` instance has the following additional attributes: + valid regular expression (for example, it might contain unmatched parentheses) + or when some other error occurs during compilation or matching. It is never an + error if a string contains no match for a pattern. The ``PatternError`` instance has + the following additional attributes: .. attribute:: msg From f0a3cb0ed435bc9d5464811f52b06afeab61a90a Mon Sep 17 00:00:00 2001 From: Adam Chhina Date: Sun, 3 Dec 2023 12:00:33 -0500 Subject: [PATCH 14/14] GH-83162: Add space back in. --- Doc/library/re.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 26498db7103165..302f7224de4a7a 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1097,7 +1097,7 @@ Exceptions Exception raised when a string passed to one of the functions here is not a valid regular expression (for example, it might contain unmatched parentheses) - or when some other error occurs during compilation or matching. It is never an + or when some other error occurs during compilation or matching. It is never an error if a string contains no match for a pattern. The ``PatternError`` instance has the following additional attributes: