GH-83162: Rename re.error for better clarity. (#101677)

Renamed re.error for clarity, and kept re.error for backward compatibility.
Updated idlelib files at TJR's request.
---------

Co-authored-by: Matthias Bussonnier <mbussonnier@ucmerced.edu>
Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
achhina 2023-12-11 15:45:08 -05:00 committed by GitHub
parent 0066ab5bc5
commit a01022af23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 53 additions and 34 deletions

View File

@ -1093,12 +1093,12 @@ Functions
Exceptions Exceptions
^^^^^^^^^^ ^^^^^^^^^^
.. exception:: error(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 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) 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 error instance has error if a string contains no match for a pattern. The ``PatternError`` instance has
the following additional attributes: the following additional attributes:
.. attribute:: msg .. attribute:: msg
@ -1124,6 +1124,10 @@ Exceptions
.. versionchanged:: 3.5 .. versionchanged:: 3.5
Added additional attributes. Added additional attributes.
.. versionchanged:: 3.13
``PatternError`` was originally named ``error``; the latter is kept as an alias for
backward compatibility.
.. _re-objects: .. _re-objects:
Regular Expression Objects Regular Expression Objects

View File

@ -298,6 +298,11 @@ pdb
command line option or :envvar:`PYTHONSAFEPATH` environment variable). command line option or :envvar:`PYTHONSAFEPATH` environment variable).
(Contributed by Tian Gao and Christian Walther in :gh:`111762`.) (Contributed by Tian Gao and Christian Walther in :gh:`111762`.)
re
--
* Rename :exc:`!re.error` to :exc:`re.PatternError` for improved clarity.
:exc:`!re.error` is kept for backward compatibility.
sqlite3 sqlite3
------- -------

View File

@ -120,7 +120,7 @@ class ReplaceDialog(SearchDialogBase):
if self.engine.isre(): if self.engine.isre():
try: try:
new = m.expand(repl) new = m.expand(repl)
except re.error: except re.PatternError:
self.engine.report_error(repl, 'Invalid Replace Expression') self.engine.report_error(repl, 'Invalid Replace Expression')
new = None new = None
else: else:

View File

@ -84,7 +84,7 @@ class SearchEngine:
flags = flags | re.IGNORECASE flags = flags | re.IGNORECASE
try: try:
prog = re.compile(pat, flags) prog = re.compile(pat, flags)
except re.error as e: except re.PatternError as e:
self.report_error(pat, e.msg, e.pos) self.report_error(pat, e.msg, e.pos)
return None return None
return prog return prog

View File

@ -329,7 +329,7 @@ class Stats:
if isinstance(sel, str): if isinstance(sel, str):
try: try:
rex = re.compile(sel) rex = re.compile(sel)
except re.error: except re.PatternError:
msg += " <Invalid regular expression %r>\n" % sel msg += " <Invalid regular expression %r>\n" % sel
return new_list, msg return new_list, msg
new_list = [] new_list = []

View File

@ -117,7 +117,8 @@ A, L, and U are mutually exclusive.
U UNICODE For compatibility only. Ignored for string patterns (it U UNICODE For compatibility only. Ignored for string patterns (it
is the default), and forbidden for bytes patterns. is the default), and forbidden for bytes patterns.
This module also defines an exception 'error'. This module also defines exception 'PatternError', aliased to 'error' for
backward compatibility.
""" """
@ -133,7 +134,7 @@ __all__ = [
"findall", "finditer", "compile", "purge", "escape", "findall", "finditer", "compile", "purge", "escape",
"error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U", "error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U",
"ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
"UNICODE", "NOFLAG", "RegexFlag", "UNICODE", "NOFLAG", "RegexFlag", "PatternError"
] ]
__version__ = "2.2.1" __version__ = "2.2.1"
@ -155,7 +156,7 @@ class RegexFlag:
_numeric_repr_ = hex _numeric_repr_ = hex
# sre exception # sre exception
error = _compiler.error PatternError = error = _compiler.PatternError
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# public interface # public interface

View File

