Skip to content

Commit 341ee08

Browse files
committed
No more allow mode 'w'/'x'
- File is not truncated in mode 'w'/'x', which results non-shrinked file. - This cannot be simply resolved by adding truncation for mode 'w'/'x', which may be used on an unseekable file buffer and truncation is not allowed.
1 parent 307ee30 commit 341ee08

File tree

3 files changed

+24
-19
lines changed

3 files changed

+24
-19
lines changed

Doc/library/zipfile.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ ZipFile Objects
523523
Removes a member from the archive. *zinfo_or_arcname* is either the full
524524
path of the member, or a :class:`ZipInfo` instance.
525525

526-
The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
526+
The archive must be opened with mode ``'a'``.
527527

528528
Calling :meth:`remove` on a closed ZipFile will raise a :exc:`ValueError`.
529529

Lib/test/test_zipfile/test_core.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,23 @@ def test_verify(self):
15031503
zh.remove(file)
15041504
mock_fn.assert_not_called()
15051505

1506+
# mode 'w': error and do nothing
1507+
with zipfile.ZipFile(TESTFN, 'w', self.compression) as zh:
1508+
zh.writestr(file, data)
1509+
with mock.patch('zipfile.ZipFile._remove_members') as mock_fn:
1510+
with self.assertRaises(ValueError):
1511+
zh.remove(file)
1512+
mock_fn.assert_not_called()
1513+
1514+
# mode 'x': error and do nothing
1515+
os.remove(TESTFN)
1516+
with zipfile.ZipFile(TESTFN, 'x', self.compression) as zh:
1517+
zh.writestr(file, data)
1518+
with mock.patch('zipfile.ZipFile._remove_members') as mock_fn:
1519+
with self.assertRaises(ValueError):
1520+
zh.remove(file)
1521+
mock_fn.assert_not_called()
1522+
15061523
# mode 'a': the most general use case
15071524
with zipfile.ZipFile(TESTFN, 'w', self.compression) as zh:
15081525
zh.writestr(file, data)
@@ -1531,21 +1548,6 @@ def test_verify(self):
15311548
zh.remove(zinfo)
15321549
mock_fn.assert_not_called()
15331550

1534-
# mode 'w': like 'a'; allows removing a just written member
1535-
with zipfile.ZipFile(TESTFN, 'w', self.compression) as zh:
1536-
zh.writestr(file, data)
1537-
with mock.patch('zipfile.ZipFile._remove_members') as mock_fn:
1538-
zh.remove(file)
1539-
mock_fn.assert_called_once_with({zh.getinfo(file)})
1540-
1541-
# mode 'x': like 'w'
1542-
os.remove(TESTFN)
1543-
with zipfile.ZipFile(TESTFN, 'x', self.compression) as zh:
1544-
zh.writestr(file, data)
1545-
with mock.patch('zipfile.ZipFile._remove_members') as mock_fn:
1546-
zh.remove(file)
1547-
mock_fn.assert_called_once_with({zh.getinfo(file)})
1548-
15491551
def test_zip64(self):
15501552
"""Test if members use zip64."""
15511553
file = 'datafile.txt'

Lib/zipfile/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,10 +1867,13 @@ def extractall(self, path=None, members=None, pwd=None):
18671867
self._extract_member(zipinfo, path, pwd)
18681868

18691869
def remove(self, zinfo_or_arcname):
1870-
"""Remove a member from the archive."""
1870+
"""Remove a member from the archive.
18711871
1872-
if self.mode not in ('w', 'x', 'a'):
1873-
raise ValueError("remove() requires mode 'w', 'x', or 'a'")
1872+
The archive must be open with mode 'a', since mode 'w'/'x' may be used
1873+
on an unseekable file buffer, which disallows truncation."""
1874+
1875+
if self.mode != 'a':
1876+
raise ValueError("remove() requires mode 'a'")
18741877
if not self.fp:
18751878
raise ValueError(
18761879
"Attempt to write to ZIP archive that was already closed")

0 commit comments

Comments
 (0)