Issue #8402: Added the escape() function to the glob module.

This commit is contained in:
Serhiy Storchaka 2013-11-18 13:06:43 +02:00
parent e3010fd740
commit fd32fffa5a
4 changed files with 49 additions and 2 deletions

View 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

View 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

View 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)

View File

@ -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