diff options
-rw-r--r-- | Lib/test/test_zipfile.py | 26 | ||||
-rw-r--r-- | Lib/test/zipdir.zip | bin | 0 -> 374 bytes | |||
-rw-r--r-- | Lib/zipfile.py | 23 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
4 files changed, 48 insertions, 4 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 5e99382..21fc703 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -11,9 +11,10 @@ from tempfile import TemporaryFile 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 @@ class TestsWithMultipleOpens(unittest.TestCase): 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 @@ class UniversalNewlineTests(unittest.TestCase): def test_main(): run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, + TestWithDirectory, UniversalNewlineTests, TestsWithRandomBinaryFiles) if __name__ == "__main__": diff --git a/Lib/test/zipdir.zip b/Lib/test/zipdir.zip Binary files differnew file mode 100644 index 0000000..ac21d7a --- /dev/null +++ b/Lib/test/zipdir.zip diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 85012d8..fe01296 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -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 @@ class ZipFile: """ # 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 @@ class ZipFile: 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 @@ class ZipFile: "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 @@ class ZipFile: 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 @@ class ZipFile: 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 @@ -76,6 +76,9 @@ Core and Builtins 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 |