Package grizzled :: Package io
[hide private]
[frames] | no frames]

Source Code for Package grizzled.io

  1  # $Id: 0d2e5b9d01530c575fc4f6834113699dda23cc4a $ 
  2   
  3  """ 
  4  Input/Output utility methods and classes. 
  5  """ 
  6   
  7  from __future__ import absolute_import 
  8   
  9  __docformat__ = "restructuredtext en" 
 10   
 11  # --------------------------------------------------------------------------- 
 12  # Imports 
 13  # --------------------------------------------------------------------------- 
 14   
 15  import os 
 16  import zipfile 
 17   
 18  # --------------------------------------------------------------------------- 
 19  # Exports 
 20  # --------------------------------------------------------------------------- 
 21   
 22  __all__ = ['AutoFlush', 'MultiWriter', 'PushbackFile', 'Zip'] 
 23   
 24  # --------------------------------------------------------------------------- 
 25  # Classes 
 26  # --------------------------------------------------------------------------- 
 27   
28 -class AutoFlush(object):
29 """ 30 An ``AutoFlush`` wraps a file-like object and flushes the output 31 (via a call to ``flush()`` after every write operation. Here's how 32 to use an ``AutoFlush`` object to force standard output to flush after 33 every write: 34 35 .. python:: 36 37 import sys 38 from grizzled.io import AutoFlush 39 40 sys.stdout = AutoFlush(sys.stdout) 41 """
42 - def __init__(self, f):
43 """ 44 Create a new ``AutoFlush`` object to wrap a file-like object. 45 46 :Parameters: 47 f : file 48 A file-like object that contains both a ``write()`` method 49 and a ``flush()`` method. 50 """ 51 self.__file = f
52
53 - def write(self, buf):
54 """ 55 Write the specified buffer to the file. 56 57 :Parameters: 58 buf : str or bytes 59 buffer to write 60 """ 61 self.__file.write(buf) 62 self.__file.flush()
63
64 - def flush(self):
65 """ 66 Force a flush. 67 """ 68 self.__file.flush()
69
70 - def truncate(self, size=-1):
71 """ 72 Truncate the underlying file. Might fail. 73 74 :Parameters: 75 size : int 76 Where to truncate. If less than 0, then file's current position 77 is used. 78 """ 79 if size < 0: 80 size = self.__file.tell() 81 self.__file.truncate(size)
82
83 - def tell(self):
84 """ 85 Return the file's current position, if applicable. 86 87 :rtype: int 88 :return: Current file position 89 """ 90 return self.__file.tell()
91
92 - def seek(self, offset, whence=os.SEEK_SET):
93 """ 94 Set the file's current position. The ``whence`` argument is optional; 95 legal values are: 96 97 - ``os.SEEK_SET`` or 0: absolute file positioning (default) 98 - ``os.SEEK_CUR`` or 1: seek relative to the current position 99 - ``os.SEEK_END`` or 2: seek relative to the file's end 100 101 There is no return value. Note that if the file is opened for 102 appending (mode 'a' or 'a+'), any ``seek()`` operations will be undone 103 at the next write. If the file is only opened for writing in append 104 mode (mode 'a'), this method is essentially a no-op, but it remains 105 useful for files opened in append mode with reading enabled (mode 106 'a+'). If the file is opened in text mode (without 'b'), only offsets 107 returned by ``tell()`` are legal. Use of other offsets causes 108 undefined behavior. 109 110 Note that not all file objects are seekable. 111 112 :Parameters: 113 offset : int 114 where to seek 115 whence : int 116 see above 117 """ 118 self.__file.seek(offset, whence)
119
120 - def fileno(self):
121 """ 122 Return the integer file descriptor used by the underlying file. 123 124 :rtype: int 125 :return: the file descriptor 126 """ 127 return self.__file.fileno()
128
129 -class MultiWriter(object):
130 """ 131 Wraps multiple file-like objects so that they all may be written at once. 132 For example, the following code arranges to have anything written to 133 ``sys.stdout`` go to ``sys.stdout`` and to a temporary file: 134 135 .. python:: 136 137 import sys 138 from grizzled.io import MultiWriter 139 140 sys.stdout = MultiWriter(sys.__stdout__, open('/tmp/log', 'w')) 141 """
142 - def __init__(self, *args):
143 """ 144 Create a new ``MultiWriter`` object to wrap one or more file-like 145 objects. 146 147 :Parameters: 148 args : iterable 149 One or more file-like objects to wrap 150 """ 151 self.__files = args
152
153 - def write(self, buf):
154 """ 155 Write the specified buffer to the wrapped files. 156 157 :Parameters: 158 buf : str or bytes 159 buffer to write 160 """ 161 for f in self.__files: 162 f.write(buf)
163
164 - def flush(self):
165 """ 166 Force a flush. 167 """ 168 for f in self.__files: 169 f.flush()
170
171 - def close(self):
172 """ 173 Close all contained files. 174 """ 175 for f in self.__files: 176 f.close()
177
178 -class PushbackFile(object):
179 """ 180 A file-like wrapper object that permits pushback. 181 """
182 - def __init__(self, f):
183 """ 184 Create a new ``PushbackFile`` object to wrap a file-like object. 185 186 :Parameters: 187 f : file 188 A file-like object that contains both a ``write()`` method 189 and a ``flush()`` method. 190 """ 191 self.__buf = [c for c in ''.join(f.readlines())]
192
193 - def write(self, buf):
194 """ 195 Write the specified buffer to the file. This method throws an 196 unconditional exception, since ``PushbackFile`` objects are read-only. 197 198 :Parameters: 199 buf : str or bytes 200 buffer to write 201 202 :raise NotImplementedError: unconditionally 203 """ 204 raise NotImplementedError, 'PushbackFile is read-only'
205
206 - def pushback(self, s):
207 """ 208 Push a character or string back onto the input stream. 209 210 :Parameters: 211 s : str 212 the string to push back onto the input stream 213 """ 214 self.__buf = [c for c in s] + self.__buf
215 216 unread=pushback 217
218 - def read(self, n=-1):
219 """ 220 Read *n* bytes from the open file. 221 222 :Parameters: 223 n : int 224 Number of bytes to read. A negative number instructs 225 ``read()`` to read all remaining bytes. 226 227 :return: the bytes read 228 """ 229 resultBuf = None 230 if n > len(self.__buf): 231 n = len(self.__buf) 232 233 if (n < 0) or (n >= len(self.__buf)): 234 resultBuf = self.__buf 235 self.__buf = [] 236 237 else: 238 resultBuf = self.__buf[0:n] 239 self.__buf = self.__buf[n:] 240 241 return ''.join(resultBuf)
242
243 - def readline(self, length=-1):
244 """ 245 Read the next line from the file. 246 247 :Parameters: 248 length : int 249 a length hint, or negative if you don't care 250 251 :rtype: str 252 :return: the line 253 """ 254 i = 0 255 while i < len(self.__buf) and (self.__buf[i] != '\n'): 256 i += 1 257 258 result = self.__buf[0:i+1] 259 self.__buf = self.__buf[i+1:] 260 return ''.join(result)
261
262 - def readlines(self, sizehint=0):
263 """ 264 Read all remaining lines in the file. 265 266 :rtype: list 267 :return: list of lines 268 """ 269 return self.read(-1)
270
271 - def __iter__(self):
272 return self
273
274 - def next(self):
275 """A file object is its own iterator. 276 277 :rtype: str 278 :return: the next line from the file 279 280 :raise StopIteration: end of file 281 :raise IncludeError: on error 282 """ 283 line = self.readline() 284 if (line == None) or (len(line) == 0): 285 raise StopIteration 286 return line
287
288 - def close(self):
289 """Close the file. A no-op in this class.""" 290 pass
291
292 - def flush(self):
293 """ 294 Force a flush. This method throws an unconditional exception, since 295 ``PushbackFile`` objects are read-only. 296 297 :raise NotImplementedError: unconditionally 298 """ 299 raise NotImplementedError, 'PushbackFile is read-only'
300
301 - def truncate(self, size=-1):
302 """ 303 Truncate the underlying file. This method throws an unconditional exception, since 304 ``PushbackFile`` objects are read-only. 305 306 :Parameters: 307 size : int 308 Where to truncate. If less than 0, then file's current 309 position is used 310 311 :raise NotImplementedError: unconditionally 312 """ 313 raise NotImplementedError, 'PushbackFile is read-only'
314
315 - def tell(self):
316 """ 317 Return the file's current position, if applicable. This method throws 318 an unconditional exception, since ``PushbackFile`` objects are 319 read-only. 320 321 :rtype: int 322 :return: Current file position 323 324 :raise NotImplementedError: unconditionally 325 """ 326 raise NotImplementedError, 'PushbackFile is not seekable'
327
328 - def seek(self, offset, whence=os.SEEK_SET):
329 """ 330 Set the file's current position. This method throws an unconditional 331 exception, since ``PushbackFile`` objects are not seekable. 332 333 :Parameters: 334 offset : int 335 where to seek 336 whence : int 337 see above 338 339 :raise NotImplementedError: unconditionally 340 """ 341 raise NotImplementedError, 'PushbackFile is not seekable'
342
343 - def fileno(self):
344 """ 345 Return the integer file descriptor used by the underlying file. 346 347 :rtype: int 348 :return: the file descriptor 349 """ 350 return -1
351
352 -class Zip(zipfile.ZipFile):
353 """ 354 ``Zip`` extends the standard ``zipfile.ZipFile`` class and provides a 355 method to extract the contents of a zip file into a directory. Adapted 356 from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252508. 357 """
358 - def __init__(self, file, mode="r", 359 compression=zipfile.ZIP_STORED, 360 allow_zip64=False):
361 """ 362 Constructor. Initialize a new zip file. 363 364 :Parameters: 365 file : str 366 path to zip file 367 mode : str 368 open mode. Valid values are 'r' (read), 'w' (write), and 369 'a' (append) 370 compression : int 371 Compression type. Valid values: ``zipfile.ZIP_STORED`, 372 ``zipfile.ZIP_DEFLATED`` 373 allow_zip64 : bool 374 Whether or not Zip64 extensions are to be used 375 """ 376 zipfile.ZipFile.__init__(self, file, mode, compression, allow_zip64) 377 self.zipFile = file
378
379 - def extract(self, output_dir):
380 """ 381 Unpack the zip file into the specified output directory. 382 383 :Parameters: 384 output_dir : str 385 path to output directory. The directory is 386 created if it doesn't already exist. 387 """ 388 if not output_dir.endswith(':') and not os.path.exists(output_dir): 389 os.mkdir(output_dir) 390 391 num_files = len(self.namelist()) 392 393 # extract files to directory structure 394 for i, name in enumerate(self.namelist()): 395 if not name.endswith('/'): 396 directory = os.path.dirname(name) 397 if directory == '': 398 directory = None 399 if directory: 400 directory = os.path.join(output_dir, directory) 401 if not os.path.exists(directory): 402 os.makedirs(directory) 403 404 outfile = open(os.path.join(output_dir, name), 'wb') 405 outfile.write(self.read(name)) 406 outfile.flush() 407 outfile.close()
408