summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_glob.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2023-11-13 17:15:56 (GMT)
committerGitHub <noreply@github.com>2023-11-13 17:15:56 (GMT)
commitcf67ebfb315ce36175f3d425249d7c6560f6d0d5 (patch)
tree3007eaa7164eba027714b9752aecea60627e6de6 /Lib/test/test_glob.py
parentbabb787047e0f7807c8238d3b1a3128dac30bd5c (diff)
downloadcpython-cf67ebfb315ce36175f3d425249d7c6560f6d0d5.zip
cpython-cf67ebfb315ce36175f3d425249d7c6560f6d0d5.tar.gz
cpython-cf67ebfb315ce36175f3d425249d7c6560f6d0d5.tar.bz2
GH-72904: Add `glob.translate()` function (#106703)
Add `glob.translate()` function that converts a pathname with shell wildcards to a regular expression. The regular expression is used by pathlib to implement `match()` and `glob()`. This function differs from `fnmatch.translate()` in that wildcards do not match path separators by default, and that a `*` pattern segment matches precisely one path segment. When *recursive* is set to true, `**` pattern segments match any number of path segments, and `**` cannot appear outside its own segment. In pathlib, this change speeds up directory walking (because `_make_child_relpath()` does less work), makes path objects smaller (they don't need a `_lines` slot), and removes the need for some gnarly code. Co-authored-by: Jason R. Coombs <jaraco@jaraco.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Diffstat (limited to 'Lib/test/test_glob.py')
-rw-r--r--Lib/test/test_glob.py91
1 files changed, 91 insertions, 0 deletions
diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py
index f4b5821..aa5fac8 100644
--- a/Lib/test/test_glob.py
+++ b/Lib/test/test_glob.py
@@ -1,5 +1,6 @@
import glob
import os
+import re
import shutil
import sys
import unittest
@@ -349,6 +350,96 @@ class GlobTests(unittest.TestCase):
for it in iters:
self.assertEqual(next(it), p)
+ def test_translate_matching(self):
+ match = re.compile(glob.translate('*')).match
+ self.assertIsNotNone(match('foo'))
+ self.assertIsNotNone(match('foo.bar'))
+ self.assertIsNone(match('.foo'))
+ match = re.compile(glob.translate('.*')).match
+ self.assertIsNotNone(match('.foo'))
+ match = re.compile(glob.translate('**', recursive=True)).match
+ self.assertIsNotNone(match('foo'))
+ self.assertIsNone(match('.foo'))
+ self.assertIsNotNone(match(os.path.join('foo', 'bar')))
+ self.assertIsNone(match(os.path.join('foo', '.bar')))
+ self.assertIsNone(match(os.path.join('.foo', 'bar')))
+ self.assertIsNone(match(os.path.join('.foo', '.bar')))
+ match = re.compile(glob.translate('**/*', recursive=True)).match
+ self.assertIsNotNone(match(os.path.join('foo', 'bar')))
+ self.assertIsNone(match(os.path.join('foo', '.bar')))
+ self.assertIsNone(match(os.path.join('.foo', 'bar')))
+ self.assertIsNone(match(os.path.join('.foo', '.bar')))
+ match = re.compile(glob.translate('*/**', recursive=True)).match
+ self.assertIsNotNone(match(os.path.join('foo', 'bar')))
+ self.assertIsNone(match(os.path.join('foo', '.bar')))
+ self.assertIsNone(match(os.path.join('.foo', 'bar')))
+ self.assertIsNone(match(os.path.join('.foo', '.bar')))
+ match = re.compile(glob.translate('**/.bar', recursive=True)).match
+ self.assertIsNotNone(match(os.path.join('foo', '.bar')))
+ self.assertIsNone(match(os.path.join('.foo', '.bar')))
+ match = re.compile(glob.translate('**/*.*', recursive=True)).match
+ self.assertIsNone(match(os.path.join('foo', 'bar')))
+ self.assertIsNone(match(os.path.join('foo', '.bar')))
+ self.assertIsNotNone(match(os.path.join('foo', 'bar.txt')))
+ self.assertIsNone(match(os.path.join('foo', '.bar.txt')))
+
+ def test_translate(self):
+ def fn(pat):
+ return glob.translate(pat, seps='/')
+ self.assertEqual(fn('foo'), r'(?s:foo)\Z')
+ self.assertEqual(fn('foo/bar'), r'(?s:foo/bar)\Z')
+ self.assertEqual(fn('*'), r'(?s:[^/.][^/]*)\Z')
+ self.assertEqual(fn('?'), r'(?s:(?!\.)[^/])\Z')
+ self.assertEqual(fn('a*'), r'(?s:a[^/]*)\Z')
+ self.assertEqual(fn('*a'), r'(?s:(?!\.)[^/]*a)\Z')
+ self.assertEqual(fn('.*'), r'(?s:\.[^/]*)\Z')
+ self.assertEqual(fn('?aa'), r'(?s:(?!\.)[^/]aa)\Z')
+ self.assertEqual(fn('aa?'), r'(?s:aa[^/])\Z')
+ self.assertEqual(fn('aa[ab]'), r'(?s:aa[ab])\Z')
+ self.assertEqual(fn('**'), r'(?s:(?!\.)[^/]*)\Z')
+ 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_include_hidden(self):
+ def fn(pat):
+ return glob.translate(pat, include_hidden=True, seps='/')
+ self.assertEqual(fn('foo'), r'(?s:foo)\Z')
+ self.assertEqual(fn('foo/bar'), r'(?s:foo/bar)\Z')
+ self.assertEqual(fn('*'), r'(?s:[^/]+)\Z')
+ self.assertEqual(fn('?'), r'(?s:[^/])\Z')
+ self.assertEqual(fn('a*'), r'(?s:a[^/]*)\Z')
+ self.assertEqual(fn('*a'), r'(?s:[^/]*a)\Z')
+ self.assertEqual(fn('.*'), r'(?s:\.[^/]*)\Z')
+ self.assertEqual(fn('?aa'), r'(?s:[^/]aa)\Z')
+ self.assertEqual(fn('aa?'), r'(?s:aa[^/])\Z')
+ self.assertEqual(fn('aa[ab]'), r'(?s:aa[ab])\Z')
+ self.assertEqual(fn('**'), r'(?s:[^/]*)\Z')
+ 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_recursive(self):
+ def fn(pat):
+ return glob.translate(pat, recursive=True, include_hidden=True, seps='/')
+ self.assertEqual(fn('*'), r'(?s:[^/]+)\Z')
+ 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')
+
+ def test_translate_seps(self):
+ def fn(pat):
+ return glob.translate(pat, recursive=True, include_hidden=True, seps=['/', '\\'])
+ self.assertEqual(fn('foo/bar\\baz'), r'(?s:foo[/\\]bar[/\\]baz)\Z')
+ self.assertEqual(fn('**/*'), r'(?s:(?:.+[/\\])?[^/\\]+)\Z')
+
@skip_unless_symlink
class SymlinkLoopGlobTests(unittest.TestCase):