• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Filename globbing utility."""
2
3import sys
4import os
5import re
6import fnmatch
7
8try:
9    _unicode = unicode
10except NameError:
11    # If Python is built without Unicode support, the unicode type
12    # will not exist. Fake one.
13    class _unicode(object):
14        pass
15
16__all__ = ["glob", "iglob"]
17
18def glob(pathname):
19    """Return a list of paths matching a pathname pattern.
20
21    The pattern may contain simple shell-style wildcards a la
22    fnmatch. However, unlike fnmatch, filenames starting with a
23    dot are special cases that are not matched by '*' and '?'
24    patterns.
25
26    """
27    return list(iglob(pathname))
28
29def iglob(pathname):
30    """Return an iterator which yields the paths matching a pathname pattern.
31
32    The pattern may contain simple shell-style wildcards a la
33    fnmatch. However, unlike fnmatch, filenames starting with a
34    dot are special cases that are not matched by '*' and '?'
35    patterns.
36
37    """
38    dirname, basename = os.path.split(pathname)
39    if not has_magic(pathname):
40        if basename:
41            if os.path.lexists(pathname):
42                yield pathname
43        else:
44            # Patterns ending with a slash should match only directories
45            if os.path.isdir(dirname):
46                yield pathname
47        return
48    if not dirname:
49        for name in glob1(os.curdir, basename):
50            yield name
51        return
52    # `os.path.split()` returns the argument itself as a dirname if it is a
53    # drive or UNC path.  Prevent an infinite recursion if a drive or UNC path
54    # contains magic characters (i.e. r'\\?\C:').
55    if dirname != pathname and has_magic(dirname):
56        dirs = iglob(dirname)
57    else:
58        dirs = [dirname]
59    if has_magic(basename):
60        glob_in_dir = glob1
61    else:
62        glob_in_dir = glob0
63    for dirname in dirs:
64        for name in glob_in_dir(dirname, basename):
65            yield os.path.join(dirname, name)
66
67# These 2 helper functions non-recursively glob inside a literal directory.
68# They return a list of basenames. `glob1` accepts a pattern while `glob0`
69# takes a literal basename (so it only has to check for its existence).
70
71def glob1(dirname, pattern):
72    if not dirname:
73        dirname = os.curdir
74    if isinstance(pattern, _unicode) and not isinstance(dirname, unicode):
75        dirname = unicode(dirname, sys.getfilesystemencoding() or
76                                   sys.getdefaultencoding())
77    try:
78        names = os.listdir(dirname)
79    except os.error:
80        return []
81    if pattern[0] != '.':
82        names = filter(lambda x: x[0] != '.', names)
83    return fnmatch.filter(names, pattern)
84
85def glob0(dirname, basename):
86    if basename == '':
87        # `os.path.split()` returns an empty basename for paths ending with a
88        # directory separator.  'q*x/' should match only directories.
89        if os.path.isdir(dirname):
90            return [basename]
91    else:
92        if os.path.lexists(os.path.join(dirname, basename)):
93            return [basename]
94    return []
95
96
97magic_check = re.compile('[*?[]')
98
99def has_magic(s):
100    return magic_check.search(s) is not None
101