https://github.com/python/cpython/commit/0634201f5391242524dbb5225de37f81a2cc1826
commit: 0634201f5391242524dbb5225de37f81a2cc1826
branch: main
author: Barney Gale <[email protected]>
committer: barneygale <[email protected]>
date: 2024-03-17T17:09:35Z
summary:
GH-116377: Stop raising `ValueError` from `glob.translate()`. (#116378)
Stop raising `ValueError` from `glob.translate()` when a `**` sub-string
appears in a non-recursive pattern segment. This matches `glob.glob()`
behaviour.
files:
M Doc/library/glob.rst
M Lib/glob.py
M Lib/test/test_glob.py
M Lib/test/test_pathlib/test_pathlib_abc.py
diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst
index 19a0bbba8966ba..15fef747296ed4 100644
--- a/Doc/library/glob.rst
+++ b/Doc/library/glob.rst
@@ -136,8 +136,7 @@ The :mod:`glob` module defines the following functions:
separators, and ``*`` pattern segments match precisely one path segment.
If *recursive* is true, the pattern segment "``**``" will match any number
- of path segments. If "``**``" occurs in any position other than a full
- pattern segment, :exc:`ValueError` is raised.
+ of path segments.
If *include_hidden* is true, wildcards can match path segments that start
with a dot (``.``).
diff --git a/Lib/glob.py b/Lib/glob.py
index 343be78a73b20a..473502c67336f9 100644
--- a/Lib/glob.py
+++ b/Lib/glob.py
@@ -256,8 +256,7 @@ def translate(pat, *, recursive=False,
include_hidden=False, seps=None):
"""Translate a pathname with shell wildcards to a regular expression.
If `recursive` is true, the pattern segment '**' will match any number of
- path segments; if '**' appears outside its own segment, ValueError will be
- raised.
+ path segments.
If `include_hidden` is true, wildcards can match path segments beginning
with a dot ('.').
@@ -291,22 +290,18 @@ def translate(pat, *, recursive=False,
include_hidden=False, seps=None):
for idx, part in enumerate(parts):
if part == '*':
results.append(one_segment if idx < last_part_idx else
one_last_segment)
- continue
- if recursive:
- if part == '**':
- if idx < last_part_idx:
- if parts[idx + 1] != '**':
- results.append(any_segments)
- else:
- results.append(any_last_segments)
- continue
- elif '**' in part:
- raise ValueError("Invalid pattern: '**' can only be an entire
path component")
- if part:
- if not include_hidden and part[0] in '*?':
- results.append(r'(?!\.)')
- results.extend(fnmatch._translate(part, f'{not_sep}*', not_sep))
- if idx < last_part_idx:
- results.append(any_sep)
+ elif recursive and part == '**':
+ if idx < last_part_idx:
+ if parts[idx + 1] != '**':
+ results.append(any_segments)
+ else:
+ results.append(any_last_segments)
+ else:
+ if part:
+ if not include_hidden and part[0] in '*?':
+ results.append(r'(?!\.)')
+ results.extend(fnmatch._translate(part, f'{not_sep}*',
not_sep))
+ if idx < last_part_idx:
+ results.append(any_sep)
res = ''.join(results)
return fr'(?s:{res})\Z'
diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py
index 1fdf2817e236f6..2de997501039ad 100644
--- a/Lib/test/test_glob.py
+++ b/Lib/test/test_glob.py
@@ -452,9 +452,9 @@ def fn(pat):
self.assertEqual(fn('?'), r'(?s:[^/])\Z')
self.assertEqual(fn('**'), r'(?s:.*)\Z')
self.assertEqual(fn('**/**'), r'(?s:.*)\Z')
- self.assertRaises(ValueError, fn, '***')
- self.assertRaises(ValueError, fn, 'a**')
- self.assertRaises(ValueError, fn, '**b')
+ self.assertEqual(fn('***'), r'(?s:[^/]*)\Z')
+ self.assertEqual(fn('a**'), r'(?s:a[^/]*)\Z')
+ self.assertEqual(fn('**b'), r'(?s:[^/]*b)\Z')
self.assertEqual(fn('/**/*/*.*/**'),
r'(?s:/(?:.+/)?[^/]+/[^/]*\.[^/]*/.*)\Z')
def test_translate_seps(self):
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py
b/Lib/test/test_pathlib/test_pathlib_abc.py
index fb467a015a80d2..840fb903fd5338 100644
--- a/Lib/test/test_pathlib/test_pathlib_abc.py
+++ b/Lib/test/test_pathlib/test_pathlib_abc.py
@@ -512,8 +512,6 @@ def test_full_match_common(self):
self.assertFalse(P('a/b/c.py').full_match('**/a/b/c./**'))
self.assertFalse(P('a/b/c.py').full_match('/a/b/c.py/**'))
self.assertFalse(P('a/b/c.py').full_match('/**/a/b/c.py'))
- self.assertRaises(ValueError, P('a').full_match, '**a/b/c')
- self.assertRaises(ValueError, P('a').full_match, 'a/b/c**')
# Case-sensitive flag
self.assertFalse(P('A.py').full_match('a.PY', case_sensitive=True))
self.assertTrue(P('A.py').full_match('a.PY', case_sensitive=False))
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]