diff --git a/.ci/requirements-cibw.txt b/.ci/requirements-cibw.txt index dd61634cd..ccd6d87ed 100644 --- a/.ci/requirements-cibw.txt +++ b/.ci/requirements-cibw.txt @@ -1 +1 @@ -cibuildwheel==2.16.2 +cibuildwheel==2.16.5 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9fe345c8a..4319cc8ff 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -37,16 +37,26 @@ jobs: with: python-version: "3.x" cache: pip - cache-dependency-path: ".ci/*.sh" + cache-dependency-path: | + ".ci/*.sh" + "pyproject.toml" - name: Build system information run: python3 .github/workflows/system-info.py + - name: Cache libimagequant + uses: actions/cache@v4 + id: cache-libimagequant + with: + path: ~/cache-libimagequant + key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }} + - name: Install Linux dependencies run: | .ci/install.sh env: GHA_PYTHON_VERSION: "3.x" + GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }} - name: Build run: | diff --git a/.github/workflows/macos-install.sh b/.github/workflows/macos-install.sh index f41324c4b..28124d7f7 100755 --- a/.github/workflows/macos-install.sh +++ b/.github/workflows/macos-install.sh @@ -2,7 +2,16 @@ set -e -brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype libraqm +brew install \ + freetype \ + ghostscript \ + libimagequant \ + libjpeg \ + libraqm \ + libtiff \ + little-cms2 \ + openjpeg \ + webp export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig" # TODO Update condition when cffi supports 3.13 diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 9c3eb0924..b5c8c39aa 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -47,7 +47,7 @@ jobs: uses: actions/checkout@v4 - name: Install Cygwin - uses: cygwin/cygwin-install-action@v4 + uses: egor-tensin/setup-cygwin@v4 with: platform: x86_64 packages: > @@ -69,6 +69,7 @@ jobs: make netpbm perl + python39=3.9.16-1 python3${{ matrix.python-minor-version }}-cffi python3${{ matrix.python-minor-version }}-cython python3${{ matrix.python-minor-version }}-devel @@ -86,7 +87,7 @@ jobs: - name: Select Python version run: | - ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3 + ln -sf c:/tools/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/tools/cygwin/bin/python3 - name: Get latest NumPy version id: latest-numpy diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 05f78704b..ae84a4d8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,6 +26,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + FORCE_COLOR: 1 + jobs: build: @@ -33,7 +36,7 @@ jobs: fail-fast: false matrix: os: [ - "macos-latest", + "macos-14", "ubuntu-latest", ] python-version: [ @@ -47,11 +50,21 @@ jobs: "3.8", ] include: - - python-version: "3.9" + - python-version: "3.11" PYTHONOPTIMIZE: 1 REVERSE: "--reverse" - - python-version: "3.8" + - python-version: "3.10" PYTHONOPTIMIZE: 2 + # M1 only available for 3.10+ + - os: "macos-latest" + python-version: "3.9" + - os: "macos-latest" + 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 }} @@ -65,17 +78,28 @@ jobs: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip - cache-dependency-path: ".ci/*.sh" + cache-dependency-path: | + ".ci/*.sh" + "pyproject.toml" - name: Build system information run: python3 .github/workflows/system-info.py + - name: Cache libimagequant + if: startsWith(matrix.os, 'ubuntu') + uses: actions/cache@v4 + id: cache-libimagequant + with: + path: ~/cache-libimagequant + key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }} + - name: Install Linux dependencies if: startsWith(matrix.os, 'ubuntu') run: | .ci/install.sh env: GHA_PYTHON_VERSION: ${{ matrix.python-version }} + GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }} - name: Install macOS dependencies if: startsWith(matrix.os, 'macOS') @@ -127,7 +151,7 @@ jobs: - name: Upload coverage uses: codecov/codecov-action@v3 with: - flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }} + flags: ${{ matrix.os == 'ubuntu-latest' && 'GHA_Ubuntu' || 'GHA_macOS' }} name: ${{ matrix.os }} Python ${{ matrix.python-version }} gcov: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6adc75b49..5ce0c9a17 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,6 +32,7 @@ repos: rev: v4.5.0 hooks: - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable - id: check-merge-conflict - id: check-json - id: check-toml diff --git a/CHANGES.rst b/CHANGES.rst index 62ae2a68b..7d80eec03 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 10.3.0 (unreleased) ------------------- +- Do not support using test-image-results to upload images after test failures #7739 + [radarhere] + +- Changed ImageMath.ops to be static #7721 + [radarhere] + - Fix APNG info after seeking backwards more than twice #7701 [esoma, radarhere] diff --git a/Tests/check_fli_oob.py b/Tests/check_fli_oob.py index ac46ff1eb..e0057a2c2 100644 --- a/Tests/check_fli_oob.py +++ b/Tests/check_fli_oob.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from __future__ import annotations from PIL import Image diff --git a/Tests/check_j2k_overflow.py b/Tests/check_j2k_overflow.py index 8a85783fc..dbdd5a4f5 100644 --- a/Tests/check_j2k_overflow.py +++ b/Tests/check_j2k_overflow.py @@ -1,13 +1,13 @@ from __future__ import annotations -from pathlib import PosixPath +from pathlib import Path import pytest from PIL import Image -def test_j2k_overflow(tmp_path: PosixPath) -> None: +def test_j2k_overflow(tmp_path: Path) -> None: im = Image.new("RGBA", (1024, 131584)) target = str(tmp_path / "temp.jpc") with pytest.raises(OSError): diff --git a/Tests/check_jp2_overflow.py b/Tests/check_jp2_overflow.py old mode 100755 new mode 100644 index 5adbb84b6..954d68bf7 --- a/Tests/check_jp2_overflow.py +++ b/Tests/check_jp2_overflow.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - # Reproductions/tests for OOB read errors in FliDecode.c # When run in python, all of these images should fail for diff --git a/Tests/check_large_memory.py b/Tests/check_large_memory.py index 2c8c77800..a9ce79e57 100644 --- a/Tests/check_large_memory.py +++ b/Tests/check_large_memory.py @@ -1,7 +1,7 @@ from __future__ import annotations import sys -from pathlib import PosixPath +from pathlib import Path from types import ModuleType import pytest @@ -31,18 +31,18 @@ XDIM = 48000 pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") -def _write_png(tmp_path: PosixPath, xdim: int, ydim: int) -> None: +def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None: f = str(tmp_path / "temp.png") im = Image.new("L", (xdim, ydim), 0) im.save(f) -def test_large(tmp_path: PosixPath) -> None: +def test_large(tmp_path: Path) -> None: """succeeded prepatch""" _write_png(tmp_path, XDIM, YDIM) -def test_2gpx(tmp_path: PosixPath) -> None: +def test_2gpx(tmp_path: Path) -> None: """failed prepatch""" _write_png(tmp_path, XDIM, XDIM) diff --git a/Tests/check_large_memory_numpy.py b/Tests/check_large_memory_numpy.py index 8609fe6d0..f4ca8d0aa 100644 --- a/Tests/check_large_memory_numpy.py +++ b/Tests/check_large_memory_numpy.py @@ -1,7 +1,7 @@ from __future__ import annotations import sys -from pathlib import PosixPath +from pathlib import Path import pytest @@ -25,7 +25,7 @@ XDIM = 48000 pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") -def _write_png(tmp_path: PosixPath, xdim: int, ydim: int) -> None: +def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None: dtype = np.uint8 a = np.zeros((xdim, ydim), dtype=dtype) f = str(tmp_path / "temp.png") @@ -33,11 +33,11 @@ def _write_png(tmp_path: PosixPath, xdim: int, ydim: int) -> None: im.save(f) -def test_large(tmp_path: PosixPath) -> None: +def test_large(tmp_path: Path) -> None: """succeeded prepatch""" _write_png(tmp_path, XDIM, YDIM) -def test_2gpx(tmp_path: PosixPath) -> None: +def test_2gpx(tmp_path: Path) -> None: """failed prepatch""" _write_png(tmp_path, XDIM, XDIM) diff --git a/Tests/helper.py b/Tests/helper.py index 99170c765..b2e7d43dd 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -25,13 +25,6 @@ if os.environ.get("SHOW_ERRORS"): uploader = "show" elif "GITHUB_ACTIONS" in os.environ: uploader = "github_actions" -else: - try: - import test_image_results - - uploader = "aws" - except ImportError: - pass def upload(a: Image.Image, b: Image.Image) -> str | None: @@ -46,8 +39,6 @@ def upload(a: Image.Image, b: Image.Image) -> str | None: a.save(os.path.join(tmpdir, "a.png")) b.save(os.path.join(tmpdir, "b.png")) return tmpdir - elif uploader == "aws": - return test_image_results.upload(a, b) return None diff --git a/Tests/images/create_eps.gnuplot b/Tests/images/create_eps.gnuplot index 4d7e29877..57a3c8c97 100644 --- a/Tests/images/create_eps.gnuplot +++ b/Tests/images/create_eps.gnuplot @@ -1,5 +1,3 @@ -#!/usr/bin/gnuplot - #This is the script that was used to create our sample EPS files #We used the following version of the gnuplot program #G N U P L O T diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py index e6e99d415..9137391b6 100644 --- a/Tests/oss-fuzz/fuzz_pillow.py +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -1,5 +1,3 @@ -#!/usr/bin/python3 - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Tests/test_000_sanity.py b/Tests/test_000_sanity.py index f64216bca..c3926250f 100644 --- a/Tests/test_000_sanity.py +++ b/Tests/test_000_sanity.py @@ -3,7 +3,7 @@ from __future__ import annotations from PIL import Image -def test_sanity(): +def test_sanity() -> None: # Make sure we have the binary extension Image.core.new("L", (100, 100)) diff --git a/Tests/test_binary.py b/Tests/test_binary.py index 41fb93fcf..d19799a09 100644 --- a/Tests/test_binary.py +++ b/Tests/test_binary.py @@ -3,12 +3,12 @@ from __future__ import annotations from PIL import _binary -def test_standard(): +def test_standard() -> None: assert _binary.i8(b"*") == 42 assert _binary.o8(42) == b"*" -def test_little_endian(): +def test_little_endian() -> None: assert _binary.i16le(b"\xff\xff\x00\x00") == 65535 assert _binary.i32le(b"\xff\xff\x00\x00") == 65535 @@ -16,7 +16,7 @@ def test_little_endian(): assert _binary.o32le(65535) == b"\xff\xff\x00\x00" -def test_big_endian(): +def test_big_endian() -> None: assert _binary.i16be(b"\x00\x00\xff\xff") == 0 assert _binary.i32be(b"\x00\x00\xff\xff") == 65535 diff --git a/Tests/test_file_cur.py b/Tests/test_file_cur.py index 27b2bc914..dbf1b866d 100644 --- a/Tests/test_file_cur.py +++ b/Tests/test_file_cur.py @@ -7,7 +7,7 @@ from PIL import CurImagePlugin, Image TEST_FILE = "Tests/images/deerstalker.cur" -def test_sanity(): +def test_sanity() -> None: with Image.open(TEST_FILE) as im: assert im.size == (32, 32) assert isinstance(im, CurImagePlugin.CurImageFile) @@ -17,7 +17,7 @@ def test_sanity(): assert im.getpixel((16, 16)) == (84, 87, 86, 255) -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): diff --git a/Tests/test_file_ftex.py b/Tests/test_file_ftex.py index 0f9154e3d..0c544245a 100644 --- a/Tests/test_file_ftex.py +++ b/Tests/test_file_ftex.py @@ -7,18 +7,18 @@ from PIL import FtexImagePlugin, Image from .helper import assert_image_equal_tofile, assert_image_similar -def test_load_raw(): +def test_load_raw() -> None: with Image.open("Tests/images/ftex_uncompressed.ftu") as im: assert_image_equal_tofile(im, "Tests/images/ftex_uncompressed.png") -def test_load_dxt1(): +def test_load_dxt1() -> None: with Image.open("Tests/images/ftex_dxt1.ftc") as im: with Image.open("Tests/images/ftex_dxt1.png") as target: assert_image_similar(im, target.convert("RGBA"), 15) -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): diff --git a/Tests/test_file_gbr.py b/Tests/test_file_gbr.py index d84004e14..be98b08f2 100644 --- a/Tests/test_file_gbr.py +++ b/Tests/test_file_gbr.py @@ -7,12 +7,12 @@ from PIL import GbrImagePlugin, Image from .helper import assert_image_equal_tofile -def test_gbr_file(): +def test_gbr_file() -> None: with Image.open("Tests/images/gbr.gbr") as im: assert_image_equal_tofile(im, "Tests/images/gbr.png") -def test_load(): +def test_load() -> None: with Image.open("Tests/images/gbr.gbr") as im: assert im.load()[0, 0] == (0, 0, 0, 0) @@ -20,14 +20,14 @@ def test_load(): assert im.load()[0, 0] == (0, 0, 0, 0) -def test_multiple_load_operations(): +def test_multiple_load_operations() -> None: with Image.open("Tests/images/gbr.gbr") as im: im.load() im.load() assert_image_equal_tofile(im, "Tests/images/gbr.png") -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): diff --git a/Tests/test_file_gd.py b/Tests/test_file_gd.py index e7db54fb4..d512df284 100644 --- a/Tests/test_file_gd.py +++ b/Tests/test_file_gd.py @@ -7,18 +7,18 @@ from PIL import GdImageFile, UnidentifiedImageError TEST_GD_FILE = "Tests/images/hopper.gd" -def test_sanity(): +def test_sanity() -> None: with GdImageFile.open(TEST_GD_FILE) as im: assert im.size == (128, 128) assert im.format == "GD" -def test_bad_mode(): +def test_bad_mode() -> None: with pytest.raises(ValueError): GdImageFile.open(TEST_GD_FILE, "bad mode") -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(UnidentifiedImageError): diff --git a/Tests/test_file_gimppalette.py b/Tests/test_file_gimppalette.py index 28855c28a..e8d5f1705 100644 --- a/Tests/test_file_gimppalette.py +++ b/Tests/test_file_gimppalette.py @@ -5,7 +5,7 @@ import pytest from PIL.GimpPaletteFile import GimpPaletteFile -def test_sanity(): +def test_sanity() -> None: with open("Tests/images/test.gpl", "rb") as fp: GimpPaletteFile(fp) @@ -22,7 +22,7 @@ def test_sanity(): GimpPaletteFile(fp) -def test_get_palette(): +def test_get_palette() -> None: # Arrange with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp: palette_file = GimpPaletteFile(fp) diff --git a/Tests/test_file_imt.py b/Tests/test_file_imt.py index aa13d4407..6957dfa0a 100644 --- a/Tests/test_file_imt.py +++ b/Tests/test_file_imt.py @@ -9,13 +9,13 @@ from PIL import Image, ImtImagePlugin from .helper import assert_image_equal_tofile -def test_sanity(): +def test_sanity() -> None: with Image.open("Tests/images/bw_gradient.imt") as im: assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") @pytest.mark.parametrize("data", (b"\n", b"\n-", b"width 1\n")) -def test_invalid_file(data): +def test_invalid_file(data: bytes) -> None: with io.BytesIO(data) as fp: with pytest.raises(SyntaxError): ImtImagePlugin.ImtImageFile(fp) diff --git a/Tests/test_file_mcidas.py b/Tests/test_file_mcidas.py index 73eba5cc8..2c94fdc39 100644 --- a/Tests/test_file_mcidas.py +++ b/Tests/test_file_mcidas.py @@ -7,14 +7,14 @@ from PIL import Image, McIdasImagePlugin from .helper import assert_image_equal_tofile -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): McIdasImagePlugin.McIdasImageFile(invalid_file) -def test_valid_file(): +def test_valid_file() -> None: # Arrange # https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8 # https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/ diff --git a/Tests/test_file_pcd.py b/Tests/test_file_pcd.py index 1a37c6ab3..81a316fc1 100644 --- a/Tests/test_file_pcd.py +++ b/Tests/test_file_pcd.py @@ -3,7 +3,7 @@ from __future__ import annotations from PIL import Image -def test_load_raw(): +def test_load_raw() -> None: with Image.open("Tests/images/hopper.pcd") as im: im.load() # should not segfault. diff --git a/Tests/test_file_pixar.py b/Tests/test_file_pixar.py index c6ddc54e7..8f208cfbf 100644 --- a/Tests/test_file_pixar.py +++ b/Tests/test_file_pixar.py @@ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper TEST_FILE = "Tests/images/hopper.pxr" -def test_sanity(): +def test_sanity() -> None: with Image.open(TEST_FILE) as im: im.load() assert im.mode == "RGB" @@ -21,7 +21,7 @@ def test_sanity(): assert_image_similar(im, im2, 4.8) -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): diff --git a/Tests/test_file_qoi.py b/Tests/test_file_qoi.py index 6dc468754..fd4b981ce 100644 --- a/Tests/test_file_qoi.py +++ b/Tests/test_file_qoi.py @@ -7,7 +7,7 @@ from PIL import Image, QoiImagePlugin from .helper import assert_image_equal_tofile -def test_sanity(): +def test_sanity() -> None: with Image.open("Tests/images/hopper.qoi") as im: assert im.mode == "RGB" assert im.size == (128, 128) @@ -23,7 +23,7 @@ def test_sanity(): assert_image_equal_tofile(im, "Tests/images/pil123rgba.png") -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): diff --git a/Tests/test_file_wal.py b/Tests/test_file_wal.py index 7acec9759..b34975e83 100644 --- a/Tests/test_file_wal.py +++ b/Tests/test_file_wal.py @@ -7,7 +7,7 @@ from .helper import assert_image_equal_tofile TEST_FILE = "Tests/images/hopper.wal" -def test_open(): +def test_open() -> None: with WalImageFile.open(TEST_FILE) as im: assert im.format == "WAL" assert im.format_description == "Quake2 Texture" @@ -19,7 +19,7 @@ def test_open(): assert_image_equal_tofile(im, "Tests/images/hopper_wal.png") -def test_load(): +def test_load() -> None: with WalImageFile.open(TEST_FILE) as im: assert im.load()[0, 0] == 122 diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index 08c80973a..32e29de56 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import Path + import pytest from PIL import Image @@ -10,7 +12,7 @@ _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") RGB_MODE = "RGB" -def test_write_lossless_rgb(tmp_path): +def test_write_lossless_rgb(tmp_path: Path) -> None: if _webp.WebPDecoderVersion() < 0x0200: pytest.skip("lossless not included") diff --git a/Tests/test_file_xpm.py b/Tests/test_file_xpm.py index 529a45580..26afe93f4 100644 --- a/Tests/test_file_xpm.py +++ b/Tests/test_file_xpm.py @@ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper TEST_FILE = "Tests/images/hopper.xpm" -def test_sanity(): +def test_sanity() -> None: with Image.open(TEST_FILE) as im: im.load() assert im.mode == "P" @@ -20,14 +20,14 @@ def test_sanity(): assert_image_similar(im.convert("RGB"), hopper("RGB"), 60) -def test_invalid_file(): +def test_invalid_file() -> None: invalid_file = "Tests/images/flower.jpg" with pytest.raises(SyntaxError): XpmImagePlugin.XpmImageFile(invalid_file) -def test_load_read(): +def test_load_read() -> None: # Arrange with Image.open(TEST_FILE) as im: dummy_bytes = 1 diff --git a/Tests/test_file_xvthumb.py b/Tests/test_file_xvthumb.py index b87494eba..6b8115930 100644 --- a/Tests/test_file_xvthumb.py +++ b/Tests/test_file_xvthumb.py @@ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper TEST_FILE = "Tests/images/hopper.p7" -def test_open(): +def test_open() -> None: # Act with Image.open(TEST_FILE) as im: # Assert @@ -20,7 +20,7 @@ def test_open(): assert_image_similar(im, im_hopper, 9) -def test_unexpected_eof(): +def test_unexpected_eof() -> None: # Test unexpected EOF reading XV thumbnail file # Arrange bad_file = "Tests/images/hopper_bad.p7" @@ -30,7 +30,7 @@ def test_unexpected_eof(): XVThumbImagePlugin.XVThumbImageFile(bad_file) -def test_invalid_file(): +def test_invalid_file() -> None: # Arrange invalid_file = "Tests/images/flower.jpg" diff --git a/Tests/test_font_bdf.py b/Tests/test_font_bdf.py index e5e856186..136070f9e 100644 --- a/Tests/test_font_bdf.py +++ b/Tests/test_font_bdf.py @@ -7,7 +7,7 @@ from PIL import BdfFontFile, FontFile filename = "Tests/images/courB08.bdf" -def test_sanity(): +def test_sanity() -> None: with open(filename, "rb") as test_file: font = BdfFontFile.BdfFontFile(test_file) @@ -15,7 +15,7 @@ def test_sanity(): assert len([_f for _f in font.glyph if _f]) == 190 -def test_invalid_file(): +def test_invalid_file() -> None: with open("Tests/images/flower.jpg", "rb") as fp: with pytest.raises(SyntaxError): BdfFontFile.BdfFontFile(fp) diff --git a/Tests/test_font_crash.py b/Tests/test_font_crash.py index e3c72c1ae..b82340ef7 100644 --- a/Tests/test_font_crash.py +++ b/Tests/test_font_crash.py @@ -8,7 +8,7 @@ from .helper import skip_unless_feature class TestFontCrash: - def _fuzz_font(self, font): + def _fuzz_font(self, font: ImageFont.FreeTypeFont) -> None: # from fuzzers.fuzz_font font.getbbox("ABC") font.getmask("test text") @@ -18,7 +18,7 @@ class TestFontCrash: draw.text((10, 10), "Test Text", font=font, fill="#000") @skip_unless_feature("freetype2") - def test_segfault(self): + def test_segfault(self) -> None: with pytest.raises(OSError): font = ImageFont.truetype("Tests/fonts/fuzz_font-5203009437302784") self._fuzz_font(font) diff --git a/Tests/test_font_leaks.py b/Tests/test_font_leaks.py index 4e29a856b..241f455b8 100644 --- a/Tests/test_font_leaks.py +++ b/Tests/test_font_leaks.py @@ -10,7 +10,7 @@ class TestTTypeFontLeak(PillowLeakTestCase): iterations = 10 mem_limit = 4096 # k - def _test_font(self, font): + def _test_font(self, font: ImageFont.FreeTypeFont) -> None: im = Image.new("RGB", (255, 255), "white") draw = ImageDraw.ImageDraw(im) self._test_leak( @@ -20,7 +20,7 @@ class TestTTypeFontLeak(PillowLeakTestCase): ) @skip_unless_feature("freetype2") - def test_leak(self): + def test_leak(self) -> None: ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) self._test_font(ttype) @@ -30,6 +30,6 @@ class TestDefaultFontLeak(TestTTypeFontLeak): iterations = 100 mem_limit = 1024 # k - def test_leak(self): + def test_leak(self) -> None: default_font = ImageFont.load_default() self._test_font(default_font) diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index e6abede07..997809e46 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -1,6 +1,7 @@ from __future__ import annotations import os +from pathlib import Path import pytest @@ -20,7 +21,7 @@ message = "hello, world" pytestmark = skip_unless_feature("zlib") -def save_font(request, tmp_path): +def save_font(request: pytest.FixtureRequest, tmp_path: Path) -> str: with open(fontname, "rb") as test_file: font = PcfFontFile.PcfFontFile(test_file) assert isinstance(font, FontFile.FontFile) @@ -29,7 +30,7 @@ def save_font(request, tmp_path): tempname = str(tmp_path / "temp.pil") - def delete_tempfile(): + def delete_tempfile() -> None: try: os.remove(tempname[:-4] + ".pbm") except OSError: @@ -47,11 +48,11 @@ def save_font(request, tmp_path): return tempname -def test_sanity(request, tmp_path): +def test_sanity(request: pytest.FixtureRequest, tmp_path: Path) -> None: save_font(request, tmp_path) -def test_less_than_256_characters(): +def test_less_than_256_characters() -> None: with open("Tests/fonts/10x20-ISO8859-1-fewer-characters.pcf", "rb") as test_file: font = PcfFontFile.PcfFontFile(test_file) assert isinstance(font, FontFile.FontFile) @@ -59,13 +60,13 @@ def test_less_than_256_characters(): assert len([_f for _f in font.glyph if _f]) == 127 -def test_invalid_file(): +def test_invalid_file() -> None: with open("Tests/images/flower.jpg", "rb") as fp: with pytest.raises(SyntaxError): PcfFontFile.PcfFontFile(fp) -def test_draw(request, tmp_path): +def test_draw(request: pytest.FixtureRequest, tmp_path: Path) -> None: tempname = save_font(request, tmp_path) font = ImageFont.load(tempname) im = Image.new("L", (130, 30), "white") @@ -74,7 +75,7 @@ def test_draw(request, tmp_path): assert_image_similar_tofile(im, "Tests/images/test_draw_pbm_target.png", 0) -def test_textsize(request, tmp_path): +def test_textsize(request: pytest.FixtureRequest, tmp_path: Path) -> None: tempname = save_font(request, tmp_path) font = ImageFont.load(tempname) for i in range(255): @@ -90,7 +91,9 @@ def test_textsize(request, tmp_path): assert font.getbbox(msg) == (0, 0, len(msg) * 10, 20) -def _test_high_characters(request, tmp_path, message): +def _test_high_characters( + request: pytest.FixtureRequest, tmp_path: Path, message: str | bytes +) -> None: tempname = save_font(request, tmp_path) font = ImageFont.load(tempname) im = Image.new("L", (750, 30), "white") @@ -99,7 +102,7 @@ def _test_high_characters(request, tmp_path, message): assert_image_similar_tofile(im, "Tests/images/high_ascii_chars.png", 0) -def test_high_characters(request, tmp_path): +def test_high_characters(request: pytest.FixtureRequest, tmp_path: Path) -> None: message = "".join(chr(i + 1) for i in range(140, 232)) _test_high_characters(request, tmp_path, message) # accept bytes instances. diff --git a/Tests/test_font_pcf_charsets.py b/Tests/test_font_pcf_charsets.py index 4c2d7185e..895458d9d 100644 --- a/Tests/test_font_pcf_charsets.py +++ b/Tests/test_font_pcf_charsets.py @@ -1,6 +1,8 @@ from __future__ import annotations import os +from pathlib import Path +from typing import TypedDict import pytest @@ -14,7 +16,14 @@ from .helper import ( fontname = "Tests/fonts/ter-x20b.pcf" -charsets = { + +class Charset(TypedDict): + glyph_count: int + message: str + image1: str + + +charsets: dict[str, Charset] = { "iso8859-1": { "glyph_count": 223, "message": "hello, world", @@ -36,7 +45,7 @@ charsets = { pytestmark = skip_unless_feature("zlib") -def save_font(request, tmp_path, encoding): +def save_font(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> str: with open(fontname, "rb") as test_file: font = PcfFontFile.PcfFontFile(test_file, encoding) assert isinstance(font, FontFile.FontFile) @@ -45,7 +54,7 @@ def save_font(request, tmp_path, encoding): tempname = str(tmp_path / "temp.pil") - def delete_tempfile(): + def delete_tempfile() -> None: try: os.remove(tempname[:-4] + ".pbm") except OSError: @@ -64,12 +73,12 @@ def save_font(request, tmp_path, encoding): @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) -def test_sanity(request, tmp_path, encoding): +def test_sanity(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> None: save_font(request, tmp_path, encoding) @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) -def test_draw(request, tmp_path, encoding): +def test_draw(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> None: tempname = save_font(request, tmp_path, encoding) font = ImageFont.load(tempname) im = Image.new("L", (150, 30), "white") @@ -80,7 +89,9 @@ def test_draw(request, tmp_path, encoding): @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) -def test_textsize(request, tmp_path, encoding): +def test_textsize( + request: pytest.FixtureRequest, tmp_path: Path, encoding: str +) -> None: tempname = save_font(request, tmp_path, encoding) font = ImageFont.load(tempname) for i in range(255): diff --git a/Tests/test_fontfile.py b/Tests/test_fontfile.py index eda8fb812..206499a04 100644 --- a/Tests/test_fontfile.py +++ b/Tests/test_fontfile.py @@ -1,11 +1,13 @@ from __future__ import annotations +from pathlib import Path + import pytest from PIL import FontFile -def test_save(tmp_path): +def test_save(tmp_path: Path) -> None: tempname = str(tmp_path / "temp.pil") font = FontFile.FontFile() diff --git a/Tests/test_format_lab.py b/Tests/test_format_lab.py index a55620e09..4fcc37e88 100644 --- a/Tests/test_format_lab.py +++ b/Tests/test_format_lab.py @@ -3,7 +3,7 @@ from __future__ import annotations from PIL import Image -def test_white(): +def test_white() -> None: with Image.open("Tests/images/lab.tif") as i: i.load() @@ -24,7 +24,7 @@ def test_white(): assert list(b) == [128] * 100 -def test_green(): +def test_green() -> None: # l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS # == RGB: 0, 152, 117 with Image.open("Tests/images/lab-green.tif") as i: @@ -32,7 +32,7 @@ def test_green(): assert k == (128, 28, 128) -def test_red(): +def test_red() -> None: # l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS # == RGB: 255, 0, 124 with Image.open("Tests/images/lab-red.tif") as i: diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index d4ddc2a31..f154de123 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import Path + import pytest from PIL import Image @@ -7,8 +9,8 @@ from PIL import Image from .helper import assert_image, assert_image_equal, assert_image_similar, hopper -def test_sanity(): - def convert(im, mode): +def test_sanity() -> None: + def convert(im: Image.Image, mode: str) -> None: out = im.convert(mode) assert out.mode == mode assert out.size == im.size @@ -40,13 +42,13 @@ def test_sanity(): convert(im, output_mode) -def test_unsupported_conversion(): +def test_unsupported_conversion() -> None: im = hopper() with pytest.raises(ValueError): im.convert("INVALID") -def test_default(): +def test_default() -> None: im = hopper("P") assert im.mode == "P" converted_im = im.convert() @@ -62,18 +64,18 @@ def test_default(): # ref https://github.com/python-pillow/Pillow/issues/274 -def _test_float_conversion(im): +def _test_float_conversion(im: Image.Image) -> None: orig = im.getpixel((5, 5)) converted = im.convert("F").getpixel((5, 5)) assert orig == converted -def test_8bit(): +def test_8bit() -> None: with Image.open("Tests/images/hopper.jpg") as im: _test_float_conversion(im.convert("L")) -def test_16bit(): +def test_16bit() -> None: with Image.open("Tests/images/16bit.cropped.tif") as im: _test_float_conversion(im) @@ -83,19 +85,19 @@ def test_16bit(): assert im_i16.getpixel((0, 0)) == 65535 -def test_16bit_workaround(): +def test_16bit_workaround() -> None: with Image.open("Tests/images/16bit.cropped.tif") as im: _test_float_conversion(im.convert("I")) -def test_opaque(): +def test_opaque() -> None: alpha = hopper("P").convert("PA").getchannel("A") solid = Image.new("L", (128, 128), 255) assert_image_equal(alpha, solid) -def test_rgba_p(): +def test_rgba_p() -> None: im = hopper("RGBA") im.putalpha(hopper("L")) @@ -105,14 +107,14 @@ def test_rgba_p(): assert_image_similar(im, comparable, 20) -def test_rgba(): +def test_rgba() -> None: with Image.open("Tests/images/transparent.png") as im: assert im.mode == "RGBA" assert_image_similar(im.convert("RGBa").convert("RGB"), im.convert("RGB"), 1.5) -def test_trns_p(tmp_path): +def test_trns_p(tmp_path: Path) -> None: im = hopper("P") im.info["transparency"] = 0 @@ -131,7 +133,7 @@ def test_trns_p(tmp_path): @pytest.mark.parametrize("mode", ("LA", "PA", "RGBA")) -def test_trns_p_transparency(mode): +def test_trns_p_transparency(mode: str) -> None: # Arrange im = hopper("P") im.info["transparency"] = 128 @@ -148,7 +150,7 @@ def test_trns_p_transparency(mode): assert converted_im.palette is None -def test_trns_l(tmp_path): +def test_trns_l(tmp_path: Path) -> None: im = hopper("L") im.info["transparency"] = 128 @@ -171,7 +173,7 @@ def test_trns_l(tmp_path): im_p.save(f) -def test_trns_RGB(tmp_path): +def test_trns_RGB(tmp_path: Path) -> None: im = hopper("RGB") im.info["transparency"] = im.getpixel((0, 0)) @@ -201,7 +203,7 @@ def test_trns_RGB(tmp_path): @pytest.mark.parametrize("convert_mode", ("L", "LA", "I")) -def test_l_macro_rounding(convert_mode): +def test_l_macro_rounding(convert_mode: str) -> None: for mode in ("P", "PA"): im = Image.new(mode, (1, 1)) im.palette.getcolor((0, 1, 2)) @@ -214,7 +216,7 @@ def test_l_macro_rounding(convert_mode): assert converted_color == 1 -def test_gif_with_rgba_palette_to_p(): +def test_gif_with_rgba_palette_to_p() -> None: # See https://github.com/python-pillow/Pillow/issues/2433 with Image.open("Tests/images/hopper.gif") as im: im.info["transparency"] = 255 @@ -226,7 +228,7 @@ def test_gif_with_rgba_palette_to_p(): im_p.load() -def test_p_la(): +def test_p_la() -> None: im = hopper("RGBA") alpha = hopper("L") im.putalpha(alpha) @@ -236,7 +238,7 @@ def test_p_la(): assert_image_similar(alpha, comparable, 5) -def test_p2pa_alpha(): +def test_p2pa_alpha() -> None: with Image.open("Tests/images/tiny.png") as im: assert im.mode == "P" @@ -250,13 +252,13 @@ def test_p2pa_alpha(): assert im_a.getpixel((x, y)) == alpha -def test_p2pa_palette(): +def test_p2pa_palette() -> None: with Image.open("Tests/images/tiny.png") as im: im_pa = im.convert("PA") assert im_pa.getpalette() == im.getpalette() -def test_matrix_illegal_conversion(): +def test_matrix_illegal_conversion() -> None: # Arrange im = hopper("CMYK") # fmt: off @@ -272,7 +274,7 @@ def test_matrix_illegal_conversion(): im.convert(mode="CMYK", matrix=matrix) -def test_matrix_wrong_mode(): +def test_matrix_wrong_mode() -> None: # Arrange im = hopper("L") # fmt: off @@ -289,7 +291,7 @@ def test_matrix_wrong_mode(): @pytest.mark.parametrize("mode", ("RGB", "L")) -def test_matrix_xyz(mode): +def test_matrix_xyz(mode: str) -> None: # Arrange im = hopper("RGB") im.info["transparency"] = (255, 0, 0) @@ -317,7 +319,7 @@ def test_matrix_xyz(mode): assert converted_im.info["transparency"] == 105 -def test_matrix_identity(): +def test_matrix_identity() -> None: # Arrange im = hopper("RGB") # fmt: off diff --git a/Tests/test_image_copy.py b/Tests/test_image_copy.py index 3a26ef96e..027e5338b 100644 --- a/Tests/test_image_copy.py +++ b/Tests/test_image_copy.py @@ -10,7 +10,7 @@ from .helper import hopper, skip_unless_feature @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F")) -def test_copy(mode): +def test_copy(mode: str) -> None: cropped_coordinates = (10, 10, 20, 20) cropped_size = (10, 10) @@ -39,7 +39,7 @@ def test_copy(mode): assert out.size == cropped_size -def test_copy_zero(): +def test_copy_zero() -> None: im = Image.new("RGB", (0, 0)) out = im.copy() assert out.mode == im.mode @@ -47,7 +47,7 @@ def test_copy_zero(): @skip_unless_feature("libtiff") -def test_deepcopy(): +def test_deepcopy() -> None: with Image.open("Tests/images/g4_orientation_5.tif") as im: out = copy.deepcopy(im) assert out.size == (590, 88) diff --git a/Tests/test_image_crop.py b/Tests/test_image_crop.py index 5e02a3b0d..d095364ba 100644 --- a/Tests/test_image_crop.py +++ b/Tests/test_image_crop.py @@ -8,7 +8,7 @@ from .helper import assert_image_equal, hopper @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F")) -def test_crop(mode): +def test_crop(mode: str) -> None: im = hopper(mode) assert_image_equal(im.crop(), im) @@ -17,8 +17,8 @@ def test_crop(mode): assert cropped.size == (50, 50) -def test_wide_crop(): - def crop(*bbox): +def test_wide_crop() -> None: + def crop(*bbox: int) -> tuple[int, ...]: i = im.crop(bbox) h = i.histogram() while h and not h[-1]: @@ -47,14 +47,14 @@ def test_wide_crop(): @pytest.mark.parametrize("box", ((8, 2, 2, 8), (2, 8, 8, 2), (8, 8, 2, 2))) -def test_negative_crop(box): +def test_negative_crop(box: tuple[int, int, int, int]) -> None: im = Image.new("RGB", (10, 10)) with pytest.raises(ValueError): im.crop(box) -def test_crop_float(): +def test_crop_float() -> None: # Check cropping floats are rounded to nearest integer # https://github.com/python-pillow/Pillow/issues/1744 @@ -69,7 +69,7 @@ def test_crop_float(): assert cropped.size == (3, 5) -def test_crop_crash(): +def test_crop_crash() -> None: # Image.crop crashes prepatch with an access violation # apparently a use after free on Windows, see # https://github.com/python-pillow/Pillow/issues/1077 @@ -87,7 +87,7 @@ def test_crop_crash(): img.load() -def test_crop_zero(): +def test_crop_zero() -> None: im = Image.new("RGB", (0, 0), "white") cropped = im.crop((0, 0, 0, 0)) diff --git a/Tests/test_image_frombytes.py b/Tests/test_image_frombytes.py index 5d5e9f2df..6474daba1 100644 --- a/Tests/test_image_frombytes.py +++ b/Tests/test_image_frombytes.py @@ -8,7 +8,7 @@ from .helper import assert_image_equal, hopper @pytest.mark.parametrize("data_type", ("bytes", "memoryview")) -def test_sanity(data_type): +def test_sanity(data_type) -> None: im1 = hopper() data = im1.tobytes() diff --git a/Tests/test_image_fromqimage.py b/Tests/test_image_fromqimage.py index 76b576da5..ea31a9de9 100644 --- a/Tests/test_image_fromqimage.py +++ b/Tests/test_image_fromqimage.py @@ -1,6 +1,7 @@ from __future__ import annotations import warnings +from typing import Generator import pytest @@ -18,7 +19,7 @@ pytestmark = pytest.mark.skipif( @pytest.fixture -def test_images(): +def test_images() -> Generator[Image.Image, None, None]: ims = [ hopper(), Image.open("Tests/images/transparent.png"), @@ -31,7 +32,7 @@ def test_images(): im.close() -def roundtrip(expected): +def roundtrip(expected: Image.Image) -> None: # PIL -> Qt intermediate = expected.toqimage() # Qt -> PIL @@ -43,26 +44,26 @@ def roundtrip(expected): assert_image_equal(result, expected.convert("RGB")) -def test_sanity_1(test_images): +def test_sanity_1(test_images: Generator[Image.Image, None, None]) -> None: for im in test_images: roundtrip(im.convert("1")) -def test_sanity_rgb(test_images): +def test_sanity_rgb(test_images: Generator[Image.Image, None, None]) -> None: for im in test_images: roundtrip(im.convert("RGB")) -def test_sanity_rgba(test_images): +def test_sanity_rgba(test_images: Generator[Image.Image, None, None]) -> None: for im in test_images: roundtrip(im.convert("RGBA")) -def test_sanity_l(test_images): +def test_sanity_l(test_images: Generator[Image.Image, None, None]) -> None: for im in test_images: roundtrip(im.convert("L")) -def test_sanity_p(test_images): +def test_sanity_p(test_images: Generator[Image.Image, None, None]) -> None: for im in test_images: roundtrip(im.convert("P")) diff --git a/Tests/test_image_getbands.py b/Tests/test_image_getbands.py index 64339e2cd..887553fc0 100644 --- a/Tests/test_image_getbands.py +++ b/Tests/test_image_getbands.py @@ -3,7 +3,7 @@ from __future__ import annotations from PIL import Image -def test_getbands(): +def test_getbands() -> None: assert Image.new("1", (1, 1)).getbands() == ("1",) assert Image.new("L", (1, 1)).getbands() == ("L",) assert Image.new("I", (1, 1)).getbands() == ("I",) diff --git a/Tests/test_image_getbbox.py b/Tests/test_image_getbbox.py index b18a7202e..18c6f6579 100644 --- a/Tests/test_image_getbbox.py +++ b/Tests/test_image_getbbox.py @@ -7,13 +7,13 @@ from PIL import Image from .helper import hopper -def test_sanity(): +def test_sanity() -> None: bbox = hopper().getbbox() assert isinstance(bbox, tuple) -def test_bbox(): - def check(im, fill_color): +def test_bbox() -> None: + def check(im: Image.Image, fill_color: int | tuple[int, ...]) -> None: assert im.getbbox() is None im.paste(fill_color, (10, 25, 90, 75)) @@ -34,8 +34,8 @@ def test_bbox(): check(im, 255) for mode in ("RGBA", "RGBa"): - for color in ((0, 0, 0, 0), (127, 127, 127, 0), (255, 255, 255, 0)): - im = Image.new(mode, (100, 100), color) + for rgba_color in ((0, 0, 0, 0), (127, 127, 127, 0), (255, 255, 255, 0)): + im = Image.new(mode, (100, 100), rgba_color) check(im, (255, 255, 255, 255)) for mode in ("La", "LA", "PA"): @@ -45,7 +45,7 @@ def test_bbox(): @pytest.mark.parametrize("mode", ("RGBA", "RGBa", "La", "LA", "PA")) -def test_bbox_alpha_only_false(mode): +def test_bbox_alpha_only_false(mode: str) -> None: im = Image.new(mode, (100, 100)) assert im.getbbox(alpha_only=False) is None diff --git a/Tests/test_image_getcolors.py b/Tests/test_image_getcolors.py index 17460fa93..8f8870f4f 100644 --- a/Tests/test_image_getcolors.py +++ b/Tests/test_image_getcolors.py @@ -3,8 +3,8 @@ from __future__ import annotations from .helper import hopper -def test_getcolors(): - def getcolors(mode, limit=None): +def test_getcolors() -> None: + def getcolors(mode: str, limit: int | None = None) -> int | None: im = hopper(mode) if limit: colors = im.getcolors(limit) @@ -39,7 +39,7 @@ def test_getcolors(): # -------------------------------------------------------------------- -def test_pack(): +def test_pack() -> None: # Pack problems for small tables (@PIL209) im = hopper().quantize(3).convert("RGB") diff --git a/Tests/test_image_getdata.py b/Tests/test_image_getdata.py index ace64279b..ac27400be 100644 --- a/Tests/test_image_getdata.py +++ b/Tests/test_image_getdata.py @@ -5,7 +5,7 @@ from PIL import Image from .helper import hopper -def test_sanity(): +def test_sanity() -> None: data = hopper().getdata() len(data) @@ -14,8 +14,8 @@ def test_sanity(): assert data[0] == (20, 20, 70) -def test_roundtrip(): - def getdata(mode): +def test_roundtrip() -> None: + def getdata(mode: str) -> tuple[float | tuple[int, ...], int, int]: im = hopper(mode).resize((32, 30), Image.Resampling.NEAREST) data = im.getdata() return data[0], len(data), len(list(data)) diff --git a/Tests/test_image_getim.py b/Tests/test_image_getim.py index bc8a7485e..9afa02b0a 100644 --- a/Tests/test_image_getim.py +++ b/Tests/test_image_getim.py @@ -3,7 +3,7 @@ from __future__ import annotations from .helper import hopper -def test_sanity(): +def test_sanity() -> None: im = hopper() type_repr = repr(type(im.getim())) diff --git a/Tests/test_image_getprojection.py b/Tests/test_image_getprojection.py index e90f5f505..2b5a758ed 100644 --- a/Tests/test_image_getprojection.py +++ b/Tests/test_image_getprojection.py @@ -5,7 +5,7 @@ from PIL import Image from .helper import hopper -def test_sanity(): +def test_sanity() -> None: im = hopper() projection = im.getprojection() diff --git a/Tests/test_image_histogram.py b/Tests/test_image_histogram.py index 3ac6649e0..dbd55d4c2 100644 --- a/Tests/test_image_histogram.py +++ b/Tests/test_image_histogram.py @@ -3,8 +3,8 @@ from __future__ import annotations from .helper import hopper -def test_histogram(): - def histogram(mode): +def test_histogram() -> None: + def histogram(mode: str) -> tuple[int, int, int]: h = hopper(mode).histogram() return len(h), min(h), max(h) diff --git a/Tests/test_image_point.py b/Tests/test_image_point.py index 2232b9442..05f209351 100644 --- a/Tests/test_image_point.py +++ b/Tests/test_image_point.py @@ -5,7 +5,7 @@ import pytest from .helper import assert_image_equal, hopper -def test_sanity(): +def test_sanity() -> None: im = hopper() with pytest.raises(ValueError): @@ -39,7 +39,7 @@ def test_sanity(): im.point(lambda x: x // 2) -def test_16bit_lut(): +def test_16bit_lut() -> None: """Tests for 16 bit -> 8 bit lut for converting I->L images see https://github.com/python-pillow/Pillow/issues/440 """ @@ -47,7 +47,7 @@ def test_16bit_lut(): im.point(list(range(256)) * 256, "L") -def test_f_lut(): +def test_f_lut() -> None: """Tests for floating point lut of 8bit gray image""" im = hopper("L") lut = [0.5 * float(x) for x in range(256)] @@ -58,7 +58,7 @@ def test_f_lut(): assert_image_equal(out.convert("L"), im.point(int_lut, "L")) -def test_f_mode(): +def test_f_mode() -> None: im = hopper("F") with pytest.raises(ValueError): im.point(None) diff --git a/Tests/test_image_putalpha.py b/Tests/test_image_putalpha.py index c44b048d5..2c92911d1 100644 --- a/Tests/test_image_putalpha.py +++ b/Tests/test_image_putalpha.py @@ -3,7 +3,7 @@ from __future__ import annotations from PIL import Image -def test_interface(): +def test_interface() -> None: im = Image.new("RGBA", (1, 1), (1, 2, 3, 0)) assert im.getpixel((0, 0)) == (1, 2, 3, 0) @@ -17,7 +17,7 @@ def test_interface(): assert im.getpixel((0, 0)) == (1, 2, 3, 5) -def test_promote(): +def test_promote() -> None: im = Image.new("L", (1, 1), 1) assert im.getpixel((0, 0)) == 1 @@ -40,7 +40,7 @@ def test_promote(): assert im.getpixel((0, 0)) == (1, 2, 3, 4) -def test_readonly(): +def test_readonly() -> None: im = Image.new("RGB", (1, 1), (1, 2, 3)) im.readonly = 1 diff --git a/Tests/test_image_quantize.py b/Tests/test_image_quantize.py index 1475b027b..873a9bb5d 100644 --- a/Tests/test_image_quantize.py +++ b/Tests/test_image_quantize.py @@ -8,7 +8,7 @@ from PIL import Image, features from .helper import assert_image_similar, hopper, is_ppc64le, skip_unless_feature -def test_sanity(): +def test_sanity() -> None: image = hopper() converted = image.quantize() assert converted.mode == "P" @@ -21,7 +21,7 @@ def test_sanity(): @skip_unless_feature("libimagequant") -def test_libimagequant_quantize(): +def test_libimagequant_quantize() -> None: image = hopper() if is_ppc64le(): libimagequant = parse_version(features.version_feature("libimagequant")) @@ -33,7 +33,7 @@ def test_libimagequant_quantize(): assert len(converted.getcolors()) == 100 -def test_octree_quantize(): +def test_octree_quantize() -> None: image = hopper() converted = image.quantize(100, Image.Quantize.FASTOCTREE) assert converted.mode == "P" @@ -41,7 +41,7 @@ def test_octree_quantize(): assert len(converted.getcolors()) == 100 -def test_rgba_quantize(): +def test_rgba_quantize() -> None: image = hopper("RGBA") with pytest.raises(ValueError): image.quantize(method=0) @@ -49,7 +49,7 @@ def test_rgba_quantize(): assert image.quantize().convert().mode == "RGBA" -def test_quantize(): +def test_quantize() -> None: with Image.open("Tests/images/caption_6_33_22.png") as image: image = image.convert("RGB") converted = image.quantize() @@ -57,7 +57,7 @@ def test_quantize(): assert_image_similar(converted.convert("RGB"), image, 1) -def test_quantize_no_dither(): +def test_quantize_no_dither() -> None: image = hopper() with Image.open("Tests/images/caption_6_33_22.png") as palette: palette = palette.convert("P") @@ -67,7 +67,7 @@ def test_quantize_no_dither(): assert converted.palette.palette == palette.palette.palette -def test_quantize_no_dither2(): +def test_quantize_no_dither2() -> None: im = Image.new("RGB", (9, 1)) im.putdata([(p,) * 3 for p in range(0, 36, 4)]) @@ -83,7 +83,7 @@ def test_quantize_no_dither2(): assert px[x, 0] == (0 if x < 5 else 1) -def test_quantize_dither_diff(): +def test_quantize_dither_diff() -> None: image = hopper() with Image.open("Tests/images/caption_6_33_22.png") as palette: palette = palette.convert("P") @@ -94,14 +94,14 @@ def test_quantize_dither_diff(): assert dither.tobytes() != nodither.tobytes() -def test_colors(): +def test_colors() -> None: im = hopper() colors = 2 converted = im.quantize(colors) assert len(converted.palette.palette) == colors * len("RGB") -def test_transparent_colors_equal(): +def test_transparent_colors_equal() -> None: im = Image.new("RGBA", (1, 2), (0, 0, 0, 0)) px = im.load() px[0, 1] = (255, 255, 255, 0) @@ -120,7 +120,7 @@ def test_transparent_colors_equal(): (Image.Quantize.FASTOCTREE, (0, 0, 0, 0)), ), ) -def test_palette(method, color): +def test_palette(method: Image.Quantize, color: tuple[int, ...]) -> None: im = Image.new("RGBA" if len(color) == 4 else "RGB", (1, 1), color) converted = im.quantize(method=method) @@ -128,7 +128,7 @@ def test_palette(method, color): assert converted_px[0, 0] == converted.palette.colors[color] -def test_small_palette(): +def test_small_palette() -> None: # Arrange im = hopper() diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index aedcf4a09..bd45ee893 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -4,6 +4,8 @@ Tests for resize functionality. from __future__ import annotations from itertools import permutations +from pathlib import Path +from typing import Generator import pytest @@ -19,7 +21,9 @@ from .helper import ( class TestImagingCoreResize: - def resize(self, im, size, f): + def resize( + self, im: Image.Image, size: tuple[int, int], f: Image.Resampling + ) -> Image.Image: # Image class independent version of resize. im.load() return im._new(im.im.resize(size, f)) @@ -27,14 +31,14 @@ class TestImagingCoreResize: @pytest.mark.parametrize( "mode", ("1", "P", "L", "I", "F", "RGB", "RGBA", "CMYK", "YCbCr", "I;16") ) - def test_nearest_mode(self, mode): + def test_nearest_mode(self, mode: str) -> None: im = hopper(mode) r = self.resize(im, (15, 12), Image.Resampling.NEAREST) assert r.mode == mode assert r.size == (15, 12) assert r.im.bands == im.im.bands - def test_convolution_modes(self): + def test_convolution_modes(self) -> None: with pytest.raises(ValueError): self.resize(hopper("1"), (15, 12), Image.Resampling.BILINEAR) with pytest.raises(ValueError): @@ -59,7 +63,7 @@ class TestImagingCoreResize: Image.Resampling.LANCZOS, ), ) - def test_reduce_filters(self, resample): + def test_reduce_filters(self, resample: Image.Resampling) -> None: r = self.resize(hopper("RGB"), (15, 12), resample) assert r.mode == "RGB" assert r.size == (15, 12) @@ -75,7 +79,7 @@ class TestImagingCoreResize: Image.Resampling.LANCZOS, ), ) - def test_enlarge_filters(self, resample): + def test_enlarge_filters(self, resample: Image.Resampling) -> None: r = self.resize(hopper("RGB"), (212, 195), resample) assert r.mode == "RGB" assert r.size == (212, 195) @@ -99,7 +103,9 @@ class TestImagingCoreResize: ("LA", ("filled", "dirty")), ), ) - def test_endianness(self, resample, mode, channels_set): + def test_endianness( + self, resample: Image.Resampling, mode: str, channels_set: tuple[str, ...] + ) -> None: # Make an image with one colored pixel, in one channel. # When resized, that channel should be the same as a GS image. # Other channels should be unaffected. @@ -139,17 +145,17 @@ class TestImagingCoreResize: Image.Resampling.LANCZOS, ), ) - def test_enlarge_zero(self, resample): + def test_enlarge_zero(self, resample: Image.Resampling) -> None: r = self.resize(Image.new("RGB", (0, 0), "white"), (212, 195), resample) assert r.mode == "RGB" assert r.size == (212, 195) assert r.getdata()[0] == (0, 0, 0) - def test_unknown_filter(self): + def test_unknown_filter(self) -> None: with pytest.raises(ValueError): self.resize(hopper(), (10, 10), 9) - def test_cross_platform(self, tmp_path): + def test_cross_platform(self, tmp_path: Path) -> None: # This test is intended for only check for consistent behaviour across # platforms. So if a future Pillow change requires that the test file # be updated, that is okay. @@ -162,7 +168,7 @@ class TestImagingCoreResize: @pytest.fixture -def gradients_image(): +def gradients_image() -> Generator[Image.Image, None, None]: with Image.open("Tests/images/radial_gradients.png") as im: im.load() try: @@ -172,7 +178,7 @@ def gradients_image(): class TestReducingGapResize: - def test_reducing_gap_values(self, gradients_image): + def test_reducing_gap_values(self, gradients_image: Image.Image) -> None: ref = gradients_image.resize( (52, 34), Image.Resampling.BICUBIC, reducing_gap=None ) @@ -191,7 +197,12 @@ class TestReducingGapResize: "box, epsilon", ((None, 4), ((1.1, 2.2, 510.8, 510.9), 4), ((3, 10, 410, 256), 10)), ) - def test_reducing_gap_1(self, gradients_image, box, epsilon): + def test_reducing_gap_1( + self, + gradients_image: Image.Image, + box: tuple[float, float, float, float], + epsilon: float, + ) -> None: ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) im = gradients_image.resize( (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=1.0 @@ -206,7 +217,12 @@ class TestReducingGapResize: "box, epsilon", ((None, 1.5), ((1.1, 2.2, 510.8, 510.9), 1.5), ((3, 10, 410, 256), 1)), ) - def test_reducing_gap_2(self, gradients_image, box, epsilon): + def test_reducing_gap_2( + self, + gradients_image: Image.Image, + box: tuple[float, float, float, float], + epsilon: float, + ) -> None: ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) im = gradients_image.resize( (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=2.0 @@ -221,7 +237,12 @@ class TestReducingGapResize: "box, epsilon", ((None, 1), ((1.1, 2.2, 510.8, 510.9), 1), ((3, 10, 410, 256), 0.5)), ) - def test_reducing_gap_3(self, gradients_image, box, epsilon): + def test_reducing_gap_3( + self, + gradients_image: Image.Image, + box: tuple[float, float, float, float], + epsilon: float, + ) -> None: ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) im = gradients_image.resize( (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=3.0 @@ -233,7 +254,9 @@ class TestReducingGapResize: assert_image_similar(ref, im, epsilon) @pytest.mark.parametrize("box", (None, (1.1, 2.2, 510.8, 510.9), (3, 10, 410, 256))) - def test_reducing_gap_8(self, gradients_image, box): + def test_reducing_gap_8( + self, gradients_image: Image.Image, box: tuple[float, float, float, float] + ) -> None: ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) im = gradients_image.resize( (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=8.0 @@ -245,7 +268,12 @@ class TestReducingGapResize: "box, epsilon", (((0, 0, 512, 512), 5.5), ((0.9, 1.7, 128, 128), 9.5)), ) - def test_box_filter(self, gradients_image, box, epsilon): + def test_box_filter( + self, + gradients_image: Image.Image, + box: tuple[float, float, float, float], + epsilon: float, + ) -> None: ref = gradients_image.resize((52, 34), Image.Resampling.BOX, box=box) im = gradients_image.resize( (52, 34), Image.Resampling.BOX, box=box, reducing_gap=1.0 @@ -255,8 +283,8 @@ class TestReducingGapResize: class TestImageResize: - def test_resize(self): - def resize(mode, size): + def test_resize(self) -> None: + def resize(mode: str, size: tuple[int, int]) -> None: out = hopper(mode).resize(size) assert out.mode == mode assert out.size == size @@ -271,7 +299,7 @@ class TestImageResize: im.resize((10, 10), "unknown") @skip_unless_feature("libtiff") - def test_load_first(self): + def test_load_first(self) -> None: # load() may change the size of the image # Test that resize() is calling it before getting the size with Image.open("Tests/images/g4_orientation_5.tif") as im: @@ -279,13 +307,13 @@ class TestImageResize: assert im.size == (64, 64) @pytest.mark.parametrize("mode", ("L", "RGB", "I", "F")) - def test_default_filter_bicubic(self, mode): + def test_default_filter_bicubic(self, mode: str) -> None: im = hopper(mode) assert im.resize((20, 20), Image.Resampling.BICUBIC) == im.resize((20, 20)) @pytest.mark.parametrize( "mode", ("1", "P", "I;16", "I;16L", "I;16B", "BGR;15", "BGR;16") ) - def test_default_filter_nearest(self, mode): + def test_default_filter_nearest(self, mode: str) -> None: im = hopper(mode) assert im.resize((20, 20), Image.Resampling.NEAREST) == im.resize((20, 20)) diff --git a/Tests/test_image_split.py b/Tests/test_image_split.py index c39a100e7..3385f81f5 100644 --- a/Tests/test_image_split.py +++ b/Tests/test_image_split.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import Path + import pytest from PIL import Image, features @@ -7,8 +9,8 @@ from PIL import Image, features from .helper import assert_image_equal, hopper -def test_split(): - def split(mode): +def test_split() -> None: + def split(mode: str) -> list[tuple[str, int, int]]: layers = hopper(mode).split() return [(i.mode, i.size[0], i.size[1]) for i in layers] @@ -36,18 +38,18 @@ def test_split(): @pytest.mark.parametrize( "mode", ("1", "L", "I", "F", "P", "RGB", "RGBA", "CMYK", "YCbCr") ) -def test_split_merge(mode): +def test_split_merge(mode: str) -> None: expected = Image.merge(mode, hopper(mode).split()) assert_image_equal(hopper(mode), expected) -def test_split_open(tmp_path): +def test_split_open(tmp_path: Path) -> None: if features.check("zlib"): test_file = str(tmp_path / "temp.png") else: test_file = str(tmp_path / "temp.pcx") - def split_open(mode): + def split_open(mode: str) -> int: hopper(mode).save(test_file) with Image.open(test_file) as im: return len(im.split()) diff --git a/Tests/test_image_tobitmap.py b/Tests/test_image_tobitmap.py index 89a41cf8e..f7a3cc41d 100644 --- a/Tests/test_image_tobitmap.py +++ b/Tests/test_image_tobitmap.py @@ -5,7 +5,7 @@ import pytest from .helper import assert_image_equal, fromstring, hopper -def test_sanity(): +def test_sanity() -> None: with pytest.raises(ValueError): hopper().tobitmap() diff --git a/Tests/test_image_tobytes.py b/Tests/test_image_tobytes.py index 8f15adac0..d32b6c09b 100644 --- a/Tests/test_image_tobytes.py +++ b/Tests/test_image_tobytes.py @@ -3,6 +3,6 @@ from __future__ import annotations from .helper import hopper -def test_sanity(): +def test_sanity() -> None: data = hopper().tobytes() assert isinstance(data, bytes) diff --git a/Tests/test_image_transpose.py b/Tests/test_image_transpose.py index 01bf5a839..d384d8141 100644 --- a/Tests/test_image_transpose.py +++ b/Tests/test_image_transpose.py @@ -2,6 +2,7 @@ from __future__ import annotations import pytest +from PIL import Image from PIL.Image import Transpose from . import helper @@ -14,7 +15,7 @@ HOPPER = { @pytest.mark.parametrize("mode", HOPPER) -def test_flip_left_right(mode): +def test_flip_left_right(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.FLIP_LEFT_RIGHT) assert out.mode == mode @@ -28,7 +29,7 @@ def test_flip_left_right(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_flip_top_bottom(mode): +def test_flip_top_bottom(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.FLIP_TOP_BOTTOM) assert out.mode == mode @@ -42,7 +43,7 @@ def test_flip_top_bottom(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_rotate_90(mode): +def test_rotate_90(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.ROTATE_90) assert out.mode == mode @@ -56,7 +57,7 @@ def test_rotate_90(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_rotate_180(mode): +def test_rotate_180(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.ROTATE_180) assert out.mode == mode @@ -70,7 +71,7 @@ def test_rotate_180(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_rotate_270(mode): +def test_rotate_270(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.ROTATE_270) assert out.mode == mode @@ -84,7 +85,7 @@ def test_rotate_270(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_transpose(mode): +def test_transpose(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.TRANSPOSE) assert out.mode == mode @@ -98,7 +99,7 @@ def test_transpose(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_tranverse(mode): +def test_tranverse(mode: str) -> None: im = HOPPER[mode] out = im.transpose(Transpose.TRANSVERSE) assert out.mode == mode @@ -112,10 +113,10 @@ def test_tranverse(mode): @pytest.mark.parametrize("mode", HOPPER) -def test_roundtrip(mode): +def test_roundtrip(mode: str) -> None: im = HOPPER[mode] - def transpose(first, second): + def transpose(first: Transpose, second: Transpose) -> Image.Image: return im.transpose(first).transpose(second) assert_image_equal( diff --git a/Tests/test_lib_image.py b/Tests/test_lib_image.py index 1c642e4c9..31548bbc9 100644 --- a/Tests/test_lib_image.py +++ b/Tests/test_lib_image.py @@ -5,7 +5,7 @@ import pytest from PIL import Image -def test_setmode(): +def test_setmode() -> None: im = Image.new("L", (1, 1), 255) im.im.setmode("1") assert im.im.getpixel((0, 0)) == 255 diff --git a/Tests/test_locale.py b/Tests/test_locale.py index db9557d7b..1c8b84a2b 100644 --- a/Tests/test_locale.py +++ b/Tests/test_locale.py @@ -24,7 +24,7 @@ from PIL import Image path = "Tests/images/hopper.jpg" -def test_sanity(): +def test_sanity() -> None: with Image.open(path): pass try: diff --git a/Tests/test_main.py b/Tests/test_main.py index 9f61a0c81..46259f1dc 100644 --- a/Tests/test_main.py +++ b/Tests/test_main.py @@ -5,7 +5,7 @@ import subprocess import sys -def test_main(): +def test_main() -> None: out = subprocess.check_output([sys.executable, "-m", "PIL"]).decode("utf-8") lines = out.splitlines() assert lines[0] == "-" * 68 diff --git a/Tests/test_pyroma.py b/Tests/test_pyroma.py index c2cea08ca..c2f7fe22e 100644 --- a/Tests/test_pyroma.py +++ b/Tests/test_pyroma.py @@ -7,7 +7,7 @@ from PIL import __version__ pyroma = pytest.importorskip("pyroma", reason="Pyroma not installed") -def test_pyroma(): +def test_pyroma() -> None: # Arrange data = pyroma.projectdata.get_data(".") diff --git a/Tests/test_uploader.py b/Tests/test_uploader.py index 75326288f..d55ceb4be 100644 --- a/Tests/test_uploader.py +++ b/Tests/test_uploader.py @@ -3,13 +3,13 @@ from __future__ import annotations from .helper import assert_image_equal, assert_image_similar, hopper -def check_upload_equal(): +def check_upload_equal() -> None: result = hopper("P").convert("RGB") target = hopper("RGB") assert_image_equal(result, target) -def check_upload_similar(): +def check_upload_similar() -> None: result = hopper("P").convert("RGB") target = hopper("RGB") assert_image_similar(result, target, 0) diff --git a/Tests/test_util.py b/Tests/test_util.py index 3395ef753..b47ca8827 100644 --- a/Tests/test_util.py +++ b/Tests/test_util.py @@ -1,11 +1,13 @@ from __future__ import annotations +from pathlib import Path + import pytest from PIL import _util -def test_is_path(): +def test_is_path() -> None: # Arrange fp = "filename.ext" @@ -16,7 +18,7 @@ def test_is_path(): assert it_is -def test_path_obj_is_path(): +def test_path_obj_is_path() -> None: # Arrange from pathlib import Path @@ -29,7 +31,7 @@ def test_path_obj_is_path(): assert it_is -def test_is_not_path(tmp_path): +def test_is_not_path(tmp_path: Path) -> None: # Arrange with (tmp_path / "temp.ext").open("w") as fp: pass @@ -41,7 +43,7 @@ def test_is_not_path(tmp_path): assert not it_is_not -def test_is_directory(): +def test_is_directory() -> None: # Arrange directory = "Tests" @@ -52,7 +54,7 @@ def test_is_directory(): assert it_is -def test_is_not_directory(): +def test_is_not_directory() -> None: # Arrange text = "abc" @@ -63,7 +65,7 @@ def test_is_not_directory(): assert not it_is_not -def test_deferred_error(): +def test_deferred_error() -> None: # Arrange # Act diff --git a/Tests/test_webp_leaks.py b/Tests/test_webp_leaks.py index 0f51abc95..626fe427c 100644 --- a/Tests/test_webp_leaks.py +++ b/Tests/test_webp_leaks.py @@ -14,11 +14,11 @@ class TestWebPLeaks(PillowLeakTestCase): mem_limit = 3 * 1024 # kb iterations = 100 - def test_leak_load(self): + def test_leak_load(self) -> None: with open(test_file, "rb") as f: im_data = f.read() - def core(): + def core() -> None: with Image.open(BytesIO(im_data)) as im: im.load() diff --git a/depends/download-and-extract.sh b/depends/download-and-extract.sh index a318bfafd..04bfbc755 100755 --- a/depends/download-and-extract.sh +++ b/depends/download-and-extract.sh @@ -5,7 +5,7 @@ archive=$1 url=$2 if [ ! -f $archive.tar.gz ]; then - wget -O $archive.tar.gz $url + wget --no-verbose -O $archive.tar.gz $url fi rmdir $archive diff --git a/depends/install_imagequant.sh b/depends/install_imagequant.sh index b7cebbdbf..3adae91a5 100755 --- a/depends/install_imagequant.sh +++ b/depends/install_imagequant.sh @@ -1,15 +1,39 @@ #!/bin/bash # install libimagequant -archive=libimagequant-4.2.2 +archive_name=libimagequant +archive_version=4.2.2 -./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz +archive=$archive_name-$archive_version -pushd $archive/imagequant-sys +if [[ "$GHA_LIBIMAGEQUANT_CACHE_HIT" == "true" ]]; then -cargo install cargo-c -cargo cinstall --prefix=/usr --destdir=. -sudo cp usr/lib/libimagequant.so* /usr/lib/ -sudo cp usr/include/libimagequant.h /usr/include/ + # Copy cached files into place + sudo cp ~/cache-$archive_name/libimagequant.so* /usr/lib/ + sudo cp ~/cache-$archive_name/libimagequant.h /usr/include/ -popd +else + + # Build from source + ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz + + pushd $archive/imagequant-sys + + cargo install cargo-c + cargo cinstall --prefix=/usr --destdir=. + + # Copy into place + sudo cp usr/lib/libimagequant.so* /usr/lib/ + sudo cp usr/include/libimagequant.h /usr/include/ + + if [ -n "$GITHUB_ACTIONS" ]; then + # Copy to cache + rm -rf ~/cache-$archive_name + mkdir ~/cache-$archive_name + cp usr/lib/libimagequant.so* ~/cache-$archive_name/ + cp usr/include/libimagequant.h ~/cache-$archive_name/ + fi + + popd + +fi diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index 1bf0bcff5..1bbd2c05c --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # > pyroma . # ------------------------------ # Checking .