gh-133306: Use \z instead of \Z in regular expressions in the stdlib (GH-133337)

This commit is contained in:
Serhiy Storchaka 2025-05-03 17:58:49 +03:00 committed by GitHub
parent add0ca9ea0
commit 84a08f8629
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 23 additions and 23 deletions

View file

@ -371,7 +371,7 @@ def _setoption(arg):
if message: if message:
message = re.escape(message) message = re.escape(message)
if module: if module:
module = re.escape(module) + r'\Z' module = re.escape(module) + r'\z'
if lineno: if lineno:
try: try:
lineno = int(lineno) lineno = int(lineno)

View file

@ -6096,7 +6096,7 @@ def _convert_for_comparison(self, other, equality_op=False):
(?P<diag>\d*) # with (possibly empty) diagnostic info. (?P<diag>\d*) # with (possibly empty) diagnostic info.
) )
# \s* # \s*
\Z \z
""", re.VERBOSE | re.IGNORECASE).match """, re.VERBOSE | re.IGNORECASE).match
_all_zeros = re.compile('0*$').match _all_zeros = re.compile('0*$').match
@ -6124,7 +6124,7 @@ def _convert_for_comparison(self, other, equality_op=False):
(?P<thousands_sep>[,_])? (?P<thousands_sep>[,_])?
(?:\.(?P<precision>0|(?!0)\d+))? (?:\.(?P<precision>0|(?!0)\d+))?
(?P<type>[eEfFgGn%])? (?P<type>[eEfFgGn%])?
\Z \z
""", re.VERBOSE|re.DOTALL) """, re.VERBOSE|re.DOTALL)
del re del re

View file

@ -30,7 +30,7 @@
NLCRE = re.compile(r'\r\n|\r|\n') NLCRE = re.compile(r'\r\n|\r|\n')
NLCRE_bol = 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)') NLCRE_crack = re.compile(r'(\r\n|\r|\n)')
# RFC 2822 $3.6.8 Optional fields. ftext is %d33-57 / %d59-126, Any character # RFC 2822 $3.6.8 Optional fields. ftext is %d33-57 / %d59-126, Any character
# except controls, SP, and ":". # except controls, SP, and ":".

View file

@ -64,7 +64,7 @@ def _hash_algorithm(numerator, denominator):
(?:\.(?P<decimal>\d*|\d+(_\d+)*))? # an optional fractional part (?:\.(?P<decimal>\d*|\d+(_\d+)*))? # an optional fractional part
(?:E(?P<exp>[-+]?\d+(_\d+)*))? # and optional exponent (?:E(?P<exp>[-+]?\d+(_\d+)*))? # and optional exponent
) )
\s*\Z # and optional whitespace to finish \s*\z # and optional whitespace to finish
""", re.VERBOSE | re.IGNORECASE) """, re.VERBOSE | re.IGNORECASE)

View file

@ -1350,7 +1350,7 @@ def recall(self, s, event):
self.text.see("insert") self.text.see("insert")
self.text.undo_block_stop() 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): def runit(self):
index_before = self.text.index("end-2c") index_before = self.text.index("end-2c")
line = self.text.get("iomark", "end-1c") line = self.text.get("iomark", "end-1c")

View file

@ -14,7 +14,7 @@
r'(, value:\d)?' r'(, value:\d)?'
r'(, waiters:\d+)?' r'(, waiters:\d+)?'
r'(, waiters:\d+\/\d+)?' # barrier r'(, waiters:\d+\/\d+)?' # barrier
r')\]>\Z' r')\]>\z'
) )
RGX_REPR = re.compile(STR_RGX_REPR) RGX_REPR = re.compile(STR_RGX_REPR)

View file

@ -300,7 +300,7 @@ def func():
# We're mostly just checking that this doesn't crash. # We're mostly just checking that this doesn't crash.
rc, stdout, stderr = assert_python_ok("-c", code) rc, stdout, stderr = assert_python_ok("-c", code)
self.assertEqual(rc, 0) self.assertEqual(rc, 0)
self.assertRegex(stdout, rb"""\A\s*func=<function at \S+>\s*\Z""") self.assertRegex(stdout, rb"""\A\s*func=<function at \S+>\s*\z""")
self.assertFalse(stderr) self.assertFalse(stderr)
@refcount_test @refcount_test

View file

