Skip to content

Commit a01022a

Browse files
achhinaMatthias Bussonnierhugovkterryjreedy
authored
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 <[email protected]> Co-authored-by: Hugo van Kemenade <[email protected]> Co-authored-by: Terry Jan Reedy <[email protected]>
1 parent 0066ab5 commit a01022a

File tree

10 files changed

+53
-34
lines changed

10 files changed

+53
-34
lines changed

Doc/library/re.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,12 +1093,12 @@ Functions
10931093
Exceptions
10941094
^^^^^^^^^^
10951095

1096-
.. exception:: error(msg, pattern=None, pos=None)
1096+
.. exception:: PatternError(msg, pattern=None, pos=None)
10971097

10981098
Exception raised when a string passed to one of the functions here is not a
10991099
valid regular expression (for example, it might contain unmatched parentheses)
11001100
or when some other error occurs during compilation or matching. It is never an
1101-
error if a string contains no match for a pattern. The error instance has
1101+
error if a string contains no match for a pattern. The ``PatternError`` instance has
11021102
the following additional attributes:
11031103

11041104
.. attribute:: msg
@@ -1124,6 +1124,10 @@ Exceptions
11241124
.. versionchanged:: 3.5
11251125
Added additional attributes.
11261126

1127+
.. versionchanged:: 3.13
1128+
``PatternError`` was originally named ``error``; the latter is kept as an alias for
1129+
backward compatibility.
1130+
11271131
.. _re-objects:
11281132

11291133
Regular Expression Objects

Doc/whatsnew/3.13.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ pdb
298298
command line option or :envvar:`PYTHONSAFEPATH` environment variable).
299299
(Contributed by Tian Gao and Christian Walther in :gh:`111762`.)
300300

301+
re
302+
--
303+
* Rename :exc:`!re.error` to :exc:`re.PatternError` for improved clarity.
304+
:exc:`!re.error` is kept for backward compatibility.
305+
301306
sqlite3
302307
-------
303308

Lib/idlelib/replace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def _replace_expand(self, m, repl):
120120
if self.engine.isre():
121121
try:
122122
new = m.expand(repl)
123-
except re.error:
123+
except re.PatternError:
124124
self.engine.report_error(repl, 'Invalid Replace Expression')
125125
new = None
126126
else:

Lib/idlelib/searchengine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def getprog(self):
8484
flags = flags | re.IGNORECASE
8585
try:
8686
prog = re.compile(pat, flags)
87-
except re.error as e:
87+
except re.PatternError as e:
8888
self.report_error(pat, e.msg, e.pos)
8989
return None
9090
return prog

Lib/pstats.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ def eval_print_amount(self, sel, list, msg):
329329
if isinstance(sel, str):
330330
try:
331331
rex = re.compile(sel)
332-
except re.error:
332+
except re.PatternError:
333333
msg += " <Invalid regular expression %r>\n" % sel
334334
return new_list, msg
335335
new_list = []

Lib/re/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@
117117
U UNICODE For compatibility only. Ignored for string patterns (it
118118
is the default), and forbidden for bytes patterns.
119119
120-
This module also defines an exception 'error'.
120+
This module also defines exception 'PatternError', aliased to 'error' for
121+
backward compatibility.
121122
122123
"""
123124

@@ -133,7 +134,7 @@
133134
"findall", "finditer", "compile", "purge", "escape",
134135
"error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U",
135136
"ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE",
136-
"UNICODE", "NOFLAG", "RegexFlag",
137+
"UNICODE", "NOFLAG", "RegexFlag", "PatternError"
137138
]
138139

139140
__version__ = "2.2.1"
@@ -155,7 +156,7 @@ class RegexFlag:
155156
_numeric_repr_ = hex
156157

157158
# sre exception
158-
error = _compiler.error
159+
PatternError = error = _compiler.PatternError
159160

160161
# --------------------------------------------------------------------
161162
# public interface

Lib/re/_compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def _compile(code, pattern, flags):
150150
if lo > MAXCODE:
151151
raise error("looks too much behind")
152152
if lo != hi:
153-
raise error("look-behind requires fixed-width pattern")
153+
raise PatternError("look-behind requires fixed-width pattern")
154154
emit(lo) # look behind
155155
_compile(code, av[1], flags)
156156
emit(SUCCESS)
@@ -209,7 +209,7 @@ def _compile(code, pattern, flags):
209209
else:
210210
code[skipyes] = _len(code) - skipyes + 1
211211
else:
212-
raise error("internal: unsupported operand type %r" % (op,))
212+
raise PatternError(f"internal: unsupported operand type {op!r}")
213213

214214
def _compile_charset(charset, flags, code):
215215
# compile charset subprogram
@@ -235,7 +235,7 @@ def _compile_charset(charset, flags, code):
235235
else:
236236
emit(av)
237237
else:
238-
raise error("internal: unsupported set operator %r" % (op,))
238+
raise PatternError(f"internal: unsupported set operator {op!r}")
239239
emit(FAILURE)
240240

241241
def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):

Lib/re/_constants.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# SRE standard exception (access as sre.error)
2121
# should this really be here?
2222

23-
class error(Exception):
23+
class PatternError(Exception):
2424
"""Exception raised for invalid regular expressions.
2525
2626
Attributes:
@@ -53,6 +53,9 @@ def __init__(self, msg, pattern=None, pos=None):
5353
super().__init__(msg)
5454