@ -150,7 +150,7 @@ def _compile(code, pattern, flags):
if lo > MAXCODE: if lo > MAXCODE:
raise error("looks too much behind") raise error("looks too much behind")
if lo != hi: if lo != hi:
raise error("look-behind requires fixed-width pattern") raise PatternError("look-behind requires fixed-width pattern")
emit(lo) # look behind emit(lo) # look behind
_compile(code, av[1], flags) _compile(code, av[1], flags)
emit(SUCCESS) emit(SUCCESS)
@ -209,7 +209,7 @@ def _compile(code, pattern, flags):
else: else:
code[skipyes] = _len(code) - skipyes + 1 code[skipyes] = _len(code) - skipyes + 1
else: else:
raise error("internal: unsupported operand type %r" % (op,)) raise PatternError(f"internal: unsupported operand type {op!r}")
def _compile_charset(charset, flags, code): def _compile_charset(charset, flags, code):
# compile charset subprogram # compile charset subprogram
@ -235,7 +235,7 @@ def _compile_charset(charset, flags, code):
else: else:
emit(av) emit(av)
else: else:
raise error("internal: unsupported set operator %r" % (op,)) raise PatternError(f"internal: unsupported set operator {op!r}")
emit(FAILURE) emit(FAILURE)
def _optimize_charset(charset, iscased=None, fixup=None, fixes=None): def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):

View File

@ -20,7 +20,7 @@ from _sre import MAXREPEAT, MAXGROUPS
# SRE standard exception (access as sre.error) # SRE standard exception (access as sre.error)
# should this really be here? # should this really be here?
class error(Exception): class PatternError(Exception):
"""Exception raised for invalid regular expressions. """Exception raised for invalid regular expressions.
Attributes: Attributes:
@ -53,6 +53,9 @@ class error(Exception):
super().__init__(msg) super().__init__(msg)
# Backward compatibility after renaming in 3.13
error = PatternError
class _NamedIntConstant(int): class _NamedIntConstant(int):
def __new__(cls, value, name): def __new__(cls, value, name):
self = super(_NamedIntConstant, cls).__new__(cls, value) self = super(_NamedIntConstant, cls).__new__(cls, value)

View File

