Merge pull request #6213 from radarhere/fp

This commit is contained in:
Hugo van Kemenade 2022-05-19 18:52:55 +03:00 committed by GitHub
commit 2c58c3ee11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 82 additions and 121 deletions

View File

@ -637,6 +637,15 @@ def test_apng_save_blend(tmp_path):
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
def test_seek_after_close():
im = Image.open("Tests/images/apng/delay.png")
im.seek(1)
im.close()
with pytest.raises(ValueError):
im.seek(0)
def test_constants_deprecation():
for enum, prefix in {
PngImagePlugin.Disposal: "APNG_DISPOSE_",

View File

@ -46,6 +46,15 @@ def test_closed_file():
im.close()
def test_seek_after_close():
im = Image.open(animated_test_file)
im.seek(1)
im.close()
with pytest.raises(ValueError):
im.seek(0)
def test_context_manager():
with warnings.catch_warnings():
with Image.open(static_test_file) as im:

View File

@ -46,6 +46,19 @@ def test_closed_file():
im.close()
def test_seek_after_close():
im = Image.open("Tests/images/iss634.gif")
im.load()
im.close()
with pytest.raises(ValueError):
im.is_animated
with pytest.raises(ValueError):
im.n_frames
with pytest.raises(ValueError):
im.seek(1)
def test_context_manager():
with warnings.catch_warnings():
with Image.open(TEST_GIF) as im:

View File

@ -48,6 +48,14 @@ def test_closed_file():
im.close()
def test_seek_after_close():
im = Image.open(test_files[0])
im.close()
with pytest.raises(ValueError):
im.seek(1)
def test_context_manager():
with warnings.catch_warnings():
with Image.open(test_files[0]) as im:

View File

@ -70,6 +70,15 @@ class TestFileTiff:
im.load()
im.close()
def test_seek_after_close(self):
im = Image.open("Tests/images/multipage.tiff")
im.close()
with pytest.raises(ValueError):
im.n_frames
with pytest.raises(ValueError):
im.seek(1)
def test_context_manager(self):
with warnings.catch_warnings():
with Image.open("Tests/images/multipage.tiff") as im:

View File

@ -57,7 +57,7 @@ class DcxImageFile(PcxImageFile):
break
self._offset.append(offset)
self.__fp = self.fp
self._fp = self.fp
self.frame = None
self.n_frames = len(self._offset)
self.is_animated = self.n_frames > 1
@ -67,22 +67,13 @@ class DcxImageFile(PcxImageFile):
if not self._seek_check(frame):
return
self.frame = frame
self.fp = self.__fp
self.fp = self._fp
self.fp.seek(self._offset[frame])
PcxImageFile._open(self)
def tell(self):
return self.frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
Image.register_open(DcxImageFile.format, DcxImageFile, _accept)

View File

@ -91,7 +91,7 @@ class FliImageFile(ImageFile.ImageFile):
# set things up to decode first frame
self.__frame = -1
self.__fp = self.fp
self._fp = self.fp
self.__rewind = self.fp.tell()
self.seek(0)
@ -125,7 +125,7 @@ class FliImageFile(ImageFile.ImageFile):
def _seek(self, frame):
if frame == 0:
self.__frame = -1
self.__fp.seek(self.__rewind)
self._fp.seek(self.__rewind)
self.__offset = 128
else:
# ensure that the previous frame was loaded
@ -136,7 +136,7 @@ class FliImageFile(ImageFile.ImageFile):
self.__frame = frame
# move to next frame
self.fp = self.__fp
self.fp = self._fp
self.fp.seek(self.__offset)
s = self.fp.read(4)
@ -153,15 +153,6 @@ class FliImageFile(ImageFile.ImageFile):
def tell(self):
return self.__frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
#
# registry

View File

@ -102,7 +102,7 @@ class GifImageFile(ImageFile.ImageFile):
p = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = p
self.__fp = self.fp # FIXME: hack
self._fp = self.fp # FIXME: hack
self.__rewind = self.fp.tell()
self._n_frames = None
self._is_animated = None
@ -161,7 +161,7 @@ class GifImageFile(ImageFile.ImageFile):
self.__offset = 0
self.dispose = None
self.__frame = -1
self.__fp.seek(self.__rewind)
self._fp.seek(self.__rewind)
self.disposal_method = 0
else:
# ensure that the previous frame was loaded
@ -171,7 +171,7 @@ class GifImageFile(ImageFile.ImageFile):
if frame != self.__frame + 1:
raise ValueError(f"cannot seek to frame {frame}")
self.fp = self.__fp
self.fp = self._fp
if self.__offset:
# backup to last frame
self.fp.seek(self.__offset)
@ -281,7 +281,7 @@ class GifImageFile(ImageFile.ImageFile):
s = None
if interlace is None:
# self.__fp = None
# self._fp = None
raise EOFError
if not update_image:
return
@ -443,15 +443,6 @@ class GifImageFile(ImageFile.ImageFile):
def tell(self):
return self.__frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
# --------------------------------------------------------------------
# Write GIF files

View File

@ -245,7 +245,7 @@ class ImImageFile(ImageFile.ImageFile):
self.__offset = offs = self.fp.tell()
self.__fp = self.fp # FIXME: hack
self._fp = self.fp # FIXME: hack
if self.rawmode[:2] == "F;":
@ -294,22 +294,13 @@ class ImImageFile(ImageFile.ImageFile):
size = ((self.size[0] * bits + 7) // 8) * self.size[1]
offs = self.__offset + frame * size
self.fp = self.__fp
self.fp = self._fp
self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))]
def tell(self):
return self.frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
#
# --------------------------------------------------------------------

