[Python-checkins] r46005 - in python/trunk: Lib/tarfile.py Lib/test/test_tarfile.py Misc/NEWS

georg.brandl python-checkins at python.org
Mon May 15 21:30:36 CEST 2006


Author: georg.brandl
Date: Mon May 15 21:30:35 2006
New Revision: 46005

Modified:
   python/trunk/Lib/tarfile.py
   python/trunk/Lib/test/test_tarfile.py
   python/trunk/Misc/NEWS
Log:
[ 1488881 ] tarfile.py: support for file-objects and bz2 (cp. #1488634)



Modified: python/trunk/Lib/tarfile.py
==============================================================================
--- python/trunk/Lib/tarfile.py	(original)
+++ python/trunk/Lib/tarfile.py	Mon May 15 21:30:35 2006
@@ -556,6 +556,69 @@
         self.fileobj.close()
 # class StreamProxy
 
+class _BZ2Proxy(object):
+    """Small proxy class that enables external file object
+       support for "r:bz2" and "w:bz2" modes. This is actually
+       a workaround for a limitation in bz2 module's BZ2File
+       class which (unlike gzip.GzipFile) has no support for
+       a file object argument.
+    """
+
+    blocksize = 16 * 1024
+
+    def __init__(self, fileobj, mode):
+        self.fileobj = fileobj
+        self.mode = mode
+        self.init()
+
+    def init(self):
+        import bz2
+        self.pos = 0
+        if self.mode == "r":
+            self.bz2obj = bz2.BZ2Decompressor()
+            self.fileobj.seek(0)
+            self.buf = ""
+        else:
+            self.bz2obj = bz2.BZ2Compressor()
+
+    def read(self, size):
+        b = [self.buf]
+        x = len(self.buf)
+        while x < size:
+            try:
+                raw = self.fileobj.read(self.blocksize)
+                data = self.bz2obj.decompress(raw)
+                b.append(data)
+            except EOFError:
+                break
+            x += len(data)
+        self.buf = "".join(b)
+
+        buf = self.buf[:size]
+        self.buf = self.buf[size:]
+        self.pos += len(buf)
+        return buf
+
+    def seek(self, pos):
+        if pos < self.pos:
+            self.init()
+        self.read(pos - self.pos)
+
+    def tell(self):
+        return self.pos
+
+    def write(self, data):
+        self.pos += len(data)
+        raw = self.bz2obj.compress(data)
+        self.fileobj.write(raw)
+
+    def close(self):
+        if self.mode == "w":
+            raw = self.bz2obj.flush()
+            self.fileobj.write(raw)
+            self.fileobj.close()
+# class _BZ2Proxy
+
 #------------------------
 # Extraction file object
 #------------------------
@@ -1057,10 +1120,12 @@
         tarname = pre + ext
 
         if fileobj is not None:
-            raise ValueError, "no support for external file objects"
+            fileobj = _BZ2Proxy(fileobj, mode)
+        else:
+            fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel)
 
         try:
-            t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel))
+            t = cls.taropen(tarname, mode, fileobj)
         except IOError:
             raise ReadError, "not a bzip2 file"
         t._extfileobj = False

Modified: python/trunk/Lib/test/test_tarfile.py
==============================================================================
--- python/trunk/Lib/test/test_tarfile.py	(original)
+++ python/trunk/Lib/test/test_tarfile.py	Mon May 15 21:30:35 2006
@@ -212,6 +212,17 @@
 
         stream.close()
 
+class ReadDetectTest(ReadTest):
+
+    def setUp(self):
+        self.tar = tarfile.open(tarname(self.comp), self.mode)
+
+class ReadDetectFileobjTest(ReadTest):
+
+    def setUp(self):
+        name = tarname(self.comp)
+        self.tar = tarfile.open(name, mode=self.mode, fileobj=file(name))
+
 class ReadAsteriskTest(ReadTest):
 
     def setUp(self):
@@ -503,6 +514,10 @@
     comp = "gz"
 class WriteStreamTestGzip(WriteStreamTest):
     comp = "gz"
+class ReadDetectTestGzip(ReadDetectTest):
+    comp = "gz"
+class ReadDetectFileobjTestGzip(ReadDetectFileobjTest):
+    comp = "gz"
 class ReadAsteriskTestGzip(ReadAsteriskTest):
     comp = "gz"
 class ReadStreamAsteriskTestGzip(ReadStreamAsteriskTest):
@@ -526,6 +541,10 @@
         comp = "bz2"
     class WriteStreamTestBzip2(WriteStreamTestGzip):
         comp = "bz2"
+    class ReadDetectTestBzip2(ReadDetectTest):
+        comp = "bz2"
+    class ReadDetectFileobjTestBzip2(ReadDetectFileobjTest):
+        comp = "bz2"
     class ReadAsteriskTestBzip2(ReadAsteriskTest):
         comp = "bz2"
     class ReadStreamAsteriskTestBzip2(ReadStreamAsteriskTest):
@@ -550,6 +569,8 @@
         FileModeTest,
         ReadTest,
         ReadStreamTest,
+        ReadDetectTest,
+        ReadDetectFileobjTest,
         ReadAsteriskTest,
         ReadStreamAsteriskTest,
         WriteTest,
@@ -567,6 +588,7 @@
         tests.extend([
             ReadTestGzip, ReadStreamTestGzip,
             WriteTestGzip, WriteStreamTestGzip,
+            ReadDetectTestGzip, ReadDetectFileobjTestGzip,
             ReadAsteriskTestGzip, ReadStreamAsteriskTestGzip
         ])
 
@@ -574,6 +596,7 @@
         tests.extend([
             ReadTestBzip2, ReadStreamTestBzip2,
             WriteTestBzip2, WriteStreamTestBzip2,
+            ReadDetectTestBzip2, ReadDetectFileobjTestBzip2,
             ReadAsteriskTestBzip2, ReadStreamAsteriskTestBzip2
         ])
     try:

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Mon May 15 21:30:35 2006
@@ -40,6 +40,9 @@
 Library
 -------
 
+- Patch #1488881: add support for external file objects in bz2 compressed
+  tarfiles.
+
 - Patch #721464: pdb.Pdb instances can now be given explicit stdin and
   stdout arguments, making it possible to redirect input and output
   for remote debugging.


More information about the Python-checkins mailing list