Index: zipfile.py =================================================================== --- zipfile.py (wersja 67911) +++ zipfile.py (kopia robocza) @@ -945,9 +945,14 @@ """ # build the destination pathname, replacing # forward slashes to platform specific separators. - if targetpath[-1:] == "/": + if targetpath[-1:] == os.sep: targetpath = targetpath[:-1] + isdir = False + + if member.filename[-1:] == os.sep: + isdir = True + # don't include leading "/" from file name if present if os.path.isabs(member.filename): targetpath = os.path.join(targetpath, member.filename[1:]) @@ -958,9 +963,13 @@ # Create all upper directories if necessary. upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): + if upperdirs and not os.path.isdir(upperdirs): os.makedirs(upperdirs) + if isdir: + os.mkdir(targetpath) + return targetpath + source = self.open(member, pwd=pwd) target = file(targetpath, "wb") shutil.copyfileobj(source, target) @@ -999,15 +1008,26 @@ raise RuntimeError( "Attempt to write to ZIP archive that was already closed") + isdir = False + + if os.path.isdir(filename): + isdir = True + st = os.stat(filename) mtime = time.localtime(st.st_mtime) date_time = mtime[0:6] + # Create ZipInfo instance to store file information if arcname is None: arcname = filename + arcname = os.path.normpath(os.path.splitdrive(arcname)[1]) while arcname[0] in (os.sep, os.altsep): arcname = arcname[1:] + + if isdir: + arcname += os.sep + zinfo = ZipInfo(arcname, date_time) zinfo.external_attr = (st[0] & 0xFFFF) << 16L # Unix attributes if compress_type is None: @@ -1019,6 +1039,14 @@ zinfo.flag_bits = 0x00 zinfo.header_offset = self.fp.tell() # Start of header bytes + if isdir: + zinfo.file_size = 0 + zinfo.compress_size = 0 + zinfo.CRC = 0 + self.filelist.append(zinfo) + self.NameToInfo[zinfo.filename] = zinfo + return + self._writecheck(zinfo) self._didModify = True fp = open(filename, "rb") Index: test/test_zipfile.py =================================================================== --- test/test_zipfile.py (wersja 67911) +++ test/test_zipfile.py (kopia robocza) @@ -14,6 +14,8 @@ from test.test_support import TESTFN, run_unittest TESTFN2 = TESTFN + "2" +TESTDN = TESTFN + "3" +TESTDN2 = TESTFN + "4" + os.sep FIXEDTEST_SIZE = 1000 SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), @@ -32,12 +34,23 @@ fp.write(self.data) fp.close() + # Create a directory + if not os.path.isdir(TESTDN): + os.mkdir(TESTDN) + + fp = open(TESTDN+os.sep+TESTFN, "wb") + fp.write(self.data) + fp.close() + def makeTestArchive(self, f, compression): # Create the ZIP archive zipfp = zipfile.ZipFile(f, "w", compression) zipfp.write(TESTFN, "another"+os.extsep+"name") zipfp.write(TESTFN, TESTFN) + zipfp.write(TESTDN) + zipfp.write(TESTDN+os.sep+TESTFN) zipfp.writestr("strfile", self.data) + zipfp.writestr(TESTDN+os.sep+"strfile", self.data) zipfp.close() def zipTest(self, f, compression): @@ -48,6 +61,8 @@ self.assertEqual(zipfp.read(TESTFN), self.data) self.assertEqual(zipfp.read("another"+os.extsep+"name"), self.data) self.assertEqual(zipfp.read("strfile"), self.data) + self.assertEqual(zipfp.read(TESTDN+os.sep+"strfile"), self.data) + self.assertEqual(zipfp.read(TESTDN+os.sep+TESTFN), self.data) # Print the ZIP directory fp = StringIO() @@ -61,7 +76,7 @@ directory = fp.getvalue() lines = directory.splitlines() - self.assertEquals(len(lines), 4) # Number of files + header + self.assertEquals(len(lines), 7) # Number of files + header self.assert_('File Name' in lines[0]) self.assert_('Modified' in lines[0]) @@ -74,23 +89,31 @@ # Check the namelist names = zipfp.namelist() - self.assertEquals(len(names), 3) + self.assertEquals(len(names), 6) self.assert_(TESTFN in names) self.assert_("another"+os.extsep+"name" in names) self.assert_("strfile" in names) + self.assert_(TESTDN+os.sep in names) + self.assert_(TESTDN+os.sep+"strfile" in names) + self.assert_(TESTDN+os.sep+TESTFN in names) # Check infolist infos = zipfp.infolist() names = [ i.filename for i in infos ] - self.assertEquals(len(names), 3) + self.assertEquals(len(names), 6) self.assert_(TESTFN in names) + self.assert_(TESTDN+os.sep in names) + self.assert_(TESTDN+os.sep+"strfile" in names) + self.assert_(TESTDN+os.sep+TESTFN in names) self.assert_("another"+os.extsep+"name" in names) self.assert_("strfile" in names) for i in infos: + if i.filename[-1:] == os.sep: + continue self.assertEquals(i.file_size, len(self.data)) # check getinfo - for nm in (TESTFN, "another"+os.extsep+"name", "strfile"): + for nm in (TESTFN, "another"+os.extsep+"name", "strfile", TESTDN+os.sep+TESTFN): info = zipfp.getinfo(nm) self.assertEquals(info.filename, nm) self.assertEquals(info.file_size, len(self.data)) @@ -124,8 +147,17 @@ break zipdata2.append(read_data) + zipdata3 = [] + zipopen3 = zipfp.open(TESTDN+os.sep+"strfile") + while 1: + read_data = zipopen3.read(256) + if not read_data: + break + zipdata3.append(read_data) + self.assertEqual(''.join(zipdata1), self.data) self.assertEqual(''.join(zipdata2), self.data) + self.assertEqual(''.join(zipdata3), self.data) zipfp.close() def testOpenStored(self): @@ -256,11 +288,12 @@ def testAbsoluteArcnames(self): zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) - zipfp.write(TESTFN, "/absolute") + zipfp.write(TESTDN, "/absolute") + zipfp.write(TESTDN2, "/absolute/dir") zipfp.close() zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) - self.assertEqual(zipfp.namelist(), ["absolute"]) + self.assertEqual(zipfp.namelist(), ["absolute", "absolute/dir/"]) zipfp.close() def testAppendToZipFile(self): @@ -324,6 +357,8 @@ zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) for fpath, fdata in SMALL_TEST_DATA: zipfp.writestr(fpath, fdata) + zipfp.write(TESTDN) + zipfp.printdir() zipfp.close() zipfp = zipfile.ZipFile(TESTFN2, "r") @@ -344,6 +379,16 @@ os.remove(writtenfile) + writtendir = zipfp.extract(TESTDN+os.sep, TESTDN2) + + correctdir = os.path.join(os.getcwd(), TESTDN2, TESTDN) + correctdir = os.path.normpath(correctdir) + + self.assertEqual(writtendir, correctdir) + self.assert_(os.path.isdir(correctdir)) + + os.rmdir(TESTDN2) + zipfp.close() # remove the test file subdirectories @@ -353,20 +398,35 @@ zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) for fpath, fdata in SMALL_TEST_DATA: zipfp.writestr(fpath, fdata) + + for fpath in (TESTDN, TESTDN+os.sep+TESTFN): + zipfp.write(fpath) + + zipfp.write(TESTDN+os.sep+TESTFN, TESTDN+os.sep+TESTFN2) zipfp.close() zipfp = zipfile.ZipFile(TESTFN2, "r") - zipfp.extractall() + zipfp.extractall(TESTDN2) for fpath, fdata in SMALL_TEST_DATA: if os.path.isabs(fpath): - outfile = os.path.join(os.getcwd(), fpath[1:]) + outfile = os.path.join(os.getcwd(), TESTDN2, fpath[1:]) else: - outfile = os.path.join(os.getcwd(), fpath) + outfile = os.path.join(os.getcwd(), TESTDN2, fpath) self.assertEqual(fdata, file(outfile, "rb").read()) os.remove(outfile) + for fpath in (TESTDN, TESTDN+os.sep+TESTFN, TESTDN+os.sep+TESTFN2): + correctpath = os.path.join(os.getcwd(), TESTDN2, fpath) + + self.assert_(os.path.exists(correctpath)) + + if os.path.isdir(correctpath): + shutil.rmtree(correctpath) + else: + os.remove(correctpath) + zipfp.close() # remove the test file subdirectories