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
4 changes: 3 additions & 1 deletion Doc/library/zipfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,9 @@ ZipFile objects
strict_descriptor=True[, chunk_size])

Rewrites the archive to remove unreferenced local file entries, shrinking
its file size. The archive must be opened with mode ``'a'``.
its file size. The archive must be opened with mode ``'a'``, and any file
object returned by :meth:`ZipFile.open` must be closed first, since
repacking moves the member data such objects refer to.

If *removed* is provided, it must be a sequence of :class:`ZipInfo` objects
representing the recently removed members, and only their corresponding
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_zipfile/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,18 @@ def test_repack_writing(self, m_repack):
zh.repack()
m_repack.assert_not_called()

@mock.patch.object(zipfile, '_ZipRepacker')
def test_repack_reading(self, m_repack):
self._prepare_zip_from_test_files(TESTFN, self.test_files)
with zipfile.ZipFile(TESTFN, 'a') as zh:
with zh.open(self.test_files[0][0]):
with self.assertRaises(ValueError):
zh.repack()
m_repack.assert_not_called()
# Allowed once the reading handle is closed.
zh.repack()
m_repack.assert_called_once()

@mock.patch.object(zipfile, '_ZipRepacker')
def test_repack_mode_r(self, m_repack):
self._prepare_zip_from_test_files(TESTFN, self.test_files)
Expand Down
15 changes: 8 additions & 7 deletions Lib/zipfile/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2397,15 +2397,16 @@ def repack(self, removed=None, *, strict_descriptor=True,
truncation."""
if self.mode != 'a':
raise ValueError("repack() requires mode 'a'")
if not self.fp:
raise ValueError(
"Attempt to write to ZIP archive that was already closed")
if self._writing:
raise ValueError(
"Can't write to ZIP archive while an open writing handle exists"
)

with self._lock:
if not self.fp:
raise ValueError(
"Attempt to write to ZIP archive that was already closed")
if self._writing or self._fileRefCnt > 1:
raise ValueError(
"Can't repack ZIP archive while an open handle exists"
)

self._writing = True
try:
repacker = _ZipRepacker(
Expand Down
Loading