bpo-34097: Add support for zipping files older than 1980-01-01 (GH-8270) · pythoncapi/cpython@a2fe1e5 · GitHub
Skip to content

Commit a2fe1e5

Browse files
Marcel Plchvstinner
authored andcommitted
bpo-34097: Add support for zipping files older than 1980-01-01 (pythonGH-8270)
ZipFile can zip files older than 1980-01-01 and newer than 2107-12-31 using a new strict_timestamps parameter at the cost of setting the timestamp to the limit.
1 parent fc512e3 commit a2fe1e5

4 files changed

Lines changed: 48 additions & 5 deletions

File tree

Doc/library/zipfile.rst

Lines changed: 20 additions & 2 deletions

Lib/test/test_zipfile.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,22 @@ def test_add_file_before_1980(self):
549549
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
550550
self.assertRaises(ValueError, zipfp.write, TESTFN)
551551

552+
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
553+
zipfp.write(TESTFN, strict_timestamps=False)
554+
zinfo = zipfp.getinfo(TESTFN)
555+
self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))
556+
557+
def test_add_file_after_2107(self):
558+
# Set atime and mtime to 2108-12-30
559+
os.utime(TESTFN, (4386268800, 4386268800))
560+
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
561+
self.assertRaises(struct.error, zipfp.write, TESTFN)
562+
563+
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
564+
zipfp.write(TESTFN, strict_timestamps=False)
565+
zinfo = zipfp.getinfo(TESTFN)
566+
self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
567+
552568

553569
@requires_zlib
554570
class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,

Lib/zipfile.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def _decodeExtra(self):
469469
extra = extra[ln+4:]
470470

471471
@classmethod
472-
def from_file(cls, filename, arcname=None):
472+
def from_file(cls, filename, arcname=None, *, strict_timestamps=True):
473473
"""Construct an appropriate ZipInfo for a file on the filesystem.
474474
475475
filename should be the path to a file or directory on the filesystem.
@@ -484,6 +484,10 @@ def from_file(cls, filename, arcname=None):
484484
isdir = stat.S_ISDIR(st.st_mode)
485485
mtime = time.localtime(st.st_mtime)
486486
date_time = mtime[0:6]
487+
if not strict_timestamps and date_time[0] < 1980:
488+
date_time = (1980, 1, 1, 0, 0, 0)
489+
elif not strict_timestamps and date_time[0] > 2107:
490+
date_time = (2107, 12, 31, 23, 59, 59)
487491
# Create ZipInfo instance to store file information
488492
if arcname is None:
489493
arcname = filename
@@ -1673,7 +1677,8 @@ def _writecheck(self, zinfo):
16731677
" would require ZIP64 extensions")
16741678

16751679
def write(self, filename, arcname=None,
1676-
compress_type=None, compresslevel=None):
1680+
compress_type=None, compresslevel=None, *,
1681+
strict_timestamps=True):
16771682
"""Put the bytes from filename into the archive under the name
16781683
arcname."""
16791684
if not self.fp:
@@ -1684,7 +1689,8 @@ def write(self, filename, arcname=None,
16841689
"Can't write to ZIP archive while an open writing handle exists"
16851690
)
16861691

1687-
zinfo = ZipInfo.from_file(filename, arcname)
1692+
zinfo = ZipInfo.from_file(filename, arcname,
1693+
strict_timestamps=strict_timestamps)
16881694

16891695
if zinfo.is_dir():
16901696
zinfo.compress_size = 0
Lines changed: 3 additions & 0 deletions

0 commit comments

Comments
 (0)