Merge pull request #8702 from radarhere/imagefile_fp

This commit is contained in:
Hugo van Kemenade 2025-01-20 19:29:05 +02:00 committed by GitHub
commit 58dd4a7dac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 19 deletions

View File

@ -603,24 +603,16 @@ class Image:
def __enter__(self): def __enter__(self):
return self return self
def _close_fp(self):
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()
def __exit__(self, *args): def __exit__(self, *args):
if hasattr(self, "fp"): from . import ImageFile
if isinstance(self, ImageFile.ImageFile):
if getattr(self, "_exclusive_fp", False): if getattr(self, "_exclusive_fp", False):
self._close_fp() self._close_fp()
self.fp = None self.fp = None
def close(self) -> None: def close(self) -> None:
""" """
Closes the file pointer, if possible.
This operation will destroy the image core and release its memory. This operation will destroy the image core and release its memory.
The image data will be unusable afterward. The image data will be unusable afterward.
@ -629,13 +621,6 @@ class Image:
:py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for
more information. more information.
""" """
if hasattr(self, "fp"):
try:
self._close_fp()
self.fp = None
except Exception as msg:
logger.debug("Error closing: %s", msg)
if getattr(self, "map", None): if getattr(self, "map", None):
self.map: mmap.mmap | None = None self.map: mmap.mmap | None = None

View File

@ -31,6 +31,7 @@ from __future__ import annotations
import abc import abc
import io import io
import itertools import itertools
import logging
import os import os
import struct import struct
import sys import sys
@ -38,11 +39,13 @@ from typing import IO, TYPE_CHECKING, Any, NamedTuple, cast
from . import ExifTags, Image from . import ExifTags, Image
from ._deprecate import deprecate from ._deprecate import deprecate
from ._util import is_path from ._util import DeferredError, is_path
if TYPE_CHECKING: if TYPE_CHECKING:
from ._typing import StrOrBytesPath from ._typing import StrOrBytesPath
logger = logging.getLogger(__name__)
MAXBLOCK = 65536 MAXBLOCK = 65536
SAFEBLOCK = 1024 * 1024 SAFEBLOCK = 1024 * 1024
@ -163,6 +166,34 @@ class ImageFile(Image.Image):
def _open(self) -> None: def _open(self) -> None:
pass pass
def _close_fp(self):
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()
def close(self) -> None:
"""
Closes the file pointer, if possible.
This operation will destroy the image core and release its memory.
The image data will be unusable afterward.
This function is required to close images that have multiple frames or
have not had their file read and closed by the
:py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for
more information.
"""
try:
self._close_fp()
self.fp = None
except Exception as msg:
logger.debug("Error closing: %s", msg)
super().close()
def get_child_images(self) -> list[ImageFile]: def get_child_images(self) -> list[ImageFile]:
child_images = [] child_images = []
exif = self.getexif() exif = self.getexif()