Permalink
Browse files

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

  • Loading branch information...
serhiy-storchaka committed Nov 18, 2013
1 parent e3010fd commit fd32fffa5ada8b8be8a65bd51b001d989f99a3d3
Showing with 49 additions and 2 deletions.
  1. +11 −0 Doc/library/glob.rst
  2. +14 −2 Lib/glob.py
  3. +22 −0 Lib/test/test_glob.py
  4. +2 −0 Misc/NEWS
@@ -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
@@ -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
@@ -169,6 +169,28 @@ def test_glob_magic_in_drive(self):
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

0 comments on commit fd32fff

Please sign in to comment.