@ -47,7 +47,7 @@ class ReTests(unittest.TestCase):
recurse(actual, expect) recurse(actual, expect)
def checkPatternError(self, pattern, errmsg, pos=None): def checkPatternError(self, pattern, errmsg, pos=None):
with self.assertRaises(re.error) as cm: with self.assertRaises(re.PatternError) as cm:
re.compile(pattern) re.compile(pattern)
with self.subTest(pattern=pattern): with self.subTest(pattern=pattern):
err = cm.exception err = cm.exception
@ -56,7 +56,7 @@ class ReTests(unittest.TestCase):
self.assertEqual(err.pos, pos) self.assertEqual(err.pos, pos)
def checkTemplateError(self, pattern, repl, string, errmsg, pos=None): def checkTemplateError(self, pattern, repl, string, errmsg, pos=None):
with self.assertRaises(re.error) as cm: with self.assertRaises(re.PatternError) as cm:
re.sub(pattern, repl, string) re.sub(pattern, repl, string)
with self.subTest(pattern=pattern, repl=repl): with self.subTest(pattern=pattern, repl=repl):
err = cm.exception err = cm.exception
@ -64,6 +64,9 @@ class ReTests(unittest.TestCase):
if pos is not None: if pos is not None:
self.assertEqual(err.pos, pos) self.assertEqual(err.pos, pos)
def test_error_is_PatternError_alias(self):
assert re.error is re.PatternError
def test_keep_buffer(self): def test_keep_buffer(self):
# See bug 14212 # See bug 14212
b = bytearray(b'x') b = bytearray(b'x')
@ -154,7 +157,7 @@ class ReTests(unittest.TestCase):
(chr(9)+chr(10)+chr(11)+chr(13)+chr(12)+chr(7)+chr(8))) (chr(9)+chr(10)+chr(11)+chr(13)+chr(12)+chr(7)+chr(8)))
for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ': for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
with self.subTest(c): with self.subTest(c):
with self.assertRaises(re.error): with self.assertRaises(re.PatternError):
self.assertEqual(re.sub('a', '\\' + c, 'a'), '\\' + c) self.assertEqual(re.sub('a', '\\' + c, 'a'), '\\' + c)
self.assertEqual(re.sub(r'^\s*', 'X', 'test'), 'Xtest') self.assertEqual(re.sub(r'^\s*', 'X', 'test'), 'Xtest')
@ -836,10 +839,10 @@ class ReTests(unittest.TestCase):
re.purge() # for warnings re.purge() # for warnings
for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY': for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY':
with self.subTest(c): with self.subTest(c):
self.assertRaises(re.error, re.compile, '\\%c' % c) self.assertRaises(re.PatternError, re.compile, '\\%c' % c)
for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ': for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ':
with self.subTest(c): with self.subTest(c):
self.assertRaises(re.error, re.compile, '[\\%c]' % c) self.assertRaises(re.PatternError, re.compile, '[\\%c]' % c)
def test_named_unicode_escapes(self): def test_named_unicode_escapes(self):
# test individual Unicode named escapes # test individual Unicode named escapes
@ -970,14 +973,14 @@ class ReTests(unittest.TestCase):
self.assertIsNone(re.match(r'(?:(a)|(x))b(?<=(?(1)c|x))c', 'abc')) 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')) self.assertTrue(re.match(r'(?:(a)|(x))b(?<=(?(1)b|x))c', 'abc'))
# Group used before defined. # Group used before defined.
self.assertRaises(re.error, 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.assertIsNone(re.match(r'(a)b(?<=(?(1)c|x))(c)', 'abc'))
self.assertTrue(re.match(r'(a)b(?<=(?(1)b|x))(c)', 'abc')) self.assertTrue(re.match(r'(a)b(?<=(?(1)b|x))(c)', 'abc'))
# Group defined in the same lookbehind pattern # Group defined in the same lookbehind pattern
self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)\2)(c)') self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)\2)(c)')
self.assertRaises(re.error, re.compile, r'(a)b(?<=(?P<a>.)(?P=a))(c)') self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(?P<a>.)(?P=a))(c)')
self.assertRaises(re.error, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)')
self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)(?<=\2))(c)')
def test_ignore_case(self): def test_ignore_case(self):
self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC")
@ -1318,8 +1321,8 @@ class ReTests(unittest.TestCase):
self.assertTrue(re.match((r"\x%02x" % i).encode(), bytes([i]))) 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%02x0" % i).encode(), bytes([i])+b"0"))
self.assertTrue(re.match((r"\x%02xz" % i).encode(), bytes([i])+b"z")) self.assertTrue(re.match((r"\x%02xz" % i).encode(), bytes([i])+b"z"))
self.assertRaises(re.error, re.compile, br"\u1234") self.assertRaises(re.PatternError, re.compile, br"\u1234")
self.assertRaises(re.error, re.compile, br"\U00012345") self.assertRaises(re.PatternError, re.compile, br"\U00012345")
self.assertTrue(re.match(br"\0", b"\000")) self.assertTrue(re.match(br"\0", b"\000"))
self.assertTrue(re.match(br"\08", b"\0008")) self.assertTrue(re.match(br"\08", b"\0008"))
self.assertTrue(re.match(br"\01", b"\001")) self.assertTrue(re.match(br"\01", b"\001"))
@ -1341,8 +1344,8 @@ class ReTests(unittest.TestCase):
self.assertTrue(re.match((r"[\x%02x]" % i).encode(), bytes([i]))) 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%02x0]" % i).encode(), bytes([i])))
self.assertTrue(re.match((r"[\x%02xz]" % 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.PatternError, re.compile, br"[\u1234]")
self.assertRaises(re.error, re.compile, br"[\U00012345]") self.assertRaises(re.PatternError, re.compile, br"[\U00012345]")
self.checkPatternError(br"[\567]", self.checkPatternError(br"[\567]",
r'octal escape value \567 outside of ' r'octal escape value \567 outside of '
r'range 0-0o377', 1) r'range 0-0o377', 1)
@ -1675,11 +1678,11 @@ class ReTests(unittest.TestCase):
self.assertIsNone(pat.match(b'\xe0')) self.assertIsNone(pat.match(b'\xe0'))
# Incompatibilities # Incompatibilities
self.assertRaises(ValueError, re.compile, br'\w', re.UNICODE) self.assertRaises(ValueError, re.compile, br'\w', re.UNICODE)
self.assertRaises(re.error, 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'\w', re.UNICODE | re.ASCII)
self.assertRaises(ValueError, re.compile, r'(?u)\w', re.ASCII) self.assertRaises(ValueError, re.compile, r'(?u)\w', re.ASCII)
self.assertRaises(ValueError, re.compile, r'(?a)\w', re.UNICODE) self.assertRaises(ValueError, re.compile, r'(?a)\w', re.UNICODE)
self.assertRaises(re.error, re.compile, r'(?au)\w') self.assertRaises(re.PatternError, re.compile, r'(?au)\w')
def test_locale_flag(self): def test_locale_flag(self):
enc = locale.getpreferredencoding() enc = locale.getpreferredencoding()
@ -1720,11 +1723,11 @@ class ReTests(unittest.TestCase):
self.assertIsNone(pat.match(bletter)) self.assertIsNone(pat.match(bletter))
# Incompatibilities # Incompatibilities
self.assertRaises(ValueError, re.compile, '', re.LOCALE) self.assertRaises(ValueError, re.compile, '', re.LOCALE)
self.assertRaises(re.error, 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'', re.LOCALE | re.ASCII)
self.assertRaises(ValueError, re.compile, b'(?L)', re.ASCII) self.assertRaises(ValueError, re.compile, b'(?L)', re.ASCII)
self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE) self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE)
self.assertRaises(re.error, re.compile, b'(?aL)') self.assertRaises(re.PatternError, re.compile, b'(?aL)')
def test_scoped_flags(self): def test_scoped_flags(self):
self.assertTrue(re.match(r'(?i:a)b', 'Ab')) self.assertTrue(re.match(r'(?i:a)b', 'Ab'))
@ -2060,7 +2063,7 @@ class ReTests(unittest.TestCase):
self.assertIsNone(p4.match(b'\xc5\xc5')) self.assertIsNone(p4.match(b'\xc5\xc5'))
def test_error(self): def test_error(self):
with self.assertRaises(re.error) as cm: with self.assertRaises(re.PatternError) as cm:
re.compile('(\u20ac))') re.compile('(\u20ac))')
err = cm.exception err = cm.exception
self.assertIsInstance(err.pattern, str) self.assertIsInstance(err.pattern, str)
@ -2072,14 +2075,14 @@ class ReTests(unittest.TestCase):
self.assertIn(' at position 3', str(err)) self.assertIn(' at position 3', str(err))
self.assertNotIn(' at position 3', err.msg) self.assertNotIn(' at position 3', err.msg)
# Bytes pattern # Bytes pattern
with self.assertRaises(re.error) as cm: with self.assertRaises(re.PatternError) as cm:
re.compile(b'(\xa4))') re.compile(b'(\xa4))')
err = cm.exception err = cm.exception
self.assertIsInstance(err.pattern, bytes) self.assertIsInstance(err.pattern, bytes)
self.assertEqual(err.pattern, b'(\xa4))') self.assertEqual(err.pattern, b'(\xa4))')
self.assertEqual(err.pos, 3) self.assertEqual(err.pos, 3)
# Multiline pattern # Multiline pattern
with self.assertRaises(re.error) as cm: with self.assertRaises(re.PatternError) as cm:
re.compile(""" re.compile("""
( (
abc abc
@ -2820,7 +2823,7 @@ class ExternalTests(unittest.TestCase):
with self.subTest(pattern=pattern, string=s): with self.subTest(pattern=pattern, string=s):
if outcome == SYNTAX_ERROR: # Expected a syntax error if outcome == SYNTAX_ERROR: # Expected a syntax error
with self.assertRaises(re.error): with self.assertRaises(re.PatternError):
re.compile(pattern) re.compile(pattern)
continue continue

View File

@ -0,0 +1,3 @@
Renamed :exc:`!re.error` to :exc:`PatternError` for clarity, and kept
:exc:`!re.error` for backward compatibility. Patch by Matthias Bussonnier and
Adam Chhina.