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.
........
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 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__":
diff --git a/Lib/test/zipdir.zip b/Lib/test/zipdir.zip
new file mode 100644
index 0000000..ac21d7a
--- /dev/null
+++ b/Lib/test/zipdir.zip
Binary files differ
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 @@
"""
# 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
diff --git a/Misc/NEWS b/Misc/NEWS
index ca5eef1..6f4dd52 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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