5555

56+
# Backward compatibility after renaming in 3.13
57+
error = PatternError
58+
5659
class _NamedIntConstant(int):
5760
def __new__(cls, value, name):
5861
self = super(_NamedIntConstant, cls).__new__(cls, value)

Lib/test/test_re.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def recurse(actual, expect):
4747
recurse(actual, expect)
4848

4949
def checkPatternError(self, pattern, errmsg, pos=None):
50-
with self.assertRaises(re.error) as cm:
50+
with self.assertRaises(re.PatternError) as cm:
5151
re.compile(pattern)
5252
with self.subTest(pattern=pattern):
5353
err = cm.exception
@@ -56,14 +56,17 @@ def checkPatternError(self, pattern, errmsg, pos=None):
5656
self.assertEqual(err.pos, pos)
5757

5858
def checkTemplateError(self, pattern, repl, string, errmsg, pos=None):
59-
with self.assertRaises(re.error) as cm:
59+
with self.assertRaises(re.PatternError) as cm:
6060
re.sub(pattern, repl, string)
6161
with self.subTest(pattern=pattern, repl=repl):
6262
err = cm.exception
6363
self.assertEqual(err.msg, errmsg)
6464
if pos is not None:
6565
self.assertEqual(err.pos, pos)
6666

67+
def test_error_is_PatternError_alias(self):
68+
assert re.error is re.PatternError
69+
6770
def test_keep_buffer(self):
6871
# See bug 14212
6972
b = bytearray(b'x')
@@ -154,7 +157,7 @@ def test_basic_re_sub(self):
154157
(chr(9)+chr(10)+chr(11)+chr(13)+chr(12)+chr(7)+chr(8)))
155158
for c in 'cdehijklmopqsuwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
156159
with self.subTest(c):
157-
with self.assertRaises(re.error):
160+
with self.assertRaises(re.PatternError):
158161
self.assertEqual(re.sub('a', '\\' + c, 'a'), '\\' + c)
159162

160163
self.assertEqual(re.sub(r'^\s*', 'X', 'test'), 'Xtest')
@@ -836,10 +839,10 @@ def test_other_escapes(self):
836839
re.purge() # for warnings
837840
for c in 'ceghijklmopqyzCEFGHIJKLMNOPQRTVXY':
838841
with self.subTest(c):
839-
self.assertRaises(re.error, re.compile, '\\%c' % c)
842+
self.assertRaises(re.PatternError, re.compile, '\\%c' % c)
840843
for c in 'ceghijklmopqyzABCEFGHIJKLMNOPQRTVXYZ':
841844
with self.subTest(c):
842-
self.assertRaises(re.error, re.compile, '[\\%c]' % c)
845+
self.assertRaises(re.PatternError, re.compile, '[\\%c]' % c)
843846

844847
def test_named_unicode_escapes(self):
845848
# test individual Unicode named escapes
@@ -970,14 +973,14 @@ def test_lookbehind(self):
970973
self.assertIsNone(re.match(r'(?:(a)|(x))b(?<=(?(1)c|x))c', 'abc'))
971974
self.assertTrue(re.match(r'(?:(a)|(x))b(?<=(?(1)b|x))c', 'abc'))
972975
# Group used before defined.
973-
self.assertRaises(re.error, re.compile, r'(a)b(?<=(?(2)b|x))(c)')
976+
self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(?(2)b|x))(c)')
974977
self.assertIsNone(re.match(r'(a)b(?<=(?(1)c|x))(c)', 'abc'))
975978
self.assertTrue(re.match(r'(a)b(?<=(?(1)b|x))(c)', 'abc'))
976979
# Group defined in the same lookbehind pattern
977-
self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)\2)(c)')
978-
self.assertRaises(re.error, re.compile, r'(a)b(?<=(?P<a>.)(?P=a))(c)')
979-
self.assertRaises(re.error, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)')
980-
self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)(?<=\2))(c)')
980+
self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)\2)(c)')
981+
self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(?P<a>.)(?P=a))(c)')
982+
self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)')
983+
self.assertRaises(re.PatternError, re.compile, r'(a)b(?<=(.)(?<=\2))(c)')
981984

