Skip to content

Commit

Permalink
GH-116377: Stop raising ValueError from glob.translate(). (#116378)
Browse files Browse the repository at this point in the history
Stop raising `ValueError` from `glob.translate()` when a `**` sub-string
appears in a non-recursive pattern segment. This matches `glob.glob()`
behaviour.
  • Loading branch information
barneygale authored Mar 17, 2024
1 parent 1cf0301 commit 0634201
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 26 deletions.
3 changes: 1 addition & 2 deletions Doc/library/glob.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 (``.``).
Expand Down
33 changes: 14 additions & 19 deletions Lib/glob.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ('.').
Expand Down Expand Up @@ -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'
6 changes: 3 additions & 3 deletions Lib/test/test_glob.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit 0634201

Please sign in to comment.