.. method:: ZipFile.write(filename, arcname=None, compress_type=None, \
- compresslevel=None)
+ compresslevel=None, *, strict_timestamps=True)
Write the file named *filename* to the archive, giving it the archive name
*arcname* (by default, this will be the same as *filename*, but without a drive
the new entry. Similarly, *compresslevel* will override the constructor if
given.
The archive must be open with mode ``'w'``, ``'x'`` or ``'a'``.
+ The *strict_timestamps* argument, when set to ``False``, allows to
+ zip files older than 1980-01-01 at the cost of setting the
+ timestamp to 1980-01-01.
+ Similar behavior occurs with files newer than 2107-12-31,
+ the timestamp is also set to the limit.
.. note::
a closed ZipFile will raise a :exc:`ValueError`. Previously,
a :exc:`RuntimeError` was raised.
+ .. versionadded:: 3.8
+ The *strict_timestamps* keyword-only argument
+
.. method:: ZipFile.writestr(zinfo_or_arcname, data, compress_type=None, \
compresslevel=None)
There is one classmethod to make a :class:`ZipInfo` instance for a filesystem
file:
-.. classmethod:: ZipInfo.from_file(filename, arcname=None)
+.. classmethod:: ZipInfo.from_file(filename, arcname=None, *, \
+ strict_timestamps=True)
Construct a :class:`ZipInfo` instance for a file on the filesystem, in
preparation for adding it to a zip file.
If *arcname* is not specified, the name will be the same as *filename*, but
with any drive letter and leading path separators removed.
+ The *strict_timestamps* argument, when set to ``False``, allows to
+ zip files older than 1980-01-01 at the cost of setting the
+ timestamp to 1980-01-01.
+ Similar behavior occurs with files newer than 2107-12-31,
+ the timestamp is also set to the limit.
+
.. versionadded:: 3.6
.. versionchanged:: 3.6.2
The *filename* parameter accepts a :term:`path-like object`.
+ .. versionadded:: 3.8
+ The *strict_timestamps* keyword-only argument
+
Instances have the following methods and attributes:
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
self.assertRaises(ValueError, zipfp.write, TESTFN)
+ with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+ zipfp.write(TESTFN, strict_timestamps=False)
+ zinfo = zipfp.getinfo(TESTFN)
+ self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))
+
+ def test_add_file_after_2107(self):
+ # Set atime and mtime to 2108-12-30
+ os.utime(TESTFN, (4386268800, 4386268800))
+ with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+ self.assertRaises(struct.error, zipfp.write, TESTFN)
+
+ with zipfile.ZipFile(TESTFN2, "w") as zipfp:
+ zipfp.write(TESTFN, strict_timestamps=False)
+ zinfo = zipfp.getinfo(TESTFN)
+ self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
+
@requires_zlib
class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
extra = extra[ln+4:]
@classmethod
- def from_file(cls, filename, arcname=None):
+ def from_file(cls, filename, arcname=None, *, strict_timestamps=True):
"""Construct an appropriate ZipInfo for a file on the filesystem.
filename should be the path to a file or directory on the filesystem.
isdir = stat.S_ISDIR(st.st_mode)
mtime = time.localtime(st.st_mtime)
date_time = mtime[0:6]
+ if not strict_timestamps and date_time[0] < 1980:
+ date_time = (1980, 1, 1, 0, 0, 0)
+ elif not strict_timestamps and date_time[0] > 2107:
+ date_time = (2107, 12, 31, 23, 59, 59)
# Create ZipInfo instance to store file information
if arcname is None:
arcname = filename
" would require ZIP64 extensions")
def write(self, filename, arcname=None,
- compress_type=None, compresslevel=None):
+ compress_type=None, compresslevel=None, *,
+ strict_timestamps=True):
"""Put the bytes from filename into the archive under the name
arcname."""
if not self.fp:
"Can't write to ZIP archive while an open writing handle exists"
)
- zinfo = ZipInfo.from_file(filename, arcname)
+ zinfo = ZipInfo.from_file(filename, arcname,
+ strict_timestamps=strict_timestamps)
if zinfo.is_dir():
zinfo.compress_size = 0
--- /dev/null
+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.