View File

@ -549,8 +549,10 @@ class Image:
def __exit__(self, *args):
if hasattr(self, "fp") and getattr(self, "_exclusive_fp", False):
if hasattr(self, "_close__fp"):
self._close__fp()
if getattr(self, "_fp", False):
if self._fp != self.fp:
self._fp.close()
self._fp = DeferredError(ValueError("Operation on closed image"))
if self.fp:
self.fp.close()
self.fp = None
@ -568,8 +570,10 @@ class Image:
more information.
"""
try:
if hasattr(self, "_close__fp"):
self._close__fp()
if getattr(self, "_fp", False):
if self._fp != self.fp:
self._fp.close()
self._fp = DeferredError(ValueError("Operation on closed image"))
if self.fp:
self.fp.close()
self.fp = None

View File

@ -62,7 +62,6 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
if not self.images:
raise SyntaxError("not an MIC file; no image entries")
self.__fp = self.fp
self.frame = None
self._n_frames = len(self.images)
self.is_animated = self._n_frames > 1
@ -89,15 +88,6 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
def tell(self):
return self.frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
#
# --------------------------------------------------------------------

View File

@ -58,20 +58,20 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
assert self.n_frames == len(self.__mpoffsets)
del self.info["mpoffset"] # no longer needed
self.is_animated = self.n_frames > 1
self.__fp = self.fp # FIXME: hack
self.__fp.seek(self.__mpoffsets[0]) # get ready to read first frame
self._fp = self.fp # FIXME: hack
self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame
self.__frame = 0
self.offset = 0
# for now we can only handle reading and individual frame extraction
self.readonly = 1
def load_seek(self, pos):
self.__fp.seek(pos)
self._fp.seek(pos)
def seek(self, frame):
if not self._seek_check(frame):
return
self.fp = self.__fp
self.fp = self._fp
self.offset = self.__mpoffsets[frame]
self.fp.seek(self.offset + 2) # skip SOI marker
@ -97,15 +97,6 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
def tell(self):
return self.__frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
@staticmethod
def adopt(jpeg_instance, mpheader=None):
"""

View File

