Skip to content

Commit f2e6adf

Browse files
committed
pythonGH-116377: Stop raising ValueError from glob.translate().
Stop raising `ValueError` from `glob.translate()` when a `**` sub-string appears in a non-recursive pattern segment. This matches `glob.glob()` behaviour.
1 parent ffed8d9 commit f2e6adf

3 files changed

Lines changed: 18 additions & 24 deletions

File tree

‎Doc/library/glob.rst‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ The :mod:`glob` module defines the following functions:
136136
separators, and ``*`` pattern segments match precisely one path segment.
137137

138138
If *recursive* is true, the pattern segment "``**``" will match any number
139-
of path segments. If "``**``" occurs in any position other than a full
140-
pattern segment, :exc:`ValueError` is raised.
139+
of path segments.
141140

142141
If *include_hidden* is true, wildcards can match path segments that start
143142
with a dot (``.``).

‎Lib/glob.py‎

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,7 @@ def translate(pat, *, recursive=False, include_hidden=False, seps=None):
256256
"""Translate a pathname with shell wildcards to a regular expression.
257257
258258
If `recursive` is true, the pattern segment '**' will match any number of
259-
path segments; if '**' appears outside its own segment, ValueError will be
260-
raised.
259+
path segments.
261260
262261
If `include_hidden` is true, wildcards can match path segments beginning
263262
with a dot ('.').
@@ -291,22 +290,18 @@ def translate(pat, *, recursive=False, include_hidden=False, seps=None):
291290
for idx, part in enumerate(parts):
292291
if part == '*':
293292
results.append(one_segment if idx < last_part_idx else one_last_segment)
294-
continue
295-
if recursive:
296-
if part == '**':
297-
if idx < last_part_idx:
298-
if parts[idx + 1] != '**':
299-
results.append(any_segments)
300-
else:
301-
results.append(any_last_segments)
302-
continue
303-
elif '**' in part:
304-
raise ValueError("Invalid pattern: '**' can only be an entire path component")
305-
if part:
306-
if not include_hidden and part[0] in '*?':
307-
results.append(r'(?!\.)')
308-
results.extend(fnmatch._translate(part, f'{not_sep}*', not_sep))
309-
if idx < last_part_idx:
310-
results.append(any_sep)
293+
elif recursive and part == '**':
294+
if idx < last_part_idx:
295+
if parts[idx + 1] != '**':
296+
results.append(any_segments)
297+
else:
298+
results.append(any_last_segments)
299+
else:
300+
if part:
301+
if not include_hidden and part[0] in '*?':
302+
results.append(r'(?!\.)')
303+
results.extend(fnmatch._translate(part, f'{not_sep}*', not_sep))
304+
if idx < last_part_idx:
305+
results.append(any_sep)
311306
res = ''.join(results)
312307
return fr'(?s:{res})\Z'

‎Lib/test/test_glob.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,9 @@ def fn(pat):
440440
self.assertEqual(fn('?'), r'(?s:[^/])\Z')
441441
self.assertEqual(fn('**'), r'(?s:.*)\Z')
442442
self.assertEqual(fn('**/**'), r'(?s:.*)\Z')
443-
self.assertRaises(ValueError, fn, '***')
444-
self.assertRaises(ValueError, fn, 'a**')
445-
self.assertRaises(ValueError, fn, '**b')
443+
self.assertEqual(fn('***'), r'(?s:[^/]*)\Z')
444+
self.assertEqual(fn('a**'), r'(?s:a[^/]*)\Z')
445+
self.assertEqual(fn('**b'), r'(?s:[^/]*b)\Z')
446446
self.assertEqual(fn('/**/*/*.*/**'), r'(?s:/(?:.+/)?[^/]+/[^/]*\.[^/]*/.*)\Z')
447447

448448
def test_translate_seps(self):

0 commit comments

Comments
 (0)