/[theodore]/bunnyblog/modules/pathutils.py


UCC Code Repository

Contents of /bunnyblog/modules/pathutils.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations) (download) (as text)
Tue Jan 29 14:32:01 2008 UTC (12 years, 2 months ago) by svn-admin
File MIME type: text/x-python
File size: 12028 byte(s)
Re-import of repository after repository database corruption.

1 svn-admin 1 # 2005/08/28
2     # Version 0.2.1
3     # pathutils.py
4     # Functions useful for working with files and paths.
5     # http://www.voidspace.org.uk/python/recipebook.shtml#utils
6    
7     # Copyright Michael Foord 2004
8     # Released subject to the BSD License
9     # Please see http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
10    
11     # For information about bugfixes, updates and support, please join the Pythonutils mailing list.
12     # http://voidspace.org.uk/mailman/listinfo/pythonutils_voidspace.org.uk
13     # Comments, suggestions and bug reports welcome.
14     # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
15     # E-mail fuzzyman@voidspace.org.uk
16    
17     """
18     This module contains convenience functions for working with files and paths.
19     """
20    
21     from __future__ import generators
22     import os
23     import sys
24    
25     __all__ = (
26     'readlines',
27     'writelines',
28     'readbinary',
29     'writebinary',
30     'readfile',
31     'writefile',
32     'tslash',
33     'relpath',
34     'splitall',
35     'walkfiles',
36     'walkdirs',
37     'walkemptydirs',
38     'formatbytes',
39     'fullcopy',
40     'import_path',
41     )
42    
43     ######################################
44     # Functions to read and write files in text and binary mode.
45    
46     def readlines(filename):
47     """Passed a filename, it reads it, and returns a list of lines. (Read in text mode)"""
48     filehandle = open(filename, 'r')
49     outfile = filehandle.readlines()
50     filehandle.close()
51     return outfile
52    
53     def writelines(filename, infile, newline=False):
54     """
55     Given a filename and a list of lines it writes the file. (In text mode)
56    
57     If ``newline`` is ``True`` (default is ``False``) it adds a newline to each
58     line.
59     """
60     filehandle = open(filename, 'w')
61     if newline:
62     infile = [line + '\n' for line in infile]
63     filehandle.writelines(infile)
64     filehandle.close()
65    
66     def readbinary(filename):
67     """Given a filename, read a file in binary mode. It returns a single string."""
68     filehandle = open(filename, 'rb')
69     thisfile = filehandle.read()
70     filehandle.close()
71     return thisfile
72    
73     def writebinary(filename, infile):
74     """Given a filename and a string, write the file in binary mode. """
75     filehandle = open(filename, 'wb')
76     filehandle.write(infile)
77     filehandle.close()
78    
79     def readfile(filename):
80     """Given a filename, read a file in text mode. It returns a single string."""
81     filehandle = open(filename, 'r')
82     outfile = filehandle.read()
83     filehandle.close()
84     return outfile
85    
86     def writefile(filename, infile):
87     """Given a filename and a string, write the file in text mode."""
88     filehandle = open(filename, 'w')
89     filehandle.write(infile)
90     filehandle.close()
91    
92     ####################################################################
93     # Some functions for dealing with paths
94    
95     def tslash(apath):
96     """
97     Add a trailing slash (``/``) to a path if it lacks one.
98    
99     It doesn't use ``os.sep`` because you end up in trouble on windoze, when you
100     want separators for URLs.
101     """
102     if apath and apath != '.' and not apath.endswith('/') and not apath.endswith('\\'):
103     return apath + '/'
104     else:
105     return apath
106    
107     def relpath(origin, dest):
108     """
109     Return the relative path between origin and dest.
110    
111     If it's not possible return dest.
112    
113    
114     If they are identical return ``os.curdir``
115    
116     Adapted from `path.py`_ by Jason Orendorff.
117    
118    
119     .. _path.py: http://www.jorendorff.com/articles/python/path/
120     """
121     origin = os.path.abspath(origin).replace('\\', '/')
122     dest = os.path.abspath(dest).replace('\\', '/')
123    
124     orig_list = splitall(os.path.normcase(origin))
125     # Don't normcase dest! We want to preserve the case.
126     dest_list = splitall(dest)
127    
128     if orig_list[0] != os.path.normcase(dest_list[0]):
129     # Can't get here from there.
130     return dest
131    
132     # Find the location where the two paths start to differ.
133     i = 0
134     for start_seg, dest_seg in zip(orig_list, dest_list):
135     if start_seg != os.path.normcase(dest_seg):
136     break
137     i += 1
138    
139     # Now i is the point where the two paths diverge.
140     # Need a certain number of "os.pardir"s to work up
141     # from the origin to the point of divergence.
142     segments = [os.pardir] * (len(orig_list) - i)
143     # Need to add the diverging part of dest_list.
144     segments += dest_list[i:]
145     if len(segments) == 0:
146     # If they happen to be identical, use os.curdir.
147     return os.curdir
148     else:
149     return os.path.join(*segments).replace('\\', '/')
150    
151     def splitall(loc):
152     """
153     Return a list of the path components in loc. (Used by relpath_).
154    
155     The first item in the list will be either ``os.curdir``, ``os.pardir``, empty,
156     or the root directory of loc (for example, ``/`` or ``C:\\).
157    
158     The other items in the list will be strings.
159    
160     Adapted from path.py by Jason Orendorff.
161     """
162     parts = []
163     while loc != os.curdir and loc != os.pardir:
164     prev = loc
165     loc, child = os.path.split(prev)
166     if loc == prev:
167     break
168     parts.append(child)
169     parts.append(loc)
170     parts.reverse()
171     return parts
172    
173     #######################################################################
174     # a pre 2.3 walkfiles function - adapted from the path module by Jason Orendorff
175    
176     join = os.path.join
177     isdir = os.path.isdir
178     isfile = os.path.isfile
179    
180     def walkfiles(thisdir):
181     """
182     walkfiles(D) -> iterator over files in D, recursively. Yields full file paths.
183    
184     Adapted from path.py by Jason Orendorff.
185     """
186     for child in os.listdir(thisdir):
187     thischild = join(thisdir, child)
188     if isfile(thischild):
189     yield thischild
190     elif isdir(thischild):
191     for f in walkfiles(thischild):
192     yield f
193    
194     def walkdirs(thisdir):
195     """
196     Walk through all the subdirectories in a tree. Recursively yields directory
197     names (full paths).
198     """
199     for child in os.listdir(thisdir):
200     thischild = join(thisdir, child)
201     if isfile(thischild):
202     continue
203     elif isdir(thischild):
204     for f in walkdirs(thischild):
205     yield f
206     yield thischild
207    
208     def walkemptydirs(thisdir):
209     """
210     Recursively yield names of *empty* directories.
211    
212     These are the only paths omitted when using ``walkfiles``.
213     """
214     if not os.listdir(thisdir): # if the directory is empty.. then yield it
215     yield thisdir
216     for child in os.listdir(thisdir):
217     thischild = join(thisdir, child)
218     if isdir(thischild):
219     for emptydir in walkemptydirs(thischild):
220     yield emptydir
221    
222     ###############################################################
223     # formatbytes takes a filesize (as returned by os.getsize() )
224     # and formats it for display in one of two ways !!
225    
226     def formatbytes(sizeint, configdict=None, **configs):
227     """
228     Given a file size as an integer, return a nicely formatted string that
229     represents the size. Has various options to control it's output.
230    
231     You can pass in a dictionary of arguments or keyword arguments. Keyword
232     arguments override the dictionary and there are sensible defaults for options
233     you don't set.
234    
235     Options and defaults are as follows :
236    
237     * ``forcekb = False`` - If set this forces the output to be in terms
238     of kilobytes and bytes only.
239    
240     * ``largestonly = True`` - If set, instead of outputting
241     ``1 Mbytes, 307 Kbytes, 478 bytes`` it outputs using only the largest
242     denominator - e.g. ``1.3 Mbytes`` or ``17.2 Kbytes``
243    
244     * ``kiloname = 'Kbytes'`` - The string to use for kilobytes
245    
246     * ``meganame = 'Mbytes'`` - The string to use for Megabytes
247    
248     * ``bytename = 'bytes'`` - The string to use for bytes
249    
250     * ``nospace = True`` - If set it outputs ``1Mbytes, 307Kbytes``,
251     notice there is no space.
252    
253     Example outputs : ::
254    
255     19Mbytes, 75Kbytes, 255bytes
256     2Kbytes, 0bytes
257     23.8Mbytes
258    
259     .. note::
260    
261     It currently uses the plural form even for singular.
262     """
263     defaultconfigs = { 'forcekb' : False,
264     'largestonly' : True,
265     'kiloname' : 'Kbytes',
266     'meganame' : 'Mbytes',
267     'bytename' : 'bytes',
268     'nospace' : True}
269     if configdict is None:
270     configdict = {}
271     for entry in configs:
272     # keyword parameters override the dictionary passed in
273     configdict[entry] = configs[entry]
274     #
275     for keyword in defaultconfigs:
276     if not configdict.has_key(keyword):
277     configdict[keyword] = defaultconfigs[keyword]
278     #
279     if configdict['nospace']:
280     space = ''
281     else:
282     space = ' '
283     #
284     mb, kb, rb = bytedivider(sizeint)
285     if configdict['largestonly']:
286     if mb and not configdict['forcekb']:
287     return stringround(mb, kb)+ space + configdict['meganame']
288     elif kb or configdict['forcekb']:
289     if mb and configdict['forcekb']:
290     kb += 1024*mb
291     return stringround(kb, rb) + space+ configdict['kiloname']
292     else:
293     return str(rb) + space + configdict['bytename']
294     else:
295     outstr = ''
296     if mb and not configdict['forcekb']:
297     outstr = str(mb) + space + configdict['meganame'] +', '
298     if kb or configdict['forcekb'] or mb:
299     if configdict['forcekb']:
300     kb += 1024*mb
301     outstr += str(kb) + space + configdict['kiloname'] +', '
302     return outstr + str(rb) + space + configdict['bytename']
303    
304     def stringround(main, rest):
305     """
306     Given a file size in either (mb, kb) or (kb, bytes) - round it
307     appropriately.
308     """
309     # divide an int by a float... get a float
310     value = main + rest/1024.0
311     return str(round(value, 1))
312    
313     def bytedivider(nbytes):
314     """
315     Given an integer (probably a long integer returned by os.getsize() )
316     it returns a tuple of (megabytes, kilobytes, bytes).
317    
318     This can be more easily converted into a formatted string to display the
319     size of the file.
320     """
321     mb, remainder = divmod(nbytes, 1048576)
322     kb, rb = divmod(remainder, 1024)
323     return (mb, kb, rb)
324    
325     ########################################
326    
327     def fullcopy(src, dst):
328     """
329     Copy file from src to dst.
330    
331     If the dst directory doesn't exist, we will attempt to create it using makedirs.
332     """
333     import shutil
334     if not os.path.isdir(os.path.dirname(dst)):
335     os.makedirs(os.path.dirname(dst))
336     shutil.copy(src, dst)
337    
338     #######################################
339    
340     def import_path(fullpath, strict=True):
341     """
342     Import a file from the full path. Allows you to import from anywhere,
343     something ``__import__`` does not do.
344    
345     If strict is ``True`` (the default), raise an ``ImportError`` if the module
346     is found in the "wrong" directory.
347    
348     Taken from firedrop2_ by `Hans Nowak`_
349    
350     .. _firedrop2: http://www.voidspace.org.uk/python/firedrop2/
351     .. _Hans Nowak: http://zephyrfalcon.org
352     """
353     path, filename = os.path.split(fullpath)
354     filename, ext = os.path.splitext(filename)
355     sys.path.insert(0, path)
356     try:
357     module = __import__(filename)
358     except ImportError:
359     del sys.path[0]
360     raise
361     del sys.path[0]
362     #
363     if strict:
364     path = os.path.split(module.__file__)[0]
365     # FIXME: doesn't *startswith* allow room for errors ?
366     if not fullpath.startswith(path):
367     raise ImportError, "Module '%s' found, but not in '%s'" % (
368     filename, fullpath)
369     #
370     return module
371    
372     """
373    
374     Changelog
375     ==========
376     2005/08/28 Version 0.2.1
377     Added import_path
378     Added __all__
379     Code cleanup
380    
381     2005/06/01 Version 0.2.0
382     Added walkdirs generator.
383    
384    
385     2005/03/11 Version 0.1.1
386     Added rounding to formatbytes and improved bytedivider with divmod.
387     Now explicit keyword parameters override the configdict in formatbytes.
388    
389     2005/02/18 Version 0.1.0
390     The first numbered version.
391     """

Managed by UCC Webmasters ViewVC Help
Powered by ViewVC 1.1.26