@ -710,7 +710,7 @@ class PngImageFile(ImageFile.ImageFile):
if not _accept(self.fp.read(8)):
raise SyntaxError("not a PNG file")
self.__fp = self.fp
self._fp = self.fp
self.__frame = 0
#
@ -767,7 +767,7 @@ class PngImageFile(ImageFile.ImageFile):
self._close_exclusive_fp_after_loading = False
self.png.save_rewind()
self.__rewind_idat = self.__prepare_idat
self.__rewind = self.__fp.tell()
self.__rewind = self._fp.tell()
if self.default_image:
# IDAT chunk contains default image and not first animation frame
self.n_frames += 1
@ -822,7 +822,7 @@ class PngImageFile(ImageFile.ImageFile):
def _seek(self, frame, rewind=False):
if frame == 0:
if rewind:
self.__fp.seek(self.__rewind)
self._fp.seek(self.__rewind)
self.png.rewind()
self.__prepare_idat = self.__rewind_idat
self.im = None
@ -830,7 +830,7 @@ class PngImageFile(ImageFile.ImageFile):
self.pyaccess = None
self.info = self.png.im_info
self.tile = self.png.im_tile
self.fp = self.__fp
self.fp = self._fp
self._prev_im = None
self.dispose = None
self.default_image = self.info.get("default_image", False)
@ -849,7 +849,7 @@ class PngImageFile(ImageFile.ImageFile):
self.im.paste(self.dispose, self.dispose_extent)
self._prev_im = self.im.copy()
self.fp = self.__fp
self.fp = self._fp
# advance to the next frame
if self.__prepare_idat:
@ -1027,15 +1027,6 @@ class PngImageFile(ImageFile.ImageFile):
else {}
)
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
# --------------------------------------------------------------------
# PNG writer

View File

@ -132,7 +132,7 @@ class PsdImageFile(ImageFile.ImageFile):
self.tile = _maketile(self.fp, mode, (0, 0) + self.size, channels)
# keep the file open
self.__fp = self.fp
self._fp = self.fp
self.frame = 1
self._min_frame = 1
@ -146,7 +146,7 @@ class PsdImageFile(ImageFile.ImageFile):
self.mode = mode
self.tile = tile
self.frame = layer
self.fp = self.__fp
self.fp = self._fp
return name, bbox
except IndexError as e:
raise EOFError("no such layer") from e
@ -155,15 +155,6 @@ class PsdImageFile(ImageFile.ImageFile):
# return layer number (0=image, 1..max=layers)
return self.frame
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
def _layerinfo(fp, ct_bytes):
# read layerinfo block

View File

@ -149,7 +149,7 @@ class SpiderImageFile(ImageFile.ImageFile):
self.mode = "F"
self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
self.__fp = self.fp # FIXME: hack
self._fp = self.fp # FIXME: hack
@property
def n_frames(self):
@ -172,7 +172,7 @@ class SpiderImageFile(ImageFile.ImageFile):
if not self._seek_check(frame):
return
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
self.fp = self.__fp
self.fp = self._fp
self.fp.seek(self.stkoffset)
self._open()
@ -191,15 +191,6 @@ class SpiderImageFile(ImageFile.ImageFile):
return ImageTk.PhotoImage(self.convert2byte(), palette=256)
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
# --------------------------------------------------------------------
# Image series

View File

@ -1073,7 +1073,7 @@ class TiffImageFile(ImageFile.ImageFile):
# setup frame pointers
self.__first = self.__next = self.tag_v2.next
self.__frame = -1
self.__fp = self.fp
self._fp = self.fp
self._frame_pos = []
self._n_frames = None
@ -1106,7 +1106,7 @@ class TiffImageFile(ImageFile.ImageFile):
self.im = Image.core.new(self.mode, self.size)
def _seek(self, frame):
self.fp = self.__fp
self.fp = self._fp
# reset buffered io handle in case fp
# was passed to libtiff, invalidating the buffer
@ -1515,15 +1515,6 @@ class TiffImageFile(ImageFile.ImageFile):
self._tile_orientation = self.tag_v2.get(0x0112)
def _close__fp(self):
try:
if self.__fp != self.fp:
self.__fp.close()
except AttributeError:
pass
finally:
self.__fp = None
#
# --------------------------------------------------------------------