From 779a0dd6b913f09b66725568e264389258093e35 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 28 Jan 2025 12:19:48 +0200 Subject: [PATCH 1/3] Defer importing tempfile --- src/PIL/EpsImagePlugin.py | 3 ++- src/PIL/Image.py | 3 ++- src/PIL/ImageGrab.py | 3 ++- src/PIL/JpegImagePlugin.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 363ba19e130..5c4a8009db8 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -26,7 +26,6 @@ import re import subprocess import sys -import tempfile from typing import IO from . import Image, ImageFile @@ -92,6 +91,8 @@ def Ghostscript( res_x = 72.0 * width / (bbox[2] - bbox[0]) res_y = 72.0 * height / (bbox[3] - bbox[1]) + import tempfile + out_fd, outfile = tempfile.mkstemp() os.close(out_fd) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index ebbd8fd35f8..abef275bd70 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -36,7 +36,6 @@ import re import struct import sys -import tempfile import warnings from collections.abc import MutableMapping from enum import IntEnum @@ -738,6 +737,8 @@ def _dump( if not filename.endswith(suffix): filename += suffix else: + import tempfile + f, filename = tempfile.mkstemp(suffix) os.close(f) diff --git a/src/PIL/ImageGrab.py b/src/PIL/ImageGrab.py index 52cbfea406d..03091e756e5 100644 --- a/src/PIL/ImageGrab.py +++ b/src/PIL/ImageGrab.py @@ -21,7 +21,6 @@ import shutil import subprocess import sys -import tempfile from . import Image @@ -40,6 +39,8 @@ def grab( scale_down: bool = False, ) -> Image.Image: im: Image.Image + import tempfile + if xdisplay is None: if sys.platform == "darwin": fh, filepath = tempfile.mkstemp(".png") diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 46320eb3b5b..54327619291 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -40,7 +40,6 @@ import struct import subprocess import sys -import tempfile import warnings from . import Image, ImageFile @@ -467,6 +466,7 @@ def draft( def load_djpeg(self) -> None: # ALTERNATIVE: handle JPEGs via the IJG command line utilities + import tempfile f, path = tempfile.mkstemp() os.close(f) From 02e98c60553c97e2916ac669677558db7760aee4 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 29 Jun 2026 17:48:23 +0300 Subject: [PATCH 2/3] Use lazy imports on Python 3.15 to improve startup speed --- src/PIL/AvifImagePlugin.py | 2 ++ src/PIL/BdfFontFile.py | 2 ++ src/PIL/BlpImagePlugin.py | 2 ++ src/PIL/BmpImagePlugin.py | 2 ++ src/PIL/BufrStubImagePlugin.py | 2 ++ src/PIL/ContainerIO.py | 2 ++ src/PIL/CurImagePlugin.py | 2 ++ src/PIL/DcxImagePlugin.py | 2 ++ src/PIL/DdsImagePlugin.py | 2 ++ src/PIL/EpsImagePlugin.py | 2 ++ src/PIL/FitsImagePlugin.py | 2 ++ src/PIL/FliImagePlugin.py | 2 ++ src/PIL/FontFile.py | 2 ++ src/PIL/FpxImagePlugin.py | 2 ++ src/PIL/FtexImagePlugin.py | 2 ++ src/PIL/GbrImagePlugin.py | 2 ++ src/PIL/GdImageFile.py | 2 ++ src/PIL/GifImagePlugin.py | 10 ++++++++++ src/PIL/GimpGradientFile.py | 2 ++ src/PIL/GimpPaletteFile.py | 2 ++ src/PIL/GribStubImagePlugin.py | 2 ++ src/PIL/Hdf5StubImagePlugin.py | 2 ++ src/PIL/IcnsImagePlugin.py | 2 ++ src/PIL/IcoImagePlugin.py | 2 ++ src/PIL/ImImagePlugin.py | 2 ++ src/PIL/Image.py | 11 +++++++++++ src/PIL/ImageCms.py | 2 ++ src/PIL/ImageColor.py | 2 ++ src/PIL/ImageDraw.py | 2 ++ src/PIL/ImageDraw2.py | 2 ++ src/PIL/ImageFile.py | 2 ++ src/PIL/ImageFilter.py | 2 ++ src/PIL/ImageFont.py | 2 ++ src/PIL/ImageGrab.py | 2 ++ src/PIL/ImageMorph.py | 2 ++ src/PIL/ImageOps.py | 2 ++ src/PIL/ImagePalette.py | 2 ++ src/PIL/ImageQt.py | 2 ++ src/PIL/ImageShow.py | 2 ++ src/PIL/ImageStat.py | 2 ++ src/PIL/ImageText.py | 2 ++ src/PIL/ImageTk.py | 2 ++ src/PIL/ImageTransform.py | 2 ++ src/PIL/IptcImagePlugin.py | 2 ++ src/PIL/Jpeg2KImagePlugin.py | 2 ++ src/PIL/JpegImagePlugin.py | 13 +++++++++++++ src/PIL/McIdasImagePlugin.py | 2 ++ src/PIL/MpegImagePlugin.py | 2 ++ src/PIL/MpoImagePlugin.py | 2 ++ src/PIL/MspImagePlugin.py | 2 ++ src/PIL/PSDraw.py | 2 ++ src/PIL/PaletteFile.py | 2 ++ src/PIL/PalmImagePlugin.py | 2 ++ src/PIL/PcfFontFile.py | 2 ++ src/PIL/PcxImagePlugin.py | 2 ++ src/PIL/PdfImagePlugin.py | 2 ++ src/PIL/PdfParser.py | 2 ++ src/PIL/PixarImagePlugin.py | 2 ++ src/PIL/PngImagePlugin.py | 11 +++++++++++ src/PIL/PpmImagePlugin.py | 2 ++ src/PIL/PsdImagePlugin.py | 2 ++ src/PIL/QoiImagePlugin.py | 2 ++ src/PIL/SgiImagePlugin.py | 2 ++ src/PIL/SpiderImagePlugin.py | 2 ++ src/PIL/SunImagePlugin.py | 2 ++ src/PIL/TarIO.py | 2 ++ src/PIL/TgaImagePlugin.py | 2 ++ src/PIL/TiffImagePlugin.py | 11 +++++++++++ src/PIL/WalImageFile.py | 2 ++ src/PIL/WebPImagePlugin.py | 2 ++ src/PIL/WmfImagePlugin.py | 2 ++ src/PIL/XbmImagePlugin.py | 2 ++ src/PIL/XpmImagePlugin.py | 2 ++ src/PIL/_binary.py | 2 ++ src/PIL/_deprecate.py | 2 ++ src/PIL/_typing.py | 2 ++ src/PIL/_util.py | 2 ++ src/PIL/features.py | 2 ++ 78 files changed, 202 insertions(+) diff --git a/src/PIL/AvifImagePlugin.py b/src/PIL/AvifImagePlugin.py index 6e7d0f738b3..d5d681312e1 100644 --- a/src/PIL/AvifImagePlugin.py +++ b/src/PIL/AvifImagePlugin.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"io", "os", "typing"} + import os from io import BytesIO from typing import IO diff --git a/src/PIL/BdfFontFile.py b/src/PIL/BdfFontFile.py index 098779bfd6e..32aa411a898 100644 --- a/src/PIL/BdfFontFile.py +++ b/src/PIL/BdfFontFile.py @@ -23,6 +23,8 @@ from __future__ import annotations +__lazy_modules__ = {"typing"} + from typing import BinaryIO from . import FontFile, Image diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index b4aaebd7b6c..6d1235b8376 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -31,6 +31,8 @@ from __future__ import annotations +__lazy_modules__ = {"io", "os", "struct", "typing"} + import abc import os import struct diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 13950ee7a4a..5b0887aa22f 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -24,6 +24,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "os", "typing"} + import os from typing import IO, Any diff --git a/src/PIL/BufrStubImagePlugin.py b/src/PIL/BufrStubImagePlugin.py index d82c4c746c3..db6f89a5798 100644 --- a/src/PIL/BufrStubImagePlugin.py +++ b/src/PIL/BufrStubImagePlugin.py @@ -10,6 +10,8 @@ # from __future__ import annotations +__lazy_modules__ = {"os", "typing"} + import os from typing import IO diff --git a/src/PIL/ContainerIO.py b/src/PIL/ContainerIO.py index ec9e66c714f..20c603fe59e 100644 --- a/src/PIL/ContainerIO.py +++ b/src/PIL/ContainerIO.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"collections.abc", "io"} + import io from collections.abc import Iterable from typing import IO, AnyStr, NoReturn diff --git a/src/PIL/CurImagePlugin.py b/src/PIL/CurImagePlugin.py index b20425040f4..f74e063d217 100644 --- a/src/PIL/CurImagePlugin.py +++ b/src/PIL/CurImagePlugin.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + from . import BmpImagePlugin, Image, ImageOps from ._binary import i16le as i16 from ._binary import i32le as i32 diff --git a/src/PIL/DcxImagePlugin.py b/src/PIL/DcxImagePlugin.py index d3f456ddcc4..0864680d128 100644 --- a/src/PIL/DcxImagePlugin.py +++ b/src/PIL/DcxImagePlugin.py @@ -22,6 +22,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._util"} + from . import Image from ._binary import i32le as i32 from ._util import DeferredError diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index 2ca9f3abb27..cd644d62975 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -12,6 +12,8 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "struct", "typing"} + import struct import sys from enum import IntEnum, IntFlag diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 5c4a8009db8..ea033c66f73 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -21,6 +21,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io", "os", "subprocess", "tempfile", "typing"} + import io import os import re diff --git a/src/PIL/FitsImagePlugin.py b/src/PIL/FitsImagePlugin.py index dca61c2e21b..b2af17fefe1 100644 --- a/src/PIL/FitsImagePlugin.py +++ b/src/PIL/FitsImagePlugin.py @@ -10,6 +10,8 @@ # from __future__ import annotations +__lazy_modules__ = {"gzip", "math"} + import gzip import math diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index da1e8e95cf3..38b282bdf54 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._util", "os"} + import os from . import Image, ImageFile, ImagePalette diff --git a/src/PIL/FontFile.py b/src/PIL/FontFile.py index c3be4ae3ddd..860a5ffcd73 100644 --- a/src/PIL/FontFile.py +++ b/src/PIL/FontFile.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"os", "typing"} + import os from typing import BinaryIO diff --git a/src/PIL/FpxImagePlugin.py b/src/PIL/FpxImagePlugin.py index f7eafe4d5e7..6da46c17bee 100644 --- a/src/PIL/FpxImagePlugin.py +++ b/src/PIL/FpxImagePlugin.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + import olefile from . import Image, ImageFile diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index e4d836cbdb2..09a728f6803 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -53,6 +53,8 @@ from __future__ import annotations +__lazy_modules__ = {"io", "struct"} + import struct from enum import IntEnum from io import BytesIO diff --git a/src/PIL/GbrImagePlugin.py b/src/PIL/GbrImagePlugin.py index ec666c81c2c..a92f108224e 100644 --- a/src/PIL/GbrImagePlugin.py +++ b/src/PIL/GbrImagePlugin.py @@ -25,6 +25,8 @@ # the color depth field. This is currently unsupported by Pillow. from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + from . import Image, ImageFile from ._binary import i32be as i32 diff --git a/src/PIL/GdImageFile.py b/src/PIL/GdImageFile.py index 4ff96f1fa04..44664ba407a 100644 --- a/src/PIL/GdImageFile.py +++ b/src/PIL/GdImageFile.py @@ -28,6 +28,8 @@ class is not registered for use with :py:func:`PIL.Image.open()`. To open a from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._typing", "typing"} + from typing import IO from . import Image, ImageFile, ImagePalette, UnidentifiedImageError diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index b8db5d83284..dcd24c037d8 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -25,6 +25,16 @@ # from __future__ import annotations +__lazy_modules__ = { + "PIL._binary", + "PIL._util", + "functools", + "itertools", + "math", + "os", + "subprocess", +} + import itertools import math import os diff --git a/src/PIL/GimpGradientFile.py b/src/PIL/GimpGradientFile.py index fb958721882..5b2cc94de23 100644 --- a/src/PIL/GimpGradientFile.py +++ b/src/PIL/GimpGradientFile.py @@ -21,6 +21,8 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "math"} + from math import log, pi, sin, sqrt from ._binary import o8 diff --git a/src/PIL/GimpPaletteFile.py b/src/PIL/GimpPaletteFile.py index 016257d3dd2..9d8d8c1678b 100644 --- a/src/PIL/GimpPaletteFile.py +++ b/src/PIL/GimpPaletteFile.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io", "re"} + import re from io import BytesIO diff --git a/src/PIL/GribStubImagePlugin.py b/src/PIL/GribStubImagePlugin.py index 3784ef2f134..f66de0430da 100644 --- a/src/PIL/GribStubImagePlugin.py +++ b/src/PIL/GribStubImagePlugin.py @@ -10,6 +10,8 @@ # from __future__ import annotations +__lazy_modules__ = {"os", "typing"} + import os from typing import IO diff --git a/src/PIL/Hdf5StubImagePlugin.py b/src/PIL/Hdf5StubImagePlugin.py index 1a56660f7bd..dab7d3e90e0 100644 --- a/src/PIL/Hdf5StubImagePlugin.py +++ b/src/PIL/Hdf5StubImagePlugin.py @@ -10,6 +10,8 @@ # from __future__ import annotations +__lazy_modules__ = {"os", "typing"} + import os from typing import IO diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py index cb7a74c2e3b..651c664e7bb 100644 --- a/src/PIL/IcnsImagePlugin.py +++ b/src/PIL/IcnsImagePlugin.py @@ -18,6 +18,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io", "os", "struct", "typing"} + import io import os import struct diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index 8dd57ff858a..5b9a4a6b3d3 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -36,6 +36,8 @@ # * https://msdn.microsoft.com/en-us/library/ms997538.aspx from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io", "math", "warnings"} + import warnings from io import BytesIO from math import ceil, log diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index ef54f16e97e..4516469fd84 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -26,6 +26,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._util", "os", "typing"} + import os import re from typing import IO, Any diff --git a/src/PIL/Image.py b/src/PIL/Image.py index abef275bd70..21aee50fc93 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -26,6 +26,17 @@ from __future__ import annotations +__lazy_modules__ = { + "PIL._binary", + "PIL._deprecate", + "PIL._util", + "io", + "math", + "os", + "re", + "struct", +} + import abc import atexit import builtins diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 388a9296f8b..baeb7f09f6f 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -19,6 +19,8 @@ # below for the original description. from __future__ import annotations +__lazy_modules__ = {"PIL._deprecate"} + import operator import sys from enum import IntEnum, IntFlag diff --git a/src/PIL/ImageColor.py b/src/PIL/ImageColor.py index 9a15a8eb759..6eb498218ac 100644 --- a/src/PIL/ImageColor.py +++ b/src/PIL/ImageColor.py @@ -18,6 +18,8 @@ # from __future__ import annotations +__lazy_modules__ = {"re"} + import re from functools import lru_cache diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 561c44729cf..d8bfd83afc4 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -31,6 +31,8 @@ # from __future__ import annotations +__lazy_modules__ = {"collections.abc", "math", "struct", "typing"} + import math import struct from collections.abc import Sequence diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index 2c9e39b2c41..48958facea3 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -25,6 +25,8 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._typing", "typing"} + from typing import Any, AnyStr, BinaryIO from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 2d69225b5c0..c62f015de4c 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -28,6 +28,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._util", "io", "itertools", "os", "struct"} + import abc import io import itertools diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 823365af076..a007300701b 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"collections.abc", "functools", "typing"} + import abc import functools from collections.abc import Sequence diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 65edf5659fa..3b1e317761a 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -27,6 +27,8 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._typing", "base64", "io", "os", "types", "warnings"} + import abc import base64 import os diff --git a/src/PIL/ImageGrab.py b/src/PIL/ImageGrab.py index 03091e756e5..e75674c8d8e 100644 --- a/src/PIL/ImageGrab.py +++ b/src/PIL/ImageGrab.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io", "os", "shutil", "subprocess", "tempfile"} + import io import os import shutil diff --git a/src/PIL/ImageMorph.py b/src/PIL/ImageMorph.py index 9fcd8d78db4..e000ea4421c 100644 --- a/src/PIL/ImageMorph.py +++ b/src/PIL/ImageMorph.py @@ -6,6 +6,8 @@ # Copyright (c) 2014 Dov Grobgeld from __future__ import annotations +__lazy_modules__ = {"re"} + import re from . import Image, _imagingmorph diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index f0ae142b9ba..40fd4dd3e13 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -18,6 +18,8 @@ # from __future__ import annotations +__lazy_modules__ = {"collections.abc", "functools", "operator", "re"} + import functools import operator import re diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index 2abbd46eaf1..26bb358fcf2 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"array", "collections.abc", "typing"} + import array from collections.abc import Sequence from typing import IO diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index af4d0742d6b..05534a8c753 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._util", "io"} + import sys from io import BytesIO diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index dd8aa0d36c2..51cbe28de69 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -13,6 +13,8 @@ # from __future__ import annotations +__lazy_modules__ = {"os", "shlex", "subprocess", "typing"} + import abc import os import shutil diff --git a/src/PIL/ImageStat.py b/src/PIL/ImageStat.py index 3a1044ba449..0a1c5dc4ddf 100644 --- a/src/PIL/ImageStat.py +++ b/src/PIL/ImageStat.py @@ -22,6 +22,8 @@ # from __future__ import annotations +__lazy_modules__ = {"functools", "math"} + import math from functools import cached_property diff --git a/src/PIL/ImageText.py b/src/PIL/ImageText.py index 96601813ce0..1e47042db9b 100644 --- a/src/PIL/ImageText.py +++ b/src/PIL/ImageText.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._typing", "math", "re"} + import math import re from typing import AnyStr, Generic, NamedTuple diff --git a/src/PIL/ImageTk.py b/src/PIL/ImageTk.py index 3a4cb81e9ef..fc6866b8403 100644 --- a/src/PIL/ImageTk.py +++ b/src/PIL/ImageTk.py @@ -26,6 +26,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io", "tkinter", "typing"} + import tkinter from io import BytesIO from typing import Any diff --git a/src/PIL/ImageTransform.py b/src/PIL/ImageTransform.py index fb144ff38a1..e1da31b8554 100644 --- a/src/PIL/ImageTransform.py +++ b/src/PIL/ImageTransform.py @@ -14,6 +14,8 @@ # from __future__ import annotations +__lazy_modules__ = {"collections.abc", "typing"} + from collections.abc import Sequence from typing import Any diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index 9c8be8b4e36..d1915a1f6ed 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io", "typing"} + from io import BytesIO from typing import cast diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index ca982f06aa5..25baefaac6b 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io", "os", "struct", "typing"} + import io import os import struct diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 54327619291..015e3acff85 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -33,6 +33,19 @@ # from __future__ import annotations +__lazy_modules__ = { + "PIL.JpegPresets", + "PIL._binary", + "array", + "io", + "math", + "os", + "struct", + "subprocess", + "tempfile", + "warnings", +} + import array import io import math diff --git a/src/PIL/McIdasImagePlugin.py b/src/PIL/McIdasImagePlugin.py index 9a47933b69c..e0f3b404b7c 100644 --- a/src/PIL/McIdasImagePlugin.py +++ b/src/PIL/McIdasImagePlugin.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"struct"} + import struct from . import Image, ImageFile diff --git a/src/PIL/MpegImagePlugin.py b/src/PIL/MpegImagePlugin.py index 47ebe9d62c4..8d32a3ee916 100644 --- a/src/PIL/MpegImagePlugin.py +++ b/src/PIL/MpegImagePlugin.py @@ -14,6 +14,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._typing"} + from . import Image, ImageFile from ._binary import i8 from ._typing import SupportsRead diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index bee0a56f9ac..810dff0bbd4 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -19,6 +19,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._util", "os", "struct", "typing"} + import os import struct from typing import IO, Any, cast diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 9df5cfd9345..0caab68b633 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -24,6 +24,8 @@ # See also: https://www.fileformat.info/format/mspaint/egff.htm from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io", "struct", "typing"} + import io import struct from typing import IO diff --git a/src/PIL/PSDraw.py b/src/PIL/PSDraw.py index e6b74a91888..603112444d0 100644 --- a/src/PIL/PSDraw.py +++ b/src/PIL/PSDraw.py @@ -16,6 +16,8 @@ # from __future__ import annotations +__lazy_modules__ = {"typing"} + import sys from typing import IO diff --git a/src/PIL/PaletteFile.py b/src/PIL/PaletteFile.py index 2a26e5d4e22..40496569a9b 100644 --- a/src/PIL/PaletteFile.py +++ b/src/PIL/PaletteFile.py @@ -14,6 +14,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "typing"} + from typing import IO from ._binary import o8 diff --git a/src/PIL/PalmImagePlugin.py b/src/PIL/PalmImagePlugin.py index 232adf3d3bb..68bead992c3 100644 --- a/src/PIL/PalmImagePlugin.py +++ b/src/PIL/PalmImagePlugin.py @@ -8,6 +8,8 @@ ## from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "typing"} + from typing import IO from . import Image, ImageFile diff --git a/src/PIL/PcfFontFile.py b/src/PIL/PcfFontFile.py index 985444106a1..b4015f95aaf 100644 --- a/src/PIL/PcfFontFile.py +++ b/src/PIL/PcfFontFile.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io"} + import io from . import FontFile, Image diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 3e34e3c63ba..299871b98e9 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -26,6 +26,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "io", "typing"} + import io import logging from typing import IO diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index cb26786b0d9..e4f6fc08ead 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -21,6 +21,8 @@ ## from __future__ import annotations +__lazy_modules__ = {"io", "math", "os", "time", "typing"} + import io import math import os diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index e4e094e715a..2e8e1f90f12 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"calendar", "codecs", "mmap", "os", "re", "time", "zlib"} + import calendar import codecs import collections diff --git a/src/PIL/PixarImagePlugin.py b/src/PIL/PixarImagePlugin.py index d2b6d0a97e4..d2cff36aed3 100644 --- a/src/PIL/PixarImagePlugin.py +++ b/src/PIL/PixarImagePlugin.py @@ -20,6 +20,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + from . import Image, ImageFile from ._binary import i16le as i16 diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 058fb831c9e..386617383ab 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -32,6 +32,17 @@ # from __future__ import annotations +__lazy_modules__ = { + "PIL._binary", + "PIL._deprecate", + "PIL._util", + "fractions", + "itertools", + "struct", + "warnings", + "zlib", +} + import itertools import logging import re diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index ca6093385be..fde641db313 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "math", "typing"} + import math from typing import IO diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 201909abde6..ff1bd3248c8 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._util", "functools", "io", "typing"} + import io from functools import cached_property from typing import IO diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index e7a6cee16db..ce777d829d7 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -7,6 +7,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "os", "typing"} + import os from typing import IO diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index 76688ba5724..259dd6973f1 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -22,6 +22,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "os", "struct", "typing"} + import os import struct from typing import IO diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index b8bf2282d74..4bce7ffa82f 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -34,6 +34,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._util", "os", "struct", "typing"} + import os import struct import sys diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index 8912379ea3e..8a0dcf1a148 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + from . import Image, ImageFile, ImagePalette from ._binary import i32be as i32 diff --git a/src/PIL/TarIO.py b/src/PIL/TarIO.py index 86490a496f3..68daf6616a0 100644 --- a/src/PIL/TarIO.py +++ b/src/PIL/TarIO.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"io"} + import io from . import ContainerIO diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 8fd63b1df5b..88448f3c429 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -17,6 +17,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "os", "typing", "warnings"} + import os import warnings from typing import IO diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 472dfcf5802..019faecd9ac 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -40,6 +40,17 @@ # from __future__ import annotations +__lazy_modules__ = { + "PIL._binary", + "PIL._util", + "fractions", + "itertools", + "math", + "os", + "struct", + "warnings", +} + import io import itertools import logging diff --git a/src/PIL/WalImageFile.py b/src/PIL/WalImageFile.py index 07bbf747155..a298da4be20 100644 --- a/src/PIL/WalImageFile.py +++ b/src/PIL/WalImageFile.py @@ -25,6 +25,8 @@ from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "PIL._typing", "typing"} + from typing import IO from . import Image, ImageFile diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 63a48169182..fe320a94a78 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"io"} + from io import BytesIO from . import Image, ImageFile diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py index f5e244782fc..948d225ba83 100644 --- a/src/PIL/WmfImagePlugin.py +++ b/src/PIL/WmfImagePlugin.py @@ -20,6 +20,8 @@ # http://wvware.sourceforge.net/caolan/ora-wmf.html from __future__ import annotations +__lazy_modules__ = {"PIL._binary", "typing"} + from typing import IO from . import Image, ImageFile diff --git a/src/PIL/XbmImagePlugin.py b/src/PIL/XbmImagePlugin.py index 1e57aa162ea..10d00d63da0 100644 --- a/src/PIL/XbmImagePlugin.py +++ b/src/PIL/XbmImagePlugin.py @@ -20,6 +20,8 @@ # from __future__ import annotations +__lazy_modules__ = {"typing"} + import re from typing import IO diff --git a/src/PIL/XpmImagePlugin.py b/src/PIL/XpmImagePlugin.py index 80192f55e53..20113ef9efc 100644 --- a/src/PIL/XpmImagePlugin.py +++ b/src/PIL/XpmImagePlugin.py @@ -15,6 +15,8 @@ # from __future__ import annotations +__lazy_modules__ = {"PIL._binary"} + import re from . import Image, ImageFile, ImagePalette diff --git a/src/PIL/_binary.py b/src/PIL/_binary.py index d3236c17abb..23d82d79632 100644 --- a/src/PIL/_binary.py +++ b/src/PIL/_binary.py @@ -16,6 +16,8 @@ from __future__ import annotations +__lazy_modules__ = {"struct"} + from struct import pack, unpack_from diff --git a/src/PIL/_deprecate.py b/src/PIL/_deprecate.py index 711c62ab2b1..1f7f59b75ce 100644 --- a/src/PIL/_deprecate.py +++ b/src/PIL/_deprecate.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"warnings"} + import warnings from . import __version__ diff --git a/src/PIL/_typing.py b/src/PIL/_typing.py index a941f89806f..0a0c6c60542 100644 --- a/src/PIL/_typing.py +++ b/src/PIL/_typing.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"types"} + import os import sys from collections.abc import Sequence diff --git a/src/PIL/_util.py b/src/PIL/_util.py index b1fa6a0f39e..a9670af154f 100644 --- a/src/PIL/_util.py +++ b/src/PIL/_util.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"os"} + import os TYPE_CHECKING = False diff --git a/src/PIL/features.py b/src/PIL/features.py index ff32c251045..5073dc0d865 100644 --- a/src/PIL/features.py +++ b/src/PIL/features.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"collections", "os", "typing", "warnings"} + import collections import os import sys From 74eba11bb4e644c55fcfa592f8efb03315199ec1 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:44:15 +0300 Subject: [PATCH 3/3] Defer importing defusedxml --- src/PIL/Image.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 21aee50fc93..206feecbd63 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -67,16 +67,9 @@ from ._deprecate import deprecate from ._util import DeferredError, is_path -ElementTree: ModuleType | None -try: - from defusedxml import ElementTree -except ImportError: - ElementTree = None - TYPE_CHECKING = False if TYPE_CHECKING: from collections.abc import Callable, Iterator, Sequence - from types import ModuleType from typing import Any, Literal logger = logging.getLogger(__name__) @@ -1596,6 +1589,11 @@ def getxmp(self) -> dict[str, Any]: :returns: XMP tags in a dictionary. """ + try: + from defusedxml import ElementTree + except ImportError: + warnings.warn("XMP data cannot be read without defusedxml dependency") + return {} def get_name(tag: str) -> str: return re.sub("^{[^}]+}", "", tag) @@ -1620,9 +1618,6 @@ def get_value(element: Element) -> str | dict[str, Any] | None: return element.text return value - if ElementTree is None: - warnings.warn("XMP data cannot be read without defusedxml dependency") - return {} if "xmp" not in self.info: return {} root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))