]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #8402: Added the escape() function to the glob module.
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 18 Nov 2013 11:06:43 +0000 (13:06 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Mon, 18 Nov 2013 11:06:43 +0000 (13:06 +0200)
Doc/library/glob.rst
Lib/glob.py
Lib/test/test_glob.py
Misc/NEWS

index eff138b3308e14b66a87666debd4095ed4161e21..57ccf4ad58ea0e614b6eed3fab57dfa508ff055e 100644 (file)
@@ -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
index 1a268a3ad1e94e98548dedb827beb75d3828875b..e388b5f9c0dd0e6bca9839cfb912e3aa4023b1af 100644 (file)
@@ -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
index eb9aeb5776c458b5ab06ecb47bbebc79f6998953..a5ab8d6c3e94623c1156e87867c114be2a9772eb 100644 (file)
@@ -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)
index 941eb29fd9c4449f69b29ec45ceea0fb287f6b1d..70254109b98615e67008ae949af0740de24ea93a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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