982985
def test_ignore_case(self):
983986
self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC")
@@ -1318,8 +1321,8 @@ def test_sre_byte_literals(self):
13181321
self.assertTrue(re.match((r"\x%02x" % i).encode(), bytes([i])))
13191322
self.assertTrue(re.match((r"\x%02x0" % i).encode(), bytes([i])+b"0"))
13201323
self.assertTrue(re.match((r"\x%02xz" % i).encode(), bytes([i])+b"z"))
1321-
self.assertRaises(re.error, re.compile, br"\u1234")
1322-
self.assertRaises(re.error, re.compile, br"\U00012345")
1324+
self.assertRaises(re.PatternError, re.compile, br"\u1234")
1325+
self.assertRaises(re.PatternError, re.compile, br"\U00012345")
13231326
self.assertTrue(re.match(br"\0", b"\000"))
13241327
self.assertTrue(re.match(br"\08", b"\0008"))
13251328
self.assertTrue(re.match(br"\01", b"\001"))
@@ -1341,8 +1344,8 @@ def test_sre_byte_class_literals(self):
13411344
self.assertTrue(re.match((r"[\x%02x]" % i).encode(), bytes([i])))
13421345
self.assertTrue(re.match((r"[\x%02x0]" % i).encode(), bytes([i])))
13431346
self.assertTrue(re.match((r"[\x%02xz]" % i).encode(), bytes([i])))
1344-
self.assertRaises(re.error, re.compile, br"[\u1234]")
1345-
self.assertRaises(re.error, re.compile, br"[\U00012345]")
1347+
self.assertRaises(re.PatternError, re.compile, br"[\u1234]")
1348+
self.assertRaises(re.PatternError, re.compile, br"[\U00012345]")
13461349
self.checkPatternError(br"[\567]",
13471350
r'octal escape value \567 outside of '
13481351
r'range 0-0o377', 1)
@@ -1675,11 +1678,11 @@ def test_ascii_and_unicode_flag(self):
16751678
self.assertIsNone(pat.match(b'\xe0'))
16761679
# Incompatibilities
16771680
self.assertRaises(ValueError, re.compile, br'\w', re.UNICODE)
1678-
self.assertRaises(re.error, re.compile, br'(?u)\w')
1681+
self.assertRaises(re.PatternError, re.compile, br'(?u)\w')
16791682
self.assertRaises(ValueError, re.compile, r'\w', re.UNICODE | re.ASCII)
16801683
self.assertRaises(ValueError, re.compile, r'(?u)\w', re.ASCII)
16811684
self.assertRaises(ValueError, re.compile, r'(?a)\w', re.UNICODE)
1682-
self.assertRaises(re.error, re.compile, r'(?au)\w')
1685+
self.assertRaises(re.PatternError, re.compile, r'(?au)\w')
16831686

16841687
def test_locale_flag(self):
16851688
enc = locale.getpreferredencoding()
@@ -1720,11 +1723,11 @@ def test_locale_flag(self):
17201723
self.assertIsNone(pat.match(bletter))
17211724
# Incompatibilities
17221725
self.assertRaises(ValueError, re.compile, '', re.LOCALE)
1723-
self.assertRaises(re.error, re.compile, '(?L)')
1726+
self.assertRaises(re.PatternError, re.compile, '(?L)')
17241727
self.assertRaises(ValueError, re.compile, b'', re.LOCALE | re.ASCII)
17251728
self.assertRaises(ValueError, re.compile, b'(?L)', re.ASCII)
17261729
self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE)
1727-
self.assertRaises(re.error, re.compile, b'(?aL)')
1730+
self.assertRaises(re.PatternError, re.compile, b'(?aL)')
17281731

17291732
def test_scoped_flags(self):
17301733
self.assertTrue(re.match(r'(?i:a)b', 'Ab'))
@@ -2060,7 +2063,7 @@ def test_locale_compiled(self):
20602063
self.assertIsNone(p4.match(b'\xc5\xc5'))
20612064

20622065
def test_error(self):
2063-
with self.assertRaises(re.error) as cm:
2066+
with self.assertRaises(re.PatternError) as cm:
20642067
re.compile('(\u20ac))')
20652068
err = cm.exception
20662069
self.assertIsInstance(err.pattern, str)
@@ -2072,14 +2075,14 @@ def test_error(self):
20722075
self.assertIn(' at position 3', str(err))
20732076
self.assertNotIn(' at position 3', err.msg)
20742077
# Bytes pattern
2075-
with self.assertRaises(re.error) as cm:
2078+
with self.assertRaises(re.PatternError) as cm:
20762079
re.compile(b'(\xa4))')
20772080
err = cm.exception
20782081
self.assertIsInstance(err.pattern, bytes)
20792082
self.assertEqual(err.pattern, b'(\xa4))')
20802083
self.assertEqual(err.pos, 3)
20812084
# Multiline pattern
2082-
with self.assertRaises(re.error) as cm:
2085+
with self.assertRaises(re.PatternError) as cm:
20832086
re.compile("""
20842087
(
20852088
abc
@@ -2820,7 +2823,7 @@ def test_re_tests(self):
28202823

28212824
with self.subTest(pattern=pattern, string=s):
28222825
if outcome == SYNTAX_ERROR: # Expected a syntax error
2823-
with self.assertRaises(re.error):
2826+
with self.assertRaises(re.PatternError):
28242827
re.compile(pattern)
28252828
continue
28262829

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Renamed :exc:`!re.error` to :exc:`PatternError` for clarity, and kept
2+
:exc:`!re.error` for backward compatibility. Patch by Matthias Bussonnier and
3+
Adam Chhina.

0 commit comments

Comments
 (0)