[Python-checkins] r68886 - in python/branches/release26-maint: Lib/test/test_zipfile.py Lib/test/zipdir.zip Lib/zipfile.py Misc/NEWS

martin.v.loewis python-checkins at python.org
Sat Jan 24 15:04:36 CET 2009


Author: martin.v.loewis
Date: Sat Jan 24 15:04:33 2009
New Revision: 68886

Log:
Merged revisions 68885 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r68885 | martin.v.loewis | 2009-01-24 15:00:33 +0100 (Sa, 24 Jan 2009) | 3 lines
  
  Issue #4710: Extract directories properly in the zipfile module;
  allow adding directories to a zipfile.
........


Added:
   python/branches/release26-maint/Lib/test/zipdir.zip
      - copied unchanged from r68885, /python/trunk/Lib/test/zipdir.zip
Modified:
   python/branches/release26-maint/   (props changed)
   python/branches/release26-maint/Lib/test/test_zipfile.py
   python/branches/release26-maint/Lib/zipfile.py
   python/branches/release26-maint/Misc/NEWS

Modified: python/branches/release26-maint/Lib/test/test_zipfile.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_zipfile.py	(original)
+++ python/branches/release26-maint/Lib/test/test_zipfile.py	Sat Jan 24 15:04:33 2009
@@ -11,9 +11,10 @@
 from random import randint, random
 
 import test.test_support as support
-from test.test_support import TESTFN, run_unittest
+from test.test_support import TESTFN, run_unittest, findfile
 
 TESTFN2 = TESTFN + "2"
+TESTFNDIR = TESTFN + "d"
 FIXEDTEST_SIZE = 1000
 
 SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
@@ -982,6 +983,28 @@
     def tearDown(self):
         os.remove(TESTFN2)
 
+class TestWithDirectory(unittest.TestCase):
+    def setUp(self):
+        os.mkdir(TESTFN2)
+
+    def testExtractDir(self):
+        zipf = zipfile.ZipFile(findfile("zipdir.zip"))
+        zipf.extractall(TESTFN2)
+        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
+        self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
+        self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
+
+    def testStoreDir(self):
+        os.mkdir(os.path.join(TESTFN2, "x"))
+        zipf = zipfile.ZipFile(TESTFN, "w")
+        zipf.write(os.path.join(TESTFN2, "x"), "x")
+        self.assertTrue(zipf.filelist[0].filename.endswith("x/"))
+
+    def tearDown(self):
+        shutil.rmtree(TESTFN2)
+        if os.path.exists(TESTFN):
+            os.remove(TESTFN)
+
 
 class UniversalNewlineTests(unittest.TestCase):
     def setUp(self):
@@ -1090,6 +1113,7 @@
 def test_main():
     run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
                  PyZipFileTests, DecryptionTests, TestsWithMultipleOpens,
+                 TestWithDirectory,
                  UniversalNewlineTests, TestsWithRandomBinaryFiles)
 
 if __name__ == "__main__":

Modified: python/branches/release26-maint/Lib/zipfile.py
==============================================================================
--- python/branches/release26-maint/Lib/zipfile.py	(original)
+++ python/branches/release26-maint/Lib/zipfile.py	Sat Jan 24 15:04:33 2009
@@ -2,7 +2,7 @@
 Read and write ZIP files.
 """
 import struct, os, time, sys, shutil
-import binascii, cStringIO
+import binascii, cStringIO, stat
 
 try:
     import zlib # We may need its compression method
@@ -940,11 +940,11 @@
         """
         # build the destination pathname, replacing
         # forward slashes to platform specific separators.
-        if targetpath[-1:] == "/":
+        if targetpath[-1:] in (os.path.sep, os.path.altsep):
             targetpath = targetpath[:-1]
 
         # don't include leading "/" from file name if present
-        if os.path.isabs(member.filename):
+        if member.filename[0] == '/':
             targetpath = os.path.join(targetpath, member.filename[1:])
         else:
             targetpath = os.path.join(targetpath, member.filename)
@@ -956,6 +956,10 @@
         if upperdirs and not os.path.exists(upperdirs):
             os.makedirs(upperdirs)
 
+        if member.filename[-1] == '/':
+            os.mkdir(targetpath)
+            return targetpath
+
         source = self.open(member, pwd=pwd)
         target = file(targetpath, "wb")
         shutil.copyfileobj(source, target)
@@ -995,6 +999,7 @@
                   "Attempt to write to ZIP archive that was already closed")
 
         st = os.stat(filename)
+        isdir = stat.S_ISDIR(st.st_mode)
         mtime = time.localtime(st.st_mtime)
         date_time = mtime[0:6]
         # Create ZipInfo instance to store file information
@@ -1003,6 +1008,8 @@
         arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
         while arcname[0] in (os.sep, os.altsep):
             arcname = arcname[1:]
+        if isdir:
+            arcname += '/'
         zinfo = ZipInfo(arcname, date_time)
         zinfo.external_attr = (st[0] & 0xFFFF) << 16L      # Unix attributes
         if compress_type is None:
@@ -1016,6 +1023,16 @@
 
         self._writecheck(zinfo)
         self._didModify = True
+
+        if isdir:
+            zinfo.file_size = 0
+            zinfo.compress_size = 0
+            zinfo.CRC = 0
+            self.filelist.append(zinfo)
+            self.NameToInfo[zinfo.filename] = zinfo
+            self.fp.write(zinfo.FileHeader())
+            return
+
         fp = open(filename, "rb")
         # Must overwrite CRC and sizes with correct data later
         zinfo.CRC = CRC = 0

Modified: python/branches/release26-maint/Misc/NEWS
==============================================================================
--- python/branches/release26-maint/Misc/NEWS	(original)
+++ python/branches/release26-maint/Misc/NEWS	Sat Jan 24 15:04:33 2009
@@ -76,6 +76,9 @@
 Library
 -------
 
+- Issue #4710: Extract directories properly in the zipfile module;
+  allow adding directories to a zipfile.
+
 - Issue #5008: When a file is opened in append mode with the new IO library,
   do an explicit seek to the end of file (so that e.g. tell() returns the
   file size rather than 0). This is consistent with the behaviour of the


More information about the Python-checkins mailing list