From 51bd7d2ea8b8dbebabb200ca3c449c38b76e1d7f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:44:45 -0600 Subject: [PATCH] Drop support for Python 3.8 (#8183) Co-authored-by: Andrew Murray Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- .appveyor.yml | 6 +++--- .ci/install.sh | 1 - .github/workflows/test-cygwin.yml | 2 +- .github/workflows/test-docker.yml | 1 - .github/workflows/test-windows.yml | 2 +- .github/workflows/test.yml | 5 ----- .github/workflows/wheels.yml | 4 ---- Tests/helper.py | 3 ++- Tests/test_file_eps.py | 7 ++++--- Tests/test_file_gif.py | 2 +- Tests/test_file_pdf.py | 3 ++- Tests/test_file_tiff.py | 2 +- Tests/test_image_resample.py | 2 +- Tests/test_image_resize.py | 2 +- Tests/test_imagedraw.py | 2 +- Tests/test_imageops_usm.py | 2 +- Tests/test_imagepath.py | 2 +- docs/installation/basic-installation.rst | 4 ++-- docs/installation/newer-versions.csv | 2 +- docs/installation/platform-support.rst | 12 +++++------- docs/releasenotes/11.0.0.rst | 6 ++++++ pyproject.toml | 5 ++--- src/PIL/GifImagePlugin.py | 4 ++-- src/PIL/Image.py | 8 +++----- src/PIL/ImageDraw.py | 9 +++++---- src/PIL/ImageFilter.py | 3 ++- src/PIL/ImageOps.py | 3 ++- src/PIL/ImagePalette.py | 3 ++- src/PIL/ImageTransform.py | 3 ++- src/PIL/IptcImagePlugin.py | 2 +- src/PIL/Jpeg2KImagePlugin.py | 4 ++-- src/PIL/PdfParser.py | 4 ++-- src/PIL/SpiderImagePlugin.py | 4 ++-- src/PIL/_typing.py | 3 ++- tox.ini | 2 +- winbuild/README.md | 2 +- winbuild/build.rst | 2 +- 37 files changed, 66 insertions(+), 67 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6ce5200b6..e12987a5f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,9 +21,9 @@ environment: - PYTHON: C:/Python312 ARCHITECTURE: x86 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - - PYTHON: C:/Python38-x64 + - PYTHON: C:/Python39-x64 ARCHITECTURE: AMD64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 install: @@ -38,7 +38,7 @@ install: - path c:\nasm-2.16.03;C:\Program Files\gs\gs10.03.1\bin;%PATH% - cd c:\pillow\winbuild\ - ps: | - c:\python38\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ + c:\python39\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ c:\pillow\winbuild\build\build_dep_all.cmd $host.SetShouldExit(0) - path C:\pillow\winbuild\build\bin;%PATH% diff --git a/.ci/install.sh b/.ci/install.sh index fc5ff0064..1eb098be9 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -48,7 +48,6 @@ if [[ $(uname) != CYGWIN* ]]; then # Pyroma uses non-isolated build and fails with old setuptools if [[ $GHA_PYTHON_VERSION == pypy3.9 - || $GHA_PYTHON_VERSION == 3.8 || $GHA_PYTHON_VERSION == 3.9 ]]; then # To match pyproject.toml diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 97422d569..8e2827099 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -35,7 +35,7 @@ jobs: strategy: fail-fast: false matrix: - python-minor-version: [8, 9] + python-minor-version: [9] timeout-minutes: 40 diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index d18ab9729..21e1275e7 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -49,7 +49,6 @@ jobs: fedora-39-amd64, fedora-40-amd64, gentoo, - ubuntu-20.04-focal-amd64, ubuntu-22.04-jammy-amd64, ubuntu-24.04-noble-amd64, ] diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index ee265774b..5b34d6703 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -35,7 +35,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["pypy3.10", "pypy3.9", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["pypy3.10", "pypy3.9", "3.9", "3.10", "3.11", "3.12", "3.13"] timeout-minutes: 30 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa5646caf..0972459b0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -48,7 +48,6 @@ jobs: "3.11", "3.10", "3.9", - "3.8", ] include: - python-version: "3.11" @@ -59,13 +58,9 @@ jobs: # M1 only available for 3.10+ - os: "macos-13" python-version: "3.9" - - os: "macos-13" - python-version: "3.8" exclude: - os: "macos-14" python-version: "3.9" - - os: "macos-14" - python-version: "3.8" runs-on: ${{ matrix.os }} name: ${{ matrix.os }} Python ${{ matrix.python-version }} diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 3d6099c1c..4eb907bcd 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -41,7 +41,6 @@ jobs: python-version: - pp39 - pp310 - - cp38 - cp39 - cp310 - cp311 @@ -136,8 +135,6 @@ jobs: CIBW_MANYLINUX_PYPY_X86_64_IMAGE: ${{ matrix.manylinux }} CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }} CIBW_PRERELEASE_PYTHONS: True - CIBW_SKIP: pp38-* - CIBW_TEST_SKIP: cp38-macosx_arm64 MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }} - uses: actions/upload-artifact@v4 @@ -208,7 +205,6 @@ jobs: CIBW_BEFORE_ALL: "{package}\\winbuild\\build\\build_dep_all.cmd" CIBW_CACHE_PATH: "C:\\cibw" CIBW_PRERELEASE_PYTHONS: True - CIBW_SKIP: pp38-* CIBW_TEST_SKIP: "*-win_arm64" CIBW_TEST_COMMAND: 'docker run --rm -v {project}:C:\pillow diff --git a/Tests/helper.py b/Tests/helper.py index 605a214d4..7abc495b6 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -11,9 +11,10 @@ import subprocess import sys import sysconfig import tempfile +from collections.abc import Sequence from functools import lru_cache from io import BytesIO -from typing import Any, Callable, Sequence +from typing import Any, Callable import pytest from packaging.version import parse as parse_version diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 3181fc204..b54238132 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -385,9 +385,10 @@ def test_timeout(test_file: str) -> None: def test_bounding_box_in_trailer() -> None: # Check bounding boxes are parsed in the same way # when specified in the header and the trailer - with Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, Image.open( - FILE1 - ) as header_image: + with ( + Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, + Image.open(FILE1) as header_image, + ): assert trailer_image.size == header_image.size diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index e19c88a47..79a2ec0ab 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -1,9 +1,9 @@ from __future__ import annotations import warnings +from collections.abc import Generator from io import BytesIO from pathlib import Path -from typing import Generator import pytest diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index d39a86565..02f07a565 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -5,8 +5,9 @@ import os import os.path import tempfile import time +from collections.abc import Generator from pathlib import Path -from typing import Any, Generator +from typing import Any import pytest diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index c06d110a7..93a9f9e6a 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -2,10 +2,10 @@ from __future__ import annotations import os import warnings +from collections.abc import Generator from io import BytesIO from pathlib import Path from types import ModuleType -from typing import Generator import pytest diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 58de812ef..92ba1553c 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -1,7 +1,7 @@ from __future__ import annotations +from collections.abc import Generator from contextlib import contextmanager -from typing import Generator import pytest diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 64098f80f..3ef05a25f 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -4,9 +4,9 @@ Tests for resize functionality. from __future__ import annotations +from collections.abc import Generator from itertools import permutations from pathlib import Path -from typing import Generator import pytest diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 1466ab1ba..1ff3fea2a 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -2,7 +2,7 @@ from __future__ import annotations import contextlib import os.path -from typing import Sequence +from collections.abc import Sequence import pytest diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index c8e2c0467..920012d86 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generator +from collections.abc import Generator import pytest diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 9487560af..cda2584e7 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -3,7 +3,7 @@ from __future__ import annotations import array import math import struct -from typing import Sequence +from collections.abc import Sequence import pytest diff --git a/docs/installation/basic-installation.rst b/docs/installation/basic-installation.rst index 01981aa4f..989f72ddd 100644 --- a/docs/installation/basic-installation.rst +++ b/docs/installation/basic-installation.rst @@ -68,8 +68,8 @@ and :pypi:`olefile` for Pillow to read FPX and MIC images:: .. tab:: Windows We provide Pillow binaries for Windows compiled for the matrix of supported - Pythons in the wheel format. These include x86, x86-64 and arm64 versions - (with the exception of Python 3.8 on arm64). These binaries include support + Pythons in the wheel format. These include x86, x86-64 and arm64 versions. + These binaries include support for all optional libraries except libimagequant and libxcb. Raqm support requires FriBiDi to be installed separately:: diff --git a/docs/installation/newer-versions.csv b/docs/installation/newer-versions.csv index 028a2018f..19816af58 100644 --- a/docs/installation/newer-versions.csv +++ b/docs/installation/newer-versions.csv @@ -1,5 +1,5 @@ Python,3.13,3.12,3.11,3.10,3.9,3.8,3.7,3.6,3.5 -Pillow >= 11,Yes,Yes,Yes,Yes,Yes,Yes,,, +Pillow >= 11,Yes,Yes,Yes,Yes,Yes,,,, Pillow 10.1 - 10.4,,Yes,Yes,Yes,Yes,Yes,,, Pillow 10.0,,,Yes,Yes,Yes,Yes,,, Pillow 9.3 - 9.5,,,Yes,Yes,Yes,Yes,Yes,, diff --git a/docs/installation/platform-support.rst b/docs/installation/platform-support.rst index cde00c76d..1d449a036 100644 --- a/docs/installation/platform-support.rst +++ b/docs/installation/platform-support.rst @@ -35,14 +35,12 @@ These platforms are built and tested for every change. +----------------------------------+----------------------------+---------------------+ | Gentoo | 3.9 | x86-64 | +----------------------------------+----------------------------+---------------------+ -| macOS 13 Ventura | 3.8, 3.9 | x86-64 | +| macOS 13 Ventura | 3.9 | x86-64 | +----------------------------------+----------------------------+---------------------+ | macOS 14 Sonoma | 3.10, 3.11, 3.12, 3.13, | arm64 | | | PyPy3 | | +----------------------------------+----------------------------+---------------------+ -| Ubuntu Linux 20.04 LTS (Focal) | 3.8 | x86-64 | -+----------------------------------+----------------------------+---------------------+ -| Ubuntu Linux 22.04 LTS (Jammy) | 3.8, 3.9, 3.10, 3.11, | x86-64 | +| Ubuntu Linux 22.04 LTS (Jammy) | 3.9, 3.10, 3.11, | x86-64 | | | 3.12, 3.13, PyPy3 | | | +----------------------------+---------------------+ | | 3.10 | arm64v8 | @@ -50,16 +48,16 @@ These platforms are built and tested for every change. | Ubuntu Linux 24.04 LTS (Noble) | 3.12 | x86-64, ppc64le, | | | | s390x | +----------------------------------+----------------------------+---------------------+ -| Windows Server 2016 | 3.8 | x86-64 | +| Windows Server 2016 | 3.9 | x86-64 | +----------------------------------+----------------------------+---------------------+ -| Windows Server 2022 | 3.8, 3.9, 3.10, 3.11, | x86-64 | +| Windows Server 2022 | 3.9, 3.10, 3.11, | x86-64 | | | 3.12, 3.13, PyPy3 | | | +----------------------------+---------------------+ | | 3.12 | x86 | | +----------------------------+---------------------+ | | 3.9 (MinGW) | x86-64 | | +----------------------------+---------------------+ -| | 3.8, 3.9 (Cygwin) | x86-64 | +| | 3.9 (Cygwin) | x86-64 | +----------------------------------+----------------------------+---------------------+ diff --git a/docs/releasenotes/11.0.0.rst b/docs/releasenotes/11.0.0.rst index 0b18fe01a..964423ae0 100644 --- a/docs/releasenotes/11.0.0.rst +++ b/docs/releasenotes/11.0.0.rst @@ -17,6 +17,12 @@ TODO Backwards Incompatible Changes ============================== +Python 3.8 +^^^^^^^^^^ + +Pillow has dropped support for Python 3.8, +which reached end-of-life in October 2024. + PSFile ^^^^^^ diff --git a/pyproject.toml b/pyproject.toml index a1cc7554f..700d5e7fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,12 +18,11 @@ license = { text = "HPND" } authors = [ { name = "Jeffrey A. Clark", email = "aclark@aclark.net" }, ] -requires-python = ">=3.8" +requires-python = ">=3.9" classifiers = [ "Development Status :: 6 - Mature", "License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -147,7 +146,7 @@ testpaths = [ ] [tool.mypy] -python_version = "3.8" +python_version = "3.9" pretty = true disallow_any_generics = true enable_error_code = "ignore-without-code" diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 8018e25dc..bf74f9356 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -32,7 +32,7 @@ import subprocess import sys from enum import IntEnum from functools import cached_property -from typing import IO, TYPE_CHECKING, Any, List, Literal, NamedTuple, Union +from typing import IO, TYPE_CHECKING, Any, Literal, NamedTuple, Union from . import ( Image, @@ -504,7 +504,7 @@ def _normalize_mode(im: Image.Image) -> Image.Image: return im.convert("L") -_Palette = Union[bytes, bytearray, List[int], ImagePalette.ImagePalette] +_Palette = Union[bytes, bytearray, list[int], ImagePalette.ImagePalette] def _normalize_palette( diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 005b4cc9e..b4ef62510 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -38,7 +38,7 @@ import struct import sys import tempfile import warnings -from collections.abc import Callable, MutableMapping +from collections.abc import Callable, MutableMapping, Sequence from enum import IntEnum from types import ModuleType from typing import ( @@ -47,8 +47,6 @@ from typing import ( Any, Literal, Protocol, - Sequence, - Tuple, cast, ) @@ -1097,7 +1095,7 @@ class Image: if trns is not None: try: new_im.info["transparency"] = new_im.palette.getcolor( - cast(Tuple[int, ...], trns), # trns was converted to RGB + cast(tuple[int, ...], trns), # trns was converted to RGB new_im, ) except Exception: @@ -3075,7 +3073,7 @@ def new( and isinstance(color, (list, tuple)) and all(isinstance(i, int) for i in color) ): - color_ints: tuple[int, ...] = cast(Tuple[int, ...], tuple(color)) + color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) if len(color_ints) == 3 or len(color_ints) == 4: # RGB or RGBA value for a P image from . import ImagePalette diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 244d3d5f0..2b3620e71 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -34,8 +34,9 @@ from __future__ import annotations import math import numbers import struct +from collections.abc import Sequence from types import ModuleType -from typing import TYPE_CHECKING, AnyStr, Callable, List, Sequence, Tuple, Union, cast +from typing import TYPE_CHECKING, AnyStr, Callable, Union, cast from . import Image, ImageColor from ._deprecate import deprecate @@ -51,7 +52,7 @@ except AttributeError: if TYPE_CHECKING: from . import ImageDraw2, ImageFont -_Ink = Union[float, Tuple[int, ...], str] +_Ink = Union[float, tuple[int, ...], str] """ A simple 2D drawing interface for PIL images. @@ -1124,7 +1125,7 @@ def _compute_regular_polygon_vertices( msg = "bounding_circle should only contain numeric data" raise ValueError(msg) - *centroid, polygon_radius = cast(List[float], list(bounding_circle)) + *centroid, polygon_radius = cast(list[float], list(bounding_circle)) elif len(bounding_circle) == 2 and isinstance(bounding_circle[0], (list, tuple)): if not all( isinstance(i, (int, float)) for i in bounding_circle[0] @@ -1136,7 +1137,7 @@ def _compute_regular_polygon_vertices( msg = "bounding_circle centre should contain 2D coordinates (e.g. (x, y))" raise ValueError(msg) - centroid = cast(List[float], list(bounding_circle[0])) + centroid = cast(list[float], list(bounding_circle[0])) polygon_radius = cast(float, bounding_circle[1]) else: msg = ( diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index e18b4a446..8b0974b2c 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -18,8 +18,9 @@ from __future__ import annotations import abc import functools +from collections.abc import Sequence from types import ModuleType -from typing import TYPE_CHECKING, Any, Callable, Sequence, cast +from typing import TYPE_CHECKING, Any, Callable, cast if TYPE_CHECKING: from . import _imaging diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index d47b86a75..44aad0c3c 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -21,7 +21,8 @@ from __future__ import annotations import functools import operator import re -from typing import Protocol, Sequence, cast +from collections.abc import Sequence +from typing import Protocol, cast from . import ExifTags, Image, ImagePalette diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index ed38285dc..8ccecbd07 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -18,7 +18,8 @@ from __future__ import annotations import array -from typing import IO, TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import IO, TYPE_CHECKING from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile diff --git a/src/PIL/ImageTransform.py b/src/PIL/ImageTransform.py index ffd791674..a3d8f441a 100644 --- a/src/PIL/ImageTransform.py +++ b/src/PIL/ImageTransform.py @@ -14,7 +14,8 @@ # from __future__ import annotations -from typing import Any, Sequence +from collections.abc import Sequence +from typing import Any from . import Image diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index 73df83bfb..f9d5b75f0 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -16,8 +16,8 @@ # from __future__ import annotations +from collections.abc import Sequence from io import BytesIO -from typing import Sequence from . import Image, ImageFile from ._binary import i16be as i16 diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index e50cd7799..c8a57567a 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -18,7 +18,7 @@ from __future__ import annotations import io import os import struct -from typing import IO, Tuple, cast +from typing import IO, cast from . import Image, ImageFile, ImagePalette, _binary @@ -82,7 +82,7 @@ class BoxReader: self.remaining_in_box = -1 # Read the length and type of the next box - lbox, tbox = cast(Tuple[int, bytes], self.read_fields(">I4s")) + lbox, tbox = cast(tuple[int, bytes], self.read_fields(">I4s")) if lbox == 1: lbox = cast(int, self.read_fields(">Q")[0]) hlen = 16 diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 9e2231347..622dc7de9 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -8,7 +8,7 @@ import os import re import time import zlib -from typing import TYPE_CHECKING, Any, List, NamedTuple, Union +from typing import TYPE_CHECKING, Any, NamedTuple, Union # see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set @@ -240,7 +240,7 @@ class PdfName: return bytes(result) -class PdfArray(List[Any]): +class PdfArray(list[Any]): def __bytes__(self) -> bytes: return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]" diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index f5a09c3ef..a07101e54 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -37,7 +37,7 @@ from __future__ import annotations import os import struct import sys -from typing import IO, TYPE_CHECKING, Any, Tuple, cast +from typing import IO, TYPE_CHECKING, Any, cast from . import Image, ImageFile @@ -187,7 +187,7 @@ class SpiderImageFile(ImageFile.ImageFile): def convert2byte(self, depth: int = 255) -> Image.Image: extrema = self.getextrema() assert isinstance(extrema[0], float) - minimum, maximum = cast(Tuple[float, float], extrema) + minimum, maximum = cast(tuple[float, float], extrema) m: float = 1 if maximum != minimum: m = depth / (maximum - minimum) diff --git a/src/PIL/_typing.py b/src/PIL/_typing.py index db1e80e2f..b6bb8d89a 100644 --- a/src/PIL/_typing.py +++ b/src/PIL/_typing.py @@ -2,7 +2,8 @@ from __future__ import annotations import os import sys -from typing import TYPE_CHECKING, Any, Protocol, Sequence, TypeVar, Union +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Protocol, TypeVar, Union if TYPE_CHECKING: try: diff --git a/tox.ini b/tox.ini index 912d7167c..189415237 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ requires = tox>=4.2 env_list = lint - py{py3, 313, 312, 311, 310, 39, 38} + py{py3, 313, 312, 311, 310, 39} [testenv] deps = diff --git a/winbuild/README.md b/winbuild/README.md index 7e81abcb0..c8048bcc9 100644 --- a/winbuild/README.md +++ b/winbuild/README.md @@ -16,7 +16,7 @@ For more extensive info, see the [Windows build instructions](build.rst). The following is a simplified version of the script used on AppVeyor: ``` -set PYTHON=C:\Python38\bin +set PYTHON=C:\Python39\bin cd /D C:\Pillow\winbuild %PYTHON%\python.exe build_prepare.py -v --depends=C:\pillow-depends build\build_dep_all.cmd diff --git a/winbuild/build.rst b/winbuild/build.rst index d0be2943e..96b8803b4 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -114,7 +114,7 @@ Example The following is a simplified version of the script used on AppVeyor:: - set PYTHON=C:\Python38\bin + set PYTHON=C:\Python39\bin cd /D C:\Pillow\winbuild %PYTHON%\python.exe build_prepare.py -v --depends C:\pillow-depends build\build_dep_all.cmd