@ -1001,7 +1001,7 @@ def test_script_shadowing_third_party(self):
expected_error = error + ( expected_error = error + (
rb" \(consider renaming '.*numpy.py' if it has the " 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")) popen = script_helper.spawn_python(os.path.join(tmp, "numpy.py"))
@ -1022,14 +1022,14 @@ def test_script_maybe_not_shadowing_third_party(self):
f.write("this_script_does_not_attempt_to_import_numpy = True") f.write("this_script_does_not_attempt_to_import_numpy = True")
expected_error = ( 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) popen = script_helper.spawn_python('-c', 'import numpy; numpy.attr', cwd=tmp)
stdout, stderr = popen.communicate() stdout, stderr = popen.communicate()
self.assertRegex(stdout, expected_error) self.assertRegex(stdout, expected_error)
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) popen = script_helper.spawn_python('-c', 'from numpy import attr', cwd=tmp)
stdout, stderr = popen.communicate() stdout, stderr = popen.communicate()

View file

@ -6740,7 +6740,7 @@ def test_compute_files_to_delete_same_filename_different_extensions(self):
rotator = rotators[i] rotator = rotators[i]
candidates = rotator.getFilesToDelete() candidates = rotator.getFilesToDelete()
self.assertEqual(len(candidates), n_files - backupCount, candidates) 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: for c in candidates:
d, fn = os.path.split(c) d, fn = os.path.split(c)
self.assertStartsWith(fn, prefix+'.') self.assertStartsWith(fn, prefix+'.')

View file

@ -19,7 +19,7 @@
(?P<int>\d*) # having a (possibly empty) integer part (?P<int>\d*) # having a (possibly empty) integer part
(?:\.(?P<frac>\d*))? # followed by an optional fractional part (?:\.(?P<frac>\d*))? # followed by an optional fractional part
(?:E(?P<exp>[-+]?\d+))? # and an optional exponent (?:E(?P<exp>[-+]?\d+))? # and an optional exponent
\Z \z
""", re.VERBOSE | re.IGNORECASE).match """, re.VERBOSE | re.IGNORECASE).match
# Pure Python version of correctly rounded string->float conversion. # Pure Python version of correctly rounded string->float conversion.

View file

@ -65,7 +65,7 @@ def checkInvalidParam(self, widget, name, value, errmsg=None):
orig = widget[name] orig = widget[name]
if errmsg is not None: if errmsg is not None:
errmsg = errmsg.format(re.escape(str(value))) errmsg = errmsg.format(re.escape(str(value)))
errmsg = fr'\A{errmsg}\Z' errmsg = fr'\A{errmsg}\z'
with self.assertRaisesRegex(tkinter.TclError, errmsg or ''): with self.assertRaisesRegex(tkinter.TclError, errmsg or ''):
widget[name] = value widget[name] = value
self.assertEqual(widget[name], orig) self.assertEqual(widget[name], orig)

View file

@ -490,7 +490,7 @@ def _show_drop_down_listbox(self):
width = self.combo.winfo_width() width = self.combo.winfo_width()
x, y = width - 5, 5 x, y = width - 5, 5
if sys.platform != 'darwin': # there's no down arrow on macOS 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('<Button-1>', x=x, y=y) self.combo.event_generate('<Button-1>', x=x, y=y)
self.combo.event_generate('<ButtonRelease-1>', x=x, y=y) self.combo.event_generate('<ButtonRelease-1>', x=x, y=y)
@ -1250,7 +1250,7 @@ def _click_increment_arrow(self):
height = self.spin.winfo_height() height = self.spin.winfo_height()
x = width - 5 x = width - 5
y = height//2 - 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('<ButtonPress-1>', x=x, y=y) self.spin.event_generate('<ButtonPress-1>', x=x, y=y)
self.spin.event_generate('<ButtonRelease-1>', x=x, y=y) self.spin.event_generate('<ButtonRelease-1>', x=x, y=y)
self.spin.update_idletasks() self.spin.update_idletasks()
@ -1260,7 +1260,7 @@ def _click_decrement_arrow(self):
height = self.spin.winfo_height() height = self.spin.winfo_height()
x = width - 5 x = width - 5
y = height//2 + 4 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('<ButtonPress-1>', x=x, y=y) self.spin.event_generate('<ButtonPress-1>', x=x, y=y)
self.spin.event_generate('<ButtonRelease-1>', x=x, y=y) self.spin.event_generate('<ButtonRelease-1>', x=x, y=y)
self.spin.update_idletasks() self.spin.update_idletasks()

View file

@ -86,7 +86,7 @@ class TextWrapper:
-(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-)) -(?: (?<=%(lt)s{2}-) | (?<=%(lt)s-%(lt)s-))
(?= %(lt)s -? %(lt)s) (?= %(lt)s -? %(lt)s)
| # end of word | # end of word
(?=%(ws)s|\Z) (?=%(ws)s|\z)
| # em-dash | # em-dash
(?<=%(wp)s) (?=-{2,}\w) (?<=%(wp)s) (?=-{2,}\w)
) )
@ -107,7 +107,7 @@ class TextWrapper:
sentence_end_re = re.compile(r'[a-z]' # lowercase letter sentence_end_re = re.compile(r'[a-z]' # lowercase letter
r'[\.\!\?]' # sentence-ending punct. r'[\.\!\?]' # sentence-ending punct.
r'[\"\']?' # optional end-of-quote r'[\"\']?' # optional end-of-quote
r'\Z') # end of chunk r'\z') # end of chunk
def __init__(self, def __init__(self,
width=70, width=70,

View file

@ -132,7 +132,7 @@ def _compile(expr):
group("'", r'\\\r?\n'), group("'", r'\\\r?\n'),
StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' +
group('"', r'\\\r?\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) PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name)
# For a given string prefix plus quotes, endpats maps it to a regex # For a given string prefix plus quotes, endpats maps it to a regex

View file

@ -460,7 +460,7 @@ def _check_bracketed_netloc(netloc):
# https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/
def _check_bracketed_host(hostname): def _check_bracketed_host(hostname):
if hostname.startswith('v'): 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") raise ValueError(f"IPvFuture address is invalid")
else: else:
ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4

View file

@ -37,9 +37,9 @@ def extend(self, pattern):
Apply '(?s:)' to create a non-matching group that Apply '(?s:)' to create a non-matching group that
matches newlines (valid on Unix). 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): def match_dirs(self, pattern):
""" """