comparison venv/lib/python2.7/site-packages/glob2/impl.py @ 0:d67268158946 draft

planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author bcclaywell
date Mon, 12 Oct 2015 17:43:33 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:d67268158946
1 """Filename globbing utility."""
2
3 from __future__ import absolute_import
4
5 import sys
6 import os
7 import re
8 from . import fnmatch
9
10
11 class Globber(object):
12
13 listdir = staticmethod(os.listdir)
14 isdir = staticmethod(os.path.isdir)
15 islink = staticmethod(os.path.islink)
16 exists = staticmethod(os.path.lexists)
17
18 def walk(self, top, followlinks=False):
19 """A simplified version of os.walk (code copied) that uses
20 ``self.listdir``, and the other local filesystem methods.
21
22 Because we don't care about file/directory distinctions, only
23 a single list is returned.
24 """
25 try:
26 names = self.listdir(top)
27 except os.error as err:
28 return
29
30 items = []
31 for name in names:
32 items.append(name)
33
34 yield top, items
35
36 for name in items:
37 new_path = os.path.join(top, name)
38 if followlinks or not self.islink(new_path):
39 for x in self.walk(new_path, followlinks):
40 yield x
41
42 def glob(self, pathname, with_matches=False):
43 """Return a list of paths matching a pathname pattern.
44
45 The pattern may contain simple shell-style wildcards a la
46 fnmatch. However, unlike fnmatch, filenames starting with a
47 dot are special cases that are not matched by '*' and '?'
48 patterns.
49
50 """
51 return list(self.iglob(pathname, with_matches))
52
53 def iglob(self, pathname, with_matches=False):
54 """Return an iterator which yields the paths matching a pathname
55 pattern.
56
57 The pattern may contain simple shell-style wildcards a la
58 fnmatch. However, unlike fnmatch, filenames starting with a
59 dot are special cases that are not matched by '*' and '?'
60 patterns.
61
62 If ``with_matches`` is True, then for each matching path
63 a 2-tuple will be returned; the second element if the tuple
64 will be a list of the parts of the path that matched the individual
65 wildcards.
66 """
67 result = self._iglob(pathname)
68 if with_matches:
69 return result
70 return map(lambda s: s[0], result)
71
72 def _iglob(self, pathname, rootcall=True):
73 """Internal implementation that backs :meth:`iglob`.
74
75 ``rootcall`` is required to differentiate between the user's call to
76 iglob(), and subsequent recursive calls, for the purposes of resolving
77 certain special cases of ** wildcards. Specifically, "**" is supposed
78 to include the current directory for purposes of globbing, but the
79 directory itself should never be returned. So if ** is the lastmost
80 part of the ``pathname`` given the user to the root call, we want to
81 ignore the current directory. For this, we need to know which the root
82 call is.
83 """
84
85 # Short-circuit if no glob magic
86 if not has_magic(pathname):
87 if self.exists(pathname):
88 yield pathname, ()
89 return
90
91 # If no directory part is left, assume the working directory
92 dirname, basename = os.path.split(pathname)
93
94 # If the directory is globbed, recurse to resolve.
95 # If at this point there is no directory part left, we simply
96 # continue with dirname="", which will search the current dir.
97 # `os.path.split()` returns the argument itself as a dirname if it is a
98 # drive or UNC path. Prevent an infinite recursion if a drive or UNC path
99 # contains magic characters (i.e. r'\\?\C:').
100 if dirname != pathname and has_magic(dirname):
101 # Note that this may return files, which will be ignored
102 # later when we try to use them as directories.
103 # Prefiltering them here would only require more IO ops.
104 dirs = self._iglob(dirname, rootcall=False)
105 else:
106 dirs = [(dirname, ())]
107
108 # Resolve ``basename`` expr for every directory found
109 for dirname, dir_groups in dirs:
110 for name, groups in self.resolve_pattern(
111 dirname, basename, not rootcall):
112 yield os.path.join(dirname, name), dir_groups + groups
113
114 def resolve_pattern(self, dirname, pattern, globstar_with_root):
115 """Apply ``pattern`` (contains no path elements) to the
116 literal directory`` in dirname``.
117
118 If pattern=='', this will filter for directories. This is
119 a special case that happens when the user's glob expression ends
120 with a slash (in which case we only want directories). It simpler
121 and faster to filter here than in :meth:`_iglob`.
122 """
123
124 if sys.version_info[0] == 3:
125 if isinstance(pattern, bytes):
126 dirname = bytes(os.curdir, 'ASCII')
127 else:
128 if isinstance(pattern, unicode) and not isinstance(dirname, unicode):
129 dirname = unicode(dirname, sys.getfilesystemencoding() or
130 sys.getdefaultencoding())
131
132 # If no magic, short-circuit, only check for existence
133 if not has_magic(pattern):
134 if pattern == '':
135 if self.isdir(dirname):
136 return [(pattern, ())]
137 else:
138 if self.exists(os.path.join(dirname, pattern)):
139 return [(pattern, ())]
140 return []
141
142 if not dirname:
143 dirname = os.curdir
144
145 try:
146 if pattern == '**':
147 # Include the current directory in **, if asked; by adding
148 # an empty string as opposed to '.', be spare ourselves
149 # having to deal with os.path.normpath() later.
150 names = [''] if globstar_with_root else []
151 for top, entries in self.walk(dirname):
152 _mkabs = lambda s: os.path.join(top[len(dirname)+1:], s)
153 names.extend(map(_mkabs, entries))
154 # Reset pattern so that fnmatch(), which does not understand
155 # ** specifically, will only return a single group match.
156 pattern = '*'
157 else:
158 names = self.listdir(dirname)
159 except os.error:
160 return []
161
162 if not _ishidden(pattern):
163 # Remove hidden files by default, but take care to ensure
164 # that the empty string we may have added earlier remains.
165 # Do not filter out the '' that we might have added earlier
166 names = filter(lambda x: not x or not _ishidden(x), names)
167 return fnmatch.filter(names, pattern)
168
169
170 default_globber = Globber()
171 glob = default_globber.glob
172 iglob = default_globber.iglob
173 del default_globber
174
175
176 magic_check = re.compile('[*?[]')
177 magic_check_bytes = re.compile(b'[*?[]')
178
179 def has_magic(s):
180 if isinstance(s, bytes):
181 match = magic_check_bytes.search(s)
182 else:
183 match = magic_check.search(s)
184 return match is not None
185
186 def _ishidden(path):
187 return path[0] in ('.', b'.'[0])