Skip to content

Commit 8d62df6

Browse files
danifusserhiy-storchaka
authored andcommitted
bpo-37523: Raise ValueError for I/O operations on a closed zipfile.ZipExtFile. (GH-14658)
Raises ValueError when calling the following on a closed zipfile.ZipExtFile: read, readable, seek, seekable, tell.
1 parent 1df65f7 commit 8d62df6

File tree

3 files changed

+25
-0
lines changed

3 files changed

+25
-0
lines changed

Lib/test/test_zipfile.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,20 @@ def test_write_default_name(self):
571571
with open(TESTFN, "rb") as f:
572572
self.assertEqual(zipfp.read(TESTFN), f.read())
573573

574+
def test_io_on_closed_zipextfile(self):
575+
fname = "somefile.txt"
576+
with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
577+
zipfp.writestr(fname, "bogus")
578+
579+
with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
580+
with zipfp.open(fname) as fid:
581+
fid.close()
582+
self.assertRaises(ValueError, fid.read)
583+
self.assertRaises(ValueError, fid.seek, 0)
584+
self.assertRaises(ValueError, fid.tell)
585+
self.assertRaises(ValueError, fid.readable)
586+
self.assertRaises(ValueError, fid.seekable)
587+
574588
def test_write_to_readonly(self):
575589
"""Check that trying to call write() on a readonly ZipFile object
576590
raises a ValueError."""

Lib/zipfile.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,12 +889,16 @@ def peek(self, n=1):
889889
return self._readbuffer[self._offset: self._offset + 512]
890890

891891
def readable(self):
892+
if self.closed:
893+
raise ValueError("I/O operation on closed file.")
892894
return True
893895

894896
def read(self, n=-1):
895897
"""Read and return up to n bytes.
896898
If the argument is omitted, None, or negative, data is read and returned until EOF is reached.
897899
"""
900+
if self.closed:
901+
raise ValueError("read from closed file.")
898902
if n is None or n < 0:
899903
buf = self._readbuffer[self._offset:]
900904
self._readbuffer = b''
@@ -1031,9 +1035,13 @@ def close(self):
10311035
super().close()
10321036

10331037
def seekable(self):
1038+
if self.closed:
1039+
raise ValueError("I/O operation on closed file.")
10341040
return self._seekable
10351041

10361042
def seek(self, offset, whence=0):
1043+
if self.closed:
1044+
raise ValueError("seek on closed file.")
10371045
if not self._seekable:
10381046
raise io.UnsupportedOperation("underlying stream is not seekable")
10391047
curr_pos = self.tell()
@@ -1082,6 +1090,8 @@ def seek(self, offset, whence=0):
10821090
return self.tell()
10831091

10841092
def tell(self):
1093+
if self.closed:
1094+
raise ValueError("tell on closed file.")
10851095
if not self._seekable:
10861096
raise io.UnsupportedOperation("underlying stream is not seekable")
10871097
filepos = self._orig_file_size - self._left - len(self._readbuffer) + self._offset
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Change :class:`zipfile.ZipExtFile` to raise ``ValueError`` when trying to access the underlying file object after it has been closed. This new behavior is consistent with how accessing closed files is handled in other parts of Python.

0 commit comments

Comments
 (0)