Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions Doc/library/zipfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ ZipFile Objects


.. class:: ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True, \
compresslevel=None)
compresslevel=None, *, strict_timestamps=True)

Open a ZIP file, where *file* can be a path to a file (a string), a
file-like object or a :term:`path-like object`.
Expand Down Expand Up @@ -169,6 +169,12 @@ ZipFile Objects
When using :const:`ZIP_BZIP2` integers ``1`` through ``9`` are accepted
(see :class:`bz2 <bz2.BZ2File>` for more information).

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.

If the file is created with mode ``'w'``, ``'x'`` or ``'a'`` and then
:meth:`closed <close>` without adding any files to the archive, the appropriate
ZIP structures for an empty archive will be written to the file.
Expand Down Expand Up @@ -203,6 +209,9 @@ ZipFile Objects
.. versionchanged:: 3.7
Add the *compresslevel* parameter.

.. versionadded:: 3.8
The *strict_timestamps* keyword-only argument


.. method:: ZipFile.close()

Expand Down Expand Up @@ -368,7 +377,7 @@ ZipFile Objects


.. method:: ZipFile.write(filename, arcname=None, compress_type=None, \
compresslevel=None, *, strict_timestamps=True)
compresslevel=None)

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
Expand All @@ -377,11 +386,6 @@ ZipFile Objects
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::

Expand All @@ -405,9 +409,6 @@ ZipFile Objects
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)
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_zipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,8 @@ def test_add_file_before_1980(self):
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)
with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
zipfp.write(TESTFN)
zinfo = zipfp.getinfo(TESTFN)
self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))

Expand All @@ -564,8 +564,8 @@ def test_add_file_after_2107(self):
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)
with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
zipfp.write(TESTFN)
zinfo = zipfp.getinfo(TESTFN)
self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))

Expand Down
8 changes: 4 additions & 4 deletions Lib/zipfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ class ZipFile:
_windows_illegal_name_trans_table = None

def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
compresslevel=None):
compresslevel=None, *, strict_timestamps=True):
"""Open the ZIP file with mode read 'r', write 'w', exclusive create 'x',
or append 'a'."""
if mode not in ('r', 'w', 'x', 'a'):
Expand All @@ -1169,6 +1169,7 @@ def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
self.mode = mode
self.pwd = None
self._comment = b''
self._strict_timestamps = strict_timestamps

# Check if we were passed a file-like object
if isinstance(file, os.PathLike):
Expand Down Expand Up @@ -1677,8 +1678,7 @@ def _writecheck(self, zinfo):
" would require ZIP64 extensions")

def write(self, filename, arcname=None,
compress_type=None, compresslevel=None, *,
strict_timestamps=True):
compress_type=None, compresslevel=None):
"""Put the bytes from filename into the archive under the name
arcname."""
if not self.fp:
Expand All @@ -1690,7 +1690,7 @@ def write(self, filename, arcname=None,
)

zinfo = ZipInfo.from_file(filename, arcname,
strict_timestamps=strict_timestamps)
strict_timestamps=self._strict_timestamps)

if zinfo.is_dir():
zinfo.compress_size = 0
Expand Down