diff -r 6f3d3003acf3 Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py Wed Nov 28 12:34:27 2012 +0200 +++ b/Lib/test/test_zipfile.py Wed Nov 28 15:44:57 2012 +0200 @@ -109,6 +109,10 @@ with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] with zipfp.open(TESTFN) as zipopen1: + if isinstance(f, str): + zipfp.open("strfile").close() + else: + self.assertRaises(RuntimeError, zipfp.open, "strfile") while True: read_data = zipopen1.read(256) if not read_data: diff -r 6f3d3003acf3 Lib/zipfile.py --- a/Lib/zipfile.py Wed Nov 28 12:34:27 2012 +0200 +++ b/Lib/zipfile.py Wed Nov 28 15:44:57 2012 +0200 @@ -622,8 +622,9 @@ # Search for universal newlines or line chunks. PATTERN = re.compile(br'^(?P[^\r\n]+)|(?P\n|\r\n?)') - def __init__(self, fileobj, mode, zipinfo, decrypter=None, + def __init__(self, zipfile, fileobj, mode, zipinfo, decrypter=None, close_fileobj=False): + self._zipfile = zipfile self._fileobj = fileobj self._decrypter = decrypter self._close_fileobj = close_fileobj @@ -846,6 +847,7 @@ def close(self): try: + self._zipfile._used = False if self._close_fileobj: self._fileobj.close() finally: @@ -886,6 +888,7 @@ self.mode = key = mode.replace('b', '')[0] self.pwd = None self._comment = b'' + self._used = False # Check if we were passed a file-like object if isinstance(file, str): @@ -1098,11 +1101,15 @@ if not self.fp: raise RuntimeError( "Attempt to read ZIP archive that was already closed") + if self._used: + raise RuntimeError( + "Attempt to read ZIP archive that already used") # Only open a new file for instances where we were not # given a file object in the constructor if self._filePassed: zef_file = self.fp + self._used = True else: zef_file = io.open(self.filename, 'rb') @@ -1172,9 +1179,10 @@ if h[11] != check_byte: raise RuntimeError("Bad password for file", name) - return ZipExtFile(zef_file, mode, zinfo, zd, + return ZipExtFile(self, zef_file, mode, zinfo, zd, close_fileobj=not self._filePassed) except: + self._used = False if not self._filePassed: zef_file.close() raise @@ -1265,6 +1273,9 @@ if not self.fp: raise RuntimeError( "Attempt to write to ZIP archive that was already closed") + if self._used: + raise RuntimeError( + "Attempt to write to ZIP archive that already used") st = os.stat(filename) isdir = stat.S_ISDIR(st.st_mode) @@ -1287,6 +1298,7 @@ zinfo.file_size = st.st_size zinfo.flag_bits = 0x00 + self._used = True zinfo.header_offset = self.fp.tell() # Start of header bytes if zinfo.compress_type == ZIP_LZMA: # Compressed data includes an end-of-stream (EOS) marker @@ -1302,6 +1314,7 @@ self.filelist.append(zinfo) self.NameToInfo[zinfo.filename] = zinfo self.fp.write(zinfo.FileHeader()) + self._used = False return cmpr = _get_compressor(zinfo.compress_type) @@ -1338,6 +1351,7 @@ self.fp.seek(position, 0) self.filelist.append(zinfo) self.NameToInfo[zinfo.filename] = zinfo + self._used = False def writestr(self, zinfo_or_arcname, data, compress_type=None): """Write a file into the archive. The contents is 'data', which @@ -1358,6 +1372,9 @@ if not self.fp: raise RuntimeError( "Attempt to write to ZIP archive that was already closed") + if self._used: + raise RuntimeError( + "Attempt to write to ZIP archive that already used") zinfo.file_size = len(data) # Uncompressed size zinfo.header_offset = self.fp.tell() # Start of header data @@ -1385,6 +1402,7 @@ zinfo.file_size)) self.filelist.append(zinfo) self.NameToInfo[zinfo.filename] = zinfo + self._used = False def __del__(self): """Call the "close()" method in case the user forgot."""