mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Merge branch 'main' into main
This commit is contained in:
commit
e7470ed789
|
@ -1 +1 @@
|
|||
cibuildwheel==2.16.2
|
||||
cibuildwheel==2.16.5
|
||||
|
|
12
.github/workflows/docs.yml
vendored
12
.github/workflows/docs.yml
vendored
|
@ -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: |
|
||||
|
|
11
.github/workflows/macos-install.sh
vendored
11
.github/workflows/macos-install.sh
vendored
|
@ -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
|
||||
|
|
5
.github/workflows/test-cygwin.yml
vendored
5
.github/workflows/test-cygwin.yml
vendored
|
@ -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
|
||||
|
|
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
from PIL import Image
|
||||
|
|
|
@ -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):
|
||||
|
|
2
Tests/check_jp2_overflow.py
Executable file → Normal file
2
Tests/check_jp2_overflow.py
Executable file → Normal file
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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",)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()))
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from PIL import Image
|
|||
from .helper import hopper
|
||||
|
||||
|
||||
def test_sanity():
|
||||
def test_sanity() -> None:
|
||||
im = hopper()
|
||||
|
||||
projection = im.getprojection()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(".")
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user