Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f50b38a

Browse files
committed
Merge #14399: zipfile now correctly handles comments added to empty zipfiles.
Patch by Serhiy Storchaka. This also moves the TypeError that results from trying to use a unicode comment from the 'close' step to the point at which the comment is added to the zipfile.
1 parent 6125e23 commit f50b38a

3 files changed

Lines changed: 49 additions & 11 deletions

File tree

Lib/test/test_zipfile.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,28 @@ def test_comments(self):
970970
with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
971971
self.assertEqual(zipfr.comment, comment2)
972972

973+
def test_unicode_comment(self):
974+
with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
975+
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
976+
with self.assertRaises(TypeError):
977+
zipf.comment = "this is an error"
978+
979+
def test_change_comment_in_empty_archive(self):
980+
with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
981+
self.assertFalse(zipf.filelist)
982+
zipf.comment = b"this is a comment"
983+
with zipfile.ZipFile(TESTFN, "r") as zipf:
984+
self.assertEqual(zipf.comment, b"this is a comment")
985+
986+
def test_change_comment_in_nonempty_archive(self):
987+
with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
988+
zipf.writestr("foo.txt", "O, for a Muse of Fire!")
989+
with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
990+
self.assertTrue(zipf.filelist)
991+
zipf.comment = b"this is a comment"
992+
with zipfile.ZipFile(TESTFN, "r") as zipf:
993+
self.assertEqual(zipf.comment, b"this is a comment")
994+
973995
def check_testzip_with_bad_crc(self, compression):
974996
"""Tests that files with bad CRCs return their name from testzip."""
975997
zipdata = self.zips_with_bad_crc[compression]

Lib/zipfile.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
698698
self.compression = compression # Method of compression
699699
self.mode = key = mode.replace('b', '')[0]
700700
self.pwd = None
701-
self.comment = b''
701+
self._comment = b''
702702

703703
# Check if we were passed a file-like object
704704
if isinstance(file, str):
@@ -774,7 +774,7 @@ def _RealGetContents(self):
774774
print(endrec)
775775
size_cd = endrec[_ECD_SIZE] # bytes in central directory
776776
offset_cd = endrec[_ECD_OFFSET] # offset of central directory
777-
self.comment = endrec[_ECD_COMMENT] # archive comment
777+
self._comment = endrec[_ECD_COMMENT] # archive comment
778778

779779
# "concat" is zero, unless zip was concatenated to another file
780780
concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
@@ -886,6 +886,24 @@ def setpassword(self, pwd):
886886
else:
887887
self.pwd = None
888888

889+
@property
890+
def comment(self):
891+
"""The comment text associated with the ZIP file."""
892+
return self._comment
893+
894+
@comment.setter
895+
def comment(self, comment):
896+
if not isinstance(comment, bytes):
897+
raise TypeError("comment: expected bytes, got %s" % type(comment))
898+
# check for valid comment length
899+
if len(comment) >= ZIP_MAX_COMMENT:
900+
if self.debug:
901+
print('Archive comment is too long; truncating to %d bytes'
902+
% ZIP_MAX_COMMENT)
903+
comment = comment[:ZIP_MAX_COMMENT]
904+
self._comment = comment
905+
self._didModify = True
906+
889907
def read(self, name, pwd=None):
890908
"""Return file bytes (as a string) for name."""
891909
with self.open(name, "r", pwd) as fp:
@@ -1287,18 +1305,11 @@ def close(self):
12871305
centDirSize = min(centDirSize, 0xFFFFFFFF)
12881306
centDirOffset = min(centDirOffset, 0xFFFFFFFF)
12891307

1290-
# check for valid comment length
1291-
if len(self.comment) >= ZIP_MAX_COMMENT:
1292-
if self.debug > 0:
1293-
msg = 'Archive comment is too long; truncating to %d bytes' \
1294-
% ZIP_MAX_COMMENT
1295-
self.comment = self.comment[:ZIP_MAX_COMMENT]
1296-
12971308
endrec = struct.pack(structEndArchive, stringEndArchive,
12981309
0, 0, centDirCount, centDirCount,
1299-
centDirSize, centDirOffset, len(self.comment))
1310+
centDirSize, centDirOffset, len(self._comment))
13001311
self.fp.write(endrec)
1301-
self.fp.write(self.comment)
1312+
self.fp.write(self._comment)
13021313
self.fp.flush()
13031314

13041315
if not self._filePassed:

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ Core and Builtins
1919
Library
2020
-------
2121

22+
- Issue #14399: zipfile now correctly adds a comment even when the zipfile
23+
being created is otherwise empty. In addition, the TypeError that results
24+
from trying to set a non-binary value as a comment is now now raised at the
25+
time the comment is set rather than at the time the zipfile is written.
26+
2227
- trace.CoverageResults.is_ignored_filename() now ignores any name that starts
2328
with "<" and ends with ">" instead of special-casing "<string>" and
2429
"<doctest ".

0 commit comments

Comments
 (0)