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

View File

@ -298,6 +298,11 @@ pdb
command line option or :envvar:`PYTHONSAFEPATH` environment variable).
(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
-------

View File

@ -120,7 +120,7 @@ class ReplaceDialog(SearchDialogBase):
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:

View File

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

View File

@ -329,7 +329,7 @@ class Stats:
if isinstance(sel, str):
try:
rex = re.compile(sel)
except re.error:
except re.PatternError:
msg += " <Invalid regular expression %r>\n" % sel
return new_list, msg
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
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",
"error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U",
"ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
"UNICODE", "NOFLAG", "RegexFlag",
"UNICODE", "NOFLAG", "RegexFlag", "PatternError"
]
__version__ = "2.2.1"
@ -155,7 +156,7 @@ class RegexFlag:
_numeric_repr_ = hex
# sre exception
error = _compiler.error
PatternError = error = _compiler.PatternError
# --------------------------------------------------------------------
# public interface

View File

@ -150,7 +150,7 @@ def _compile(code, pattern, flags):
if lo > MAXCODE:
raise error("looks too much behind")
if lo != hi:
raise error("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 error("internal: unsupported operand type %r" % (op,))
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 error("internal: unsupported set operator %r" % (op,))
raise PatternError(f"internal: unsupported set operator {op!r}")
emit(FAILURE)
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)
# should this really be here?
class error(Exception):
class PatternError(Exception):
"""Exception raised for invalid regular expressions.
Attributes:
@ -53,6 +53,9 @@ class error(Exception):
super().__init__(msg)
# Backward compatibility after renaming in 3.13
error = PatternError
class _NamedIntConstant(int):
def __new__(cls, value, name):
self = super(_NamedIntConstant, cls).__new__(cls, value)

View File

@ -47,7 +47,7 @@ class ReTests(unittest.TestCase):
recurse(actual, expect)
def checkPatternError(self, pattern, errmsg, pos=None):
with self.assertRaises(re.error) as cm:
with self.assertRaises(re.PatternError) as cm:
re.compile(pattern)
with self.subTest(pattern=pattern):
err = cm.exception
@ -56,7 +56,7 @@ class ReTests(unittest.TestCase):
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.PatternError) as cm:
re.sub(pattern, repl, string)
with self.subTest(pattern=pattern, repl=repl):
err = cm.exception
@ -64,6 +64,9 @@ class ReTests(unittest.TestCase):
if pos is not None:
self.assertEqual(err.pos, pos)
def test_error_is_PatternError_alias(self):
assert re.error is re.PatternError
def test_keep_buffer(self):
# See bug 14212
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)))
for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
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(r'^\s*', 'X', 'test'), 'Xtest')
@ -836,10 +839,10 @@ class ReTests(unittest.TestCase):
re.purge() # for warnings
for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY':
with self.subTest(c):
self.assertRaises(re.error, re.compile, '\\%c' % c)
self.assertRaises(re.PatternError, re.compile, '\\%c' % c)
for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ':
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):
# 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.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.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.error, re.compile, r'(a)b(?<=(.)\2)(c)')
self.assertRaises(re.error, 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.error, 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<a>.)(?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")
@ -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%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.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"))
@ -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%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.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)
@ -1675,11 +1678,11 @@ class ReTests(unittest.TestCase):
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.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.error, re.compile, r'(?au)\w')
self.assertRaises(re.PatternError, re.compile, r'(?au)\w')
def test_locale_flag(self):
enc = locale.getpreferredencoding()
@ -1720,11 +1723,11 @@ class ReTests(unittest.TestCase):
self.assertIsNone(pat.match(bletter))
# Incompatibilities
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'(?L)', re.ASCII)
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):
self.assertTrue(re.match(r'(?i:a)b', 'Ab'))
@ -2060,7 +2063,7 @@ class ReTests(unittest.TestCase):
self.assertIsNone(p4.match(b'\xc5\xc5'))
def test_error(self):
with self.assertRaises(re.error) as cm:
with self.assertRaises(re.PatternError) as cm:
re.compile('(\u20ac))')
err = cm.exception
self.assertIsInstance(err.pattern, str)
@ -2072,14 +2075,14 @@ class ReTests(unittest.TestCase):
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.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.error) as cm:
with self.assertRaises(re.PatternError) as cm:
re.compile("""
(
abc
@ -2820,7 +2823,7 @@ class ExternalTests(unittest.TestCase):
with self.subTest(pattern=pattern, string=s):
if outcome == SYNTAX_ERROR: # Expected a syntax error
with self.assertRaises(re.error):
with self.assertRaises(re.PatternError):
re.compile(pattern)
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.