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]

Reply via email to