]> granicus.if.org Git - python/commitdiff
Issue #14099: Restored support of writing ZIP files to tellable but
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 26 Jan 2015 12:01:27 +0000 (14:01 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Mon, 26 Jan 2015 12:01:27 +0000 (14:01 +0200)
non-seekable streams.

Lib/test/test_zipfile.py
Lib/zipfile.py
Misc/NEWS

index 57431c7809b9eb71d56118107ac163dbe23020f5..abe80e4de2a76f66680f6cceeb3c27145a82cd31 100644 (file)
@@ -1668,6 +1668,34 @@ class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
     compression = zipfile.ZIP_LZMA
 
 
+# Privide the tell() method but not seek()
+class Tellable:
+    def __init__(self, fp):
+        self.fp = fp
+        self.offset = 0
+
+    def write(self, data):
+        self.offset += self.fp.write(data)
+
+    def tell(self):
+        return self.offset
+
+    def flush(self):
+        pass
+
+class UnseekableTests(unittest.TestCase):
+    def test_writestr_tellable(self):
+        f = io.BytesIO()
+        with zipfile.ZipFile(Tellable(f), 'w', zipfile.ZIP_STORED) as zipfp:
+            zipfp.writestr('ones', b'111')
+            zipfp.writestr('twos', b'222')
+        with zipfile.ZipFile(f, mode='r') as zipf:
+            with zipf.open('ones') as zopen:
+                self.assertEqual(zopen.read(), b'111')
+            with zipf.open('twos') as zopen:
+                self.assertEqual(zopen.read(), b'222')
+
+
 @requires_zlib
 class TestsWithMultipleOpens(unittest.TestCase):
     @classmethod
index d0789b69215f43c19b2410a9ae939cfe508ac3de..845c6a96fc61bef97c28c274522303f560933122 100644 (file)
@@ -1504,7 +1504,14 @@ class ZipFile:
 
         zinfo.file_size = len(data)            # Uncompressed size
         with self._lock:
-            self.fp.seek(self.start_dir, 0)
+            try:
+                self.fp.seek(self.start_dir)
+            except (AttributeError, io.UnsupportedOperation):
+                # Some file-like objects can provide tell() but not seek()
+                pass
+            zinfo.header_offset = self.fp.tell()    # Start of header data
+            if compress_type is not None:
+                zinfo.compress_type = compress_type
             zinfo.header_offset = self.fp.tell()    # Start of header data
             if compress_type is not None:
                 zinfo.compress_type = compress_type
@@ -1550,7 +1557,11 @@ class ZipFile:
         try:
             if self.mode in ("w", "a") and self._didModify: # write ending records
                 with self._lock:
-                    self.fp.seek(self.start_dir, 0)
+                    try:
+                        self.fp.seek(self.start_dir)
+                    except (AttributeError, io.UnsupportedOperation):
+                        # Some file-like objects can provide tell() but not seek()
+                        pass
                     self._write_end_record()
         finally:
             fp = self.fp
@@ -1558,7 +1569,6 @@ class ZipFile:
             self._fpclose(fp)
 
     def _write_end_record(self):
-        self.fp.seek(self.start_dir, 0)
         for zinfo in self.filelist:         # write central directory
             dt = zinfo.date_time
             dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
index 21f1ac9e161f6b902690509527d8a4484dc0ddbc..d9acd567101d69ee00fce111c41d16cbeb2d3ee0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -218,6 +218,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #14099: Restored support of writing ZIP files to tellable but
+  non-seekable streams.
+
 - Issue #14099: Writing to ZipFile and reading multiple ZipExtFiles is
   threadsafe now.