1 """
2 This module contains file- and path-related methods, classes, and modules.
3 """
4
5 from __future__ import with_statement, absolute_import
6
7 __docformat__ = "restructuredtext en"
8
9
10
11
12
13 import os as _os
14 import sys
15 import shutil
16
17
18
19
20
21 __all__ = ['unlink_quietly', 'recursively_remove', 'copy_recursively',
22 'copy', 'touch', 'pathsplit', 'eglob', 'universal_path',
23 'native_path']
24
25
26
27
28
30 """
31 Like the standard ``os.unlink()`` function, this function attempts to
32 delete a file. However, it swallows any exceptions that occur during the
33 unlink operation, making it more suitable for certain uses (e.g.,
34 in ``atexit`` handlers).
35
36 :Parameters:
37 paths : str or list
38 path(s) to unlink
39 """
40 def looper(*paths):
41 for i in paths:
42 if type(i) == list:
43 for path in i:
44 yield path
45 else:
46 yield i
47
48 for path in looper(*paths):
49 try:
50 _os.unlink(path)
51 except:
52 pass
53
55 """
56 Recursively remove all files and directories below and including a
57 specified directory.
58
59 :Parameters:
60 dir : str
61 path to directory to remove
62 """
63 if not _os.path.exists(dir):
64 return
65
66 shutil.rmtree(dir)
67
69 """
70 Recursively list the contents of a directory. Yields the contents of
71 the directory and all subdirectories. This method returns a generator,
72 so it evaluates its recursive walk lazily.
73
74 :Parameters:
75 dir : str
76 Path to directory to list
77
78 :raise ValueError: If ``dir`` does not exist, or if ``dir`` exists
79 but is not a directory.
80 """
81 if not _os.path.isdir(dir):
82 raise ValueError, "%s is not a directory." % dir
83
84 for f in _os.listdir(dir):
85 if _os.path.isdir(f):
86 list_recursively(f)
87 else:
88 yield f
89
91 """
92 Recursively copy a source directory (and all its contents) to a target
93 directory.
94
95 :Parameters:
96 source_dir : str
97 Source directory to copy recursively. This path must
98 exist and must specify a directory; otherwise, this
99 function throws a ``ValueError``
100
101 target_dir : str
102 Directory to which to copy the contents of ``source_dir``.
103 This directory must not already exist.
104
105 :raise ValueError: If: ``source_dir`` does not exist; ``source_dir`` exists
106 but is not a directory; or ``target_dir`` exists but is
107 not a directory.
108 """
109 shutil.copytree(source_dir, target_dir)
110
111 -def copy(files, target_dir, create_target=False):
112 """
113 Copy one or more files to a target directory.
114
115 :Parameters:
116 files : str or list
117 single file path or a list of file paths to be copied
118
119 target_dir : str
120 path to target directory
121
122 create_target : bool
123 If ``True``, ``copy()`` will attempt to create the target directory
124 if it does not exist. If ``False``, ``copy()`` will throw an
125 exception if the target directory does not exist.
126
127 :raise OSError: ``target_dir`` does not exist, and ``create_target`` is
128 ``False``
129 """
130 if type(files) == str:
131 files = [files]
132
133 if not _os.path.exists(target_dir):
134 if create_target:
135 _os.mkdir(target_dir)
136
137 if _os.path.exists(target_dir) and (not _os.path.isdir(target_dir)):
138 raise OSError, 'Cannot copy files to non-directory "%s"' % target_dir
139
140 for f in files:
141 targetFile = _os.path.join(target_dir, _os.path.basename(f))
142 open(targetFile, 'wb').write(open(f, 'rb').read())
143
144 -def touch(files, times=None):
145 """
146 Similar to the Unix *touch* command, this function:
147
148 - updates the access and modification times for any existing files
149 in a list of files
150 - creates any non-existent files in the list of files
151
152 If any file in the list is a directory, this function will throw an
153 exception.
154
155 :Parameters:
156 files : list or str
157 pathname or list of pathnames of files to be created or updated
158
159 times : tuple
160 tuple of the form (*atime*, *mtime*), identical to
161 what is passed to the standard ``os.utime()`` function.
162 If this tuple is ``None``, then the current time is used.
163 """
164 if type(files) == str:
165 files = [files]
166
167 for f in files:
168 if _os.path.exists(f):
169 if not _os.path.isfile(f):
170 raise OSError, "Can't touch non-file \"%s\"" % f
171 _os.utime(f, times)
172
173 else:
174
175 open(f, 'wb').close()
176
177
179 """
180 Split a path into an array of path components, using the file separator
181 ('/' on POSIX systems, '\' on Windows) that's appropriate for the
182 underlying operating system. Does not take drive letters into account.
183 If there's a Windows drive letter in the path, it'll end up with the
184 first component.
185
186 :Parameters:
187 path : str
188 path to split. Can be relative or absolute
189
190 :rtype: list
191 :return: a list of path components
192 """
193 result = []
194 (head, tail) = _os.path.split(path)
195
196 if (not head) or (head == path):
197
198 pass
199
200 else:
201 result = pathsplit(head)
202
203 if tail:
204 result += [tail]
205
206 return result
207
209 """
210 Used by eglob.
211 """
212 import glob
213
214 result = []
215 if not _os.path.isdir(directory):
216 return []
217
218 piece = pattern_pieces[0]
219 last = len(pattern_pieces) == 1
220 if piece == '**':
221 if not last:
222 remaining_pieces = pattern_pieces[1:]
223
224 for root, dirs, files in _os.walk(directory):
225 if last:
226
227
228 result += [root]
229 else:
230
231
232 sub_result = __find_matches(remaining_pieces, root)
233 for partial_path in sub_result:
234 result += [partial_path]
235
236 else:
237
238
239 matches = glob.glob(_os.path.join(directory, piece))
240 if len(matches) > 0:
241 if last:
242 for match in matches:
243 result += [match]
244 else:
245 remaining_pieces = pattern_pieces[1:]
246 for match in matches:
247 sub_result = __find_matches(remaining_pieces, match)
248 for partial_path in sub_result:
249 result += [partial_path]
250
251
252
253 for i in range(len(result)):
254 result[i] = _os.path.normpath(result[i])
255
256 return result
257
258 -def eglob(pattern, directory='.'):
259 """
260 Extended glob function that supports the all the wildcards supported
261 by the Python standard ``glob`` routine, as well as a special "**"
262 wildcard that recursively matches any directory. Examples:
263
264 +--------------+--------------------------------------------------------+
265 | \*\*/\*.py | all files ending in '.py' under the current directory |
266 +--------------+--------------------------------------------------------+
267 | foo/\*\*/bar | all files name 'bar' anywhere under subdirectory 'foo' |
268 +--------------+--------------------------------------------------------+
269
270 :Parameters:
271 pattern : str
272 The wildcard pattern. Must be a simple pattern with no directories.
273
274 directory : str
275 The directory in which to do the globbing.
276
277 :rtype: list
278 :return: A list of matched files, or an empty list for no match
279 """
280 pieces = pathsplit(pattern)
281 return __find_matches(pieces, directory)
282
284 """
285 Converts a path name from its operating system-specific format to a
286 universal path notation. Universal path notation always uses a Unix-style
287 "/" to separate path elements. A universal path can be converted to a
288 native (operating system-specific) path via the ``native_path()``
289 function. Note that on POSIX-compliant systems, this function simply
290 returns the ``path`` parameter unmodified.
291
292 :Parameters:
293 path : str
294 the path to convert to universal path notation
295
296 :rtype: str
297 :return: the universal path.
298 """
299 if _os.name != 'posix':
300 path = path.replace(_os.path.sep, '/')
301
302 return path
303
305 """
306 Converts a path name from universal path notation to the operating
307 system-specific format. Universal path notation always uses a Unix-style
308 "/" to separate path elements. A native path can be converted to a
309 universal path via the ``universal_path()`` function. Note that on
310 POSIX-compliant systems, this function simply returns the ``path``
311 parameter unmodified.
312
313 :Parameters:
314 path : str
315 the path to convert to native path notation
316
317 :rtype: str
318 :return: the native path.
319 """
320 if _os.name != 'posix':
321 path = path.replace('/', _os.path.sep)
322
323 return path
324