@@ -285,53 +285,84 @@ def ZipFile(*args, **kwargs):
285
285
ZipFile = zipfile .ZipFile
286
286
287
287
288
- def _get_handle (path , mode , encoding = None , compression = None , memory_map = False ):
288
+ def _get_handle (source , mode , encoding = None , compression = None , memory_map = False ):
289
289
"""Gets file handle for given path and mode.
290
290
"""
291
- if compression is not None :
292
- if encoding is not None and not compat .PY3 :
291
+
292
+ f = source
293
+ is_path = isinstance (source , compat .string_types )
294
+
295
+ # in Python 3, convert BytesIO or fileobjects passed with an encoding
296
+ if compat .PY3 and isinstance (source , compat .BytesIO ):
297
+ from io import TextIOWrapper
298
+
299
+ return TextIOWrapper (source , encoding = encoding )
300
+
301
+ elif compression is not None :
302
+ compression = compression .lower ()
303
+ if encoding is not None and not compat .PY3 and not is_path :
293
304
msg = 'encoding + compression not yet supported in Python 2'
294
305
raise ValueError (msg )
295
306
307
+ # GZ Compression
296
308
if compression == 'gzip' :
297
309
import gzip
298
- f = gzip .GzipFile (path , mode )
310
+
311
+ f = gzip .GzipFile (source , mode ) \
312
+ if is_path else gzip .GzipFile (fileobj = source )
313
+
314
+ # BZ Compression
299
315
elif compression == 'bz2' :
300
316
import bz2
301
- f = bz2 .BZ2File (path , mode )
317
+
318
+ if is_path :
319
+ f = bz2 .BZ2File (source , mode )
320
+
321
+ else :
322
+ f = bz2 .BZ2File (source ) if compat .PY3 else StringIO (
323
+ bz2 .decompress (source .read ()))
324
+ # Python 2's bz2 module can't take file objects, so have to
325
+ # run through decompress manually
326
+
327
+ # ZIP Compression
302
328
elif compression == 'zip' :
303
329
import zipfile
304
- zip_file = zipfile .ZipFile (path )
330
+ zip_file = zipfile .ZipFile (source )
305
331
zip_names = zip_file .namelist ()
306
332
307
333
if len (zip_names ) == 1 :
308
- file_name = zip_names .pop ()
309
- f = zip_file .open (file_name )
334
+ f = zip_file .open (zip_names .pop ())
310
335
elif len (zip_names ) == 0 :
311
336
raise ValueError ('Zero files found in ZIP file {}'
312
- .format (path ))
337
+ .format (source ))
313
338
else :
314
339
raise ValueError ('Multiple files found in ZIP file.'
315
340
' Only one file per ZIP :{}'
316
341
.format (zip_names ))
342
+
343
+ # XZ Compression
317
344
elif compression == 'xz' :
318
345
lzma = compat .import_lzma ()
319
- f = lzma .LZMAFile (path , mode )
346
+ f = lzma .LZMAFile (source , mode )
347
+
320
348
else :
321
- raise ValueError ('Unrecognized compression type : %s' %
322
- compression )
349
+ raise ValueError ('Unrecognized compression: %s' % compression )
350
+
323
351
if compat .PY3 :
324
352
from io import TextIOWrapper
353
+
325
354
f = TextIOWrapper (f , encoding = encoding )
355
+
326
356
return f
327
- else :
357
+
358
+ elif is_path :
328
359
if compat .PY3 :
329
360
if encoding :
330
- f = open (path , mode , encoding = encoding )
361
+ f = open (source , mode , encoding = encoding )
331
362
else :
332
- f = open (path , mode , errors = 'replace' )
363
+ f = open (source , mode , errors = 'replace' )
333
364
else :
334
- f = open (path , mode )
365
+ f = open (source , mode )
335
366
336
367
if memory_map and hasattr (f , 'fileno' ):
337
368
try :
0 commit comments