diff options
-rw-r--r-- | Doc/library/glob.rst | 11 | ||||
-rw-r--r-- | Lib/glob.py | 16 | ||||
-rw-r--r-- | Lib/test/test_glob.py | 22 | ||||
-rw-r--r-- | Misc/NEWS | 2 |
4 files changed, 49 insertions, 2 deletions
diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst index eff138b..57ccf4a 100644 --- a/Doc/library/glob.rst +++ b/Doc/library/glob.rst @@ -40,6 +40,17 @@ For example, ``'[?]'`` matches the character ``'?'``. without actually storing them all simultaneously. +.. function:: escape(pathname) + + Escape all special characters (``'?'``, ``'*'`` and ``'['``). + This is useful if you want to match an arbitrary literal string that may + have special characters in it. Special characters in drive/UNC + sharepoints are not escaped, e.g. on Windows + ``escape('//?/c:/Quo vadis?.txt')`` returns ``'//?/c:/Quo vadis[?].txt'``. + + .. versionadded:: 3.4 + + For example, consider a directory containing only the following files: :file:`1.gif`, :file:`2.txt`, and :file:`card.gif`. :func:`glob` will produce the following results. Notice how any leading components of the path are diff --git a/Lib/glob.py b/Lib/glob.py index 1a268a3..e388b5f 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -79,8 +79,8 @@ def glob0(dirname, basename): return [] -magic_check = re.compile('[*?[]') -magic_check_bytes = re.compile(b'[*?[]') +magic_check = re.compile('([*?[])') +magic_check_bytes = re.compile(b'([*?[])') def has_magic(s): if isinstance(s, bytes): @@ -91,3 +91,15 @@ def has_magic(s): def _ishidden(path): return path[0] in ('.', b'.'[0]) + +def escape(pathname): + """Escape all special characters. + """ + # Escaping is done by wrapping any of "*?[" between square brackets. + # Metacharacters do not work in the drive part and shouldn't be escaped. + drive, pathname = os.path.splitdrive(pathname) + if isinstance(pathname, bytes): + pathname = magic_check_bytes.sub(br'[\1]', pathname) + else: + pathname = magic_check.sub(r'[\1]', pathname) + return drive + pathname diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index eb9aeb5..a5ab8d6 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -169,6 +169,28 @@ class GlobTests(unittest.TestCase): eq(glob.glob('\\\\*\\*\\'), []) eq(glob.glob(b'\\\\*\\*\\'), []) + def check_escape(self, arg, expected): + self.assertEqual(glob.escape(arg), expected) + self.assertEqual(glob.escape(os.fsencode(arg)), os.fsencode(expected)) + + def test_escape(self): + check = self.check_escape + check('abc', 'abc') + check('[', '[[]') + check('?', '[?]') + check('*', '[*]') + check('[[_/*?*/_]]', '[[][[]_/[*][?][*]/_]]') + check('/[[_/*?*/_]]/', '/[[][[]_/[*][?][*]/_]]/') + + @unittest.skipUnless(sys.platform == "win32", "Win32 specific test") + def test_escape_windows(self): + check = self.check_escape + check('?:?', '?:[?]') + check('*:*', '*:[*]') + check(r'\\?\c:\?', r'\\?\c:\[?]') + check(r'\\*\*\*', r'\\*\*\[*]') + check('//?/c:/?', '//?/c:/[?]') + check('//*/*/*', '//*/*/[*]') def test_main(): run_unittest(GlobTests) @@ -50,6 +50,8 @@ Core and Builtins Library ------- +- Issue #8402: Added the escape() function to the glob module. + - Issue #17618: Add Base85 and Ascii85 encoding/decoding to the base64 module. - Issue #19634: time.strftime("%y") now raises a ValueError on AIX when given a |