From 84a08f8629dffae355407cc3239c981a2b7a930a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 3 May 2025 17:58:49 +0300 Subject: [PATCH] gh-133306: Use \z instead of \Z in regular expressions in the stdlib (GH-133337) --- Lib/_py_warnings.py | 2 +- Lib/_pydecimal.py | 4 ++-- Lib/email/feedparser.py | 2 +- Lib/fractions.py | 2 +- Lib/idlelib/pyshell.py | 2 +- Lib/test/test_asyncio/test_locks.py | 2 +- Lib/test/test_gc.py | 2 +- Lib/test/test_import/__init__.py | 6 +++--- Lib/test/test_logging.py | 2 +- Lib/test/test_strtod.py | 2 +- Lib/test/test_tkinter/widget_tests.py | 2 +- Lib/test/test_ttk/test_widgets.py | 6 +++--- Lib/textwrap.py | 4 ++-- Lib/tokenize.py | 2 +- Lib/urllib/parse.py | 2 +- Lib/zipfile/_path/glob.py | 4 ++-- 16 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Lib/_py_warnings.py b/Lib/_py_warnings.py index 3cdc6ffe198..cbaa9445862 100644 --- a/Lib/_py_warnings.py +++ b/Lib/_py_warnings.py @@ -371,7 +371,7 @@ def _setoption(arg): if message: message = re.escape(message) if module: - module = re.escape(module) + r'\Z' + module = re.escape(module) + r'\z' if lineno: try: lineno = int(lineno) diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py index 4b09207eca6..46fa9ffcb1e 100644 --- a/Lib/_pydecimal.py +++ b/Lib/_pydecimal.py @@ -6096,7 +6096,7 @@ _parser = re.compile(r""" # A numeric string consists of: (?P\d*) # with (possibly empty) diagnostic info. ) # \s* - \Z + \z """, re.VERBOSE | re.IGNORECASE).match _all_zeros = re.compile('0*$').match @@ -6124,7 +6124,7 @@ _parse_format_specifier_regex = re.compile(r"""\A (?P[,_])? (?:\.(?P0|(?!0)\d+))? (?P[eEfFgGn%])? -\Z +\z """, re.VERBOSE|re.DOTALL) del re diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index b2bc4afc1cc..9d80a5822af 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -30,7 +30,7 @@ from io import StringIO NLCRE = re.compile(r'\r\n|\r|\n') NLCRE_bol = re.compile(r'(\r\n|\r|\n)') -NLCRE_eol = re.compile(r'(\r\n|\r|\n)\Z') +NLCRE_eol = re.compile(r'(\r\n|\r|\n)\z') NLCRE_crack = re.compile(r'(\r\n|\r|\n)') # RFC 2822 $3.6.8 Optional fields. ftext is %d33-57 / %d59-126, Any character # except controls, SP, and ":". diff --git a/Lib/fractions.py b/Lib/fractions.py index fa722589fb4..8163e3bb594 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -64,7 +64,7 @@ _RATIONAL_FORMAT = re.compile(r""" (?:\.(?P\d*|\d+(_\d+)*))? # an optional fractional part (?:E(?P[-+]?\d+(_\d+)*))? # and optional exponent ) - \s*\Z # and optional whitespace to finish + \s*\z # and optional whitespace to finish """, re.VERBOSE | re.IGNORECASE) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 60b63d58cdd..74a0e03994f 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1350,7 +1350,7 @@ class PyShell(OutputWindow): self.text.see("insert") self.text.undo_block_stop() - _last_newline_re = re.compile(r"[ \t]*(\n[ \t]*)?\Z") + _last_newline_re = re.compile(r"[ \t]*(\n[ \t]*)?\z") def runit(self): index_before = self.text.index("end-2c") line = self.text.get("iomark", "end-1c") diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py index 3bb3e5c4ca0..047f03cbb14 100644 --- a/Lib/test/test_asyncio/test_locks.py +++ b/Lib/test/test_asyncio/test_locks.py @@ -14,7 +14,7 @@ STR_RGX_REPR = ( r'(, value:\d)?' r'(, waiters:\d+)?' r'(, waiters:\d+\/\d+)?' # barrier - r')\]>\Z' + r')\]>\z' ) RGX_REPR = re.compile(STR_RGX_REPR) diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index b5140057a69..8fae12c478c 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -300,7 +300,7 @@ class GCTests(unittest.TestCase): # We're mostly just checking that this doesn't crash. rc, stdout, stderr = assert_python_ok("-c", code) self.assertEqual(rc, 0) - self.assertRegex(stdout, rb"""\A\s*func=\s*\Z""") + self.assertRegex(stdout, rb"""\A\s*func=\s*\z""") self.assertFalse(stderr) @refcount_test diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index b5f4645847a..6e34094c5aa 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1001,7 +1001,7 @@ from not_a_module import symbol expected_error = error + ( rb" \(consider renaming '.*numpy.py' if it has the " - rb"same name as a library you intended to import\)\s+\Z" + rb"same name as a library you intended to import\)\s+\z" ) popen = script_helper.spawn_python(os.path.join(tmp, "numpy.py")) @@ -1022,14 +1022,14 @@ from not_a_module import symbol f.write("this_script_does_not_attempt_to_import_numpy = True") expected_error = ( - rb"AttributeError: module 'numpy' has no attribute 'attr'\s+\Z" + rb"AttributeError: module 'numpy' has no attribute 'attr'\s+\z" ) popen = script_helper.spawn_python('-c', 'import numpy; numpy.attr', cwd=tmp) stdout, stderr = popen.communicate() self.assertRegex(stdout, expected_error) expected_error = ( - rb"ImportError: cannot import name 'attr' from 'numpy' \(.*\)\s+\Z" + rb"ImportError: cannot import name 'attr' from 'numpy' \(.*\)\s+\z" ) popen = script_helper.spawn_python('-c', 'from numpy import attr', cwd=tmp) stdout, stderr = popen.communicate() diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index de9108288a7..3f113ec1be4 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -6740,7 +6740,7 @@ class TimedRotatingFileHandlerTest(BaseFileTest): rotator = rotators[i] candidates = rotator.getFilesToDelete() self.assertEqual(len(candidates), n_files - backupCount, candidates) - matcher = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\Z") + matcher = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\z") for c in candidates: d, fn = os.path.split(c) self.assertStartsWith(fn, prefix+'.') diff --git a/Lib/test/test_strtod.py b/Lib/test/test_strtod.py index 2727514fad4..570de390a95 100644 --- a/Lib/test/test_strtod.py +++ b/Lib/test/test_strtod.py @@ -19,7 +19,7 @@ strtod_parser = re.compile(r""" # A numeric string consists of: (?P\d*) # having a (possibly empty) integer part (?:\.(?P\d*))? # followed by an optional fractional part (?:E(?P[-+]?\d+))? # and an optional exponent - \Z + \z """, re.VERBOSE | re.IGNORECASE).match # Pure Python version of correctly rounded string->float conversion. diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index ac7fb5977e0..f518925e994 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -65,7 +65,7 @@ class AbstractWidgetTest(AbstractTkTest): orig = widget[name] if errmsg is not None: errmsg = errmsg.format(re.escape(str(value))) - errmsg = fr'\A{errmsg}\Z' + errmsg = fr'\A{errmsg}\z' with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): widget[name] = value self.assertEqual(widget[name], orig) diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index d5620becfa7..f33da2a8848 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -490,7 +490,7 @@ class ComboboxTest(EntryTest, unittest.TestCase): width = self.combo.winfo_width() x, y = width - 5, 5 if sys.platform != 'darwin': # there's no down arrow on macOS - self.assertRegex(self.combo.identify(x, y), r'.*downarrow\Z') + self.assertRegex(self.combo.identify(x, y), r'.*downarrow\z') self.combo.event_generate('', x=x, y=y) self.combo.event_generate('', x=x, y=y) @@ -1250,7 +1250,7 @@ class SpinboxTest(EntryTest, unittest.TestCase): height = self.spin.winfo_height() x = width - 5 y = height//2 - 5 - self.assertRegex(self.spin.identify(x, y), r'.*uparrow\Z') + self.assertRegex(self.spin.identify(x, y), r'.*uparrow\z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() @@ -1260,7 +1260,7 @@ class SpinboxTest(EntryTest, unittest.TestCase): height = self.spin.winfo_height() x = width - 5 y = height//2 + 4 - self.assertRegex(self.spin.identify(x, y), r'.*downarrow\Z') + self.assertRegex(self.spin.identify(x, y), r'.*downarrow\z') self.spin.event_generate('', x=x, y=y) self.spin.event_generate('', x=x, y=y) self.spin.update_idletasks() diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 00465f67d09..5ae439f5cd3 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -86,7 +86,7 @@ class TextWrapper: -(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-)) (?= %(lt)s -? %(lt)s) | # end of word - (?=%(ws)s|\Z) + (?=%(ws)s|\z) | # em-dash (?<=%(wp)s) (?=-{2,}\w) ) @@ -107,7 +107,7 @@ class TextWrapper: sentence_end_re = re.compile(r'[a-z]' # lowercase letter r'[\.\!\?]' # sentence-ending punct. r'[\"\']?' # optional end-of-quote - r'\Z') # end of chunk + r'\z') # end of chunk def __init__(self, width=70, diff --git a/Lib/tokenize.py b/Lib/tokenize.py index edb1ed8bdb8..117b485b934 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -132,7 +132,7 @@ ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r'\\\r?\n'), StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r'\\\r?\n')) -PseudoExtras = group(r'\\\r?\n|\Z', Comment, Triple) +PseudoExtras = group(r'\\\r?\n|\z', Comment, Triple) PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) # For a given string prefix plus quotes, endpats maps it to a regex diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 9d51f4c6812..67d9bbea0d3 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -460,7 +460,7 @@ def _check_bracketed_netloc(netloc): # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ def _check_bracketed_host(hostname): if hostname.startswith('v'): - if not re.match(r"\Av[a-fA-F0-9]+\..+\Z", hostname): + if not re.match(r"\Av[a-fA-F0-9]+\..+\z", hostname): raise ValueError(f"IPvFuture address is invalid") else: ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 diff --git a/Lib/zipfile/_path/glob.py b/Lib/zipfile/_path/glob.py index 4320f1c0bad..d7fe45a4947 100644 --- a/Lib/zipfile/_path/glob.py +++ b/Lib/zipfile/_path/glob.py @@ -37,9 +37,9 @@ class Translator: Apply '(?s:)' to create a non-matching group that matches newlines (valid on Unix). - Append '\Z' to imply fullmatch even when match is used. + Append '\z' to imply fullmatch even when match is used. """ - return rf'(?s:{pattern})\Z' + return rf'(?s:{pattern})\z' def match_dirs(self, pattern): """