summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/re.rst8
-rw-r--r--Doc/whatsnew/3.13.rst5
-rw-r--r--Lib/idlelib/replace.py2
-rw-r--r--Lib/idlelib/searchengine.py2
-rw-r--r--Lib/pstats.py2
-rw-r--r--Lib/re/__init__.py7
-rw-r--r--Lib/re/_compiler.py6
-rw-r--r--Lib/re/_constants.py5
-rw-r--r--Lib/test/test_re.py47
-rw-r--r--Misc/NEWS.d/next/Library/2023-02-08-00-43-29.gh-issue-83162.ufdI9F.rst3
10 files changed, 53 insertions, 34 deletions
diff --git a/Doc/library/re.rst b/Doc/library/re.rst
index 251ec8c..302f722 100644
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -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
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 00f3968..d599ba9 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -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
-------
diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py
index a29ca59..7997f24 100644
--- a/Lib/idlelib/replace.py
+++ b/Lib/idlelib/replace.py
@@ -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:
diff --git a/Lib/idlelib/searchengine.py b/Lib/idlelib/searchengine.py
index 0684142..ceb38cf 100644
--- a/Lib/idlelib/searchengine.py
+++ b/Lib/idlelib/searchengine.py
@@ -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
diff --git a/Lib/pstats.py b/Lib/pstats.py
index 51bcca8..2f054bb 100644
--- a/Lib/pstats.py
+++ b/Lib/pstats.py
@@ -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 = []
diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py
index 428d1b0..7e8abbf 100644
--- a/Lib/re/__init__.py
+++ b/Lib/re/__init__.py
@@ -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
diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py
index f87712d..7b888f8 100644
--- a/Lib/re/_compiler.py
+++ b/Lib/re/_compiler.py
@@ -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):
diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py
index d8e483a..9c3c294 100644
--- a/Lib/re/_constants.py
+++ b/Lib/re/_constants.py
@@ -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)
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index 1eca22f..993a7d6 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -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
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 0000000..6074dd7
--- /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:`PatternError` for clarity, and kept
+:exc:`!re.error` for backward compatibility. Patch by Matthias Bussonnier and
+Adam Chhina.