Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into type_hints
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/PIL/Image.py
  • Loading branch information
nulano committed Jun 12, 2024
2 parents eb56f3e + 114e017 commit 31a8da4
Show file tree
Hide file tree
Showing 89 changed files with 976 additions and 624 deletions.
6 changes: 3 additions & 3 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ install:
- curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip
- 7z x pillow-test-images.zip -oc:\
- xcopy /S /Y c:\test-images-main\* c:\pillow\tests\images
- curl -fsSL -o nasm-win64.zip https://raw.githubusercontent.com/python-pillow/pillow-depends/main/nasm-2.16.01-win64.zip
- curl -fsSL -o nasm-win64.zip https://raw.githubusercontent.com/python-pillow/pillow-depends/main/nasm-2.16.03-win64.zip
- 7z x nasm-win64.zip -oc:\
- choco install ghostscript --version=10.3.0
- path c:\nasm-2.16.01;C:\Program Files\gs\gs10.00.0\bin;%PATH%
- choco install ghostscript --version=10.3.1
- path c:\nasm-2.16.03;C:\Program Files\gs\gs10.00.0\bin;%PATH%
- cd c:\pillow\winbuild\
- ps: |
c:\python38\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
Expand Down
2 changes: 1 addition & 1 deletion .ci/requirements-cibw.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cibuildwheel==2.18.1
cibuildwheel==2.19.0
2 changes: 1 addition & 1 deletion .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
choco install nasm --no-progress
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
choco install ghostscript --version=10.3.0 --no-progress
choco install ghostscript --version=10.3.1 --no-progress
echo "C:\Program Files\gs\gs10.00.0\bin" >> $env:GITHUB_PATH
# Install extra test images
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/wheels-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ ARCHIVE_SDIR=pillow-depends-main

# Package versions for fresh source builds
FREETYPE_VERSION=2.13.2
HARFBUZZ_VERSION=8.4.0
HARFBUZZ_VERSION=8.5.0
LIBPNG_VERSION=1.6.43
JPEGTURBO_VERSION=3.0.2
JPEGTURBO_VERSION=3.0.3
OPENJPEG_VERSION=2.5.2
XZ_VERSION=5.4.5
TIFF_VERSION=4.6.0
Expand All @@ -33,9 +33,9 @@ if [[ -n "$IS_MACOS" ]] || [[ "$MB_ML_VER" != 2014 ]]; then
else
ZLIB_VERSION=1.2.8
fi
LIBWEBP_VERSION=1.3.2
LIBWEBP_VERSION=1.4.0
BZIP2_VERSION=1.0.8
LIBXCB_VERSION=1.16.1
LIBXCB_VERSION=1.17.0
BROTLI_VERSION=1.1.0

if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "x86_64" ]]; then
Expand Down Expand Up @@ -70,7 +70,7 @@ function build {
fi
build_new_zlib

build_simple xcb-proto 1.16.0 https://xorg.freedesktop.org/archive/individual/proto
build_simple xcb-proto 1.17.0 https://xorg.freedesktop.org/archive/individual/proto
if [ -n "$IS_MACOS" ]; then
build_simple xorgproto 2024.1 https://www.x.org/pub/individual/proto
build_simple libXau 1.0.11 https://www.x.org/pub/individual/lib
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.3
rev: v0.4.7
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
Expand All @@ -24,7 +24,7 @@ repos:
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.4
rev: v18.1.5
hooks:
- id: clang-format
types: [c]
Expand All @@ -50,7 +50,7 @@ repos:
exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.2
rev: 0.28.4
hooks:
- id: check-github-workflows
- id: check-readthedocs
Expand All @@ -67,7 +67,7 @@ repos:
- id: pyproject-fmt

- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.16
rev: v0.18
hooks:
- id: validate-pyproject

Expand Down
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Changelog (Pillow)
10.4.0 (unreleased)
-------------------

- Accept 't' suffix for libtiff version #8126, #8129
[radarhere]

- Deprecate ImageDraw.getdraw hints parameter #8124
[radarhere, hugovk]

- Added ImageDraw circle() #8085
[void4, hugovk, radarhere]

Expand Down
1 change: 1 addition & 0 deletions Tests/bench_cffi_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def test_direct() -> None:
caccess = im.im.pixel_access(False)
access = PyAccess.new(im, False)

assert access is not None
assert caccess[(0, 0)] == access[(0, 0)]

print(f"Size: {im.width}x{im.height}")
Expand Down
6 changes: 4 additions & 2 deletions Tests/test_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def test(name: str, function: Callable[[str], str | None]) -> None:
assert function(name) == version
if name != "PIL":
if name == "zlib" and version is not None:
version = version.replace(".zlib-ng", "")
version = re.sub(".zlib-ng$", "", version)
elif name == "libtiff" and version is not None:
version = re.sub("t$", "", version)
assert version is None or re.search(r"\d+(\.\d+)*$", version)

for module in features.modules:
Expand Down Expand Up @@ -124,7 +126,7 @@ def test_unsupported_module() -> None:


@pytest.mark.parametrize("supported_formats", (True, False))
def test_pilinfo(supported_formats) -> None:
def test_pilinfo(supported_formats: bool) -> None:
buf = io.StringIO()
features.pilinfo(buf, supported_formats=supported_formats)
out = buf.getvalue()
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_bmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_load_dib() -> None:
(124, "g/pal8v5.bmp"),
),
)
def test_dib_header_size(header_size, path):
def test_dib_header_size(header_size: int, path: str) -> None:
image_path = "Tests/images/bmp/" + path
with open(image_path, "rb") as fp:
data = fp.read()[14:]
Expand Down
11 changes: 6 additions & 5 deletions Tests/test_file_bufrstub.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

from pathlib import Path
from typing import IO

import pytest

from PIL import BufrStubImagePlugin, Image
from PIL import BufrStubImagePlugin, Image, ImageFile

from .helper import hopper

Expand Down Expand Up @@ -50,20 +51,20 @@ def test_save(tmp_path: Path) -> None:


def test_handler(tmp_path: Path) -> None:
class TestHandler:
class TestHandler(ImageFile.StubHandler):
opened = False
loaded = False
saved = False

def open(self, im) -> None:
def open(self, im: ImageFile.StubImageFile) -> None:
self.opened = True

def load(self, im):
def load(self, im: ImageFile.StubImageFile) -> Image.Image:
self.loaded = True
im.fp.close()
return Image.new("RGB", (1, 1))

def save(self, im, fp, filename) -> None:
def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
self.saved = True

handler = TestHandler()
Expand Down
9 changes: 6 additions & 3 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def test_closed_file() -> None:

def test_seek_after_close() -> None:
im = Image.open("Tests/images/iss634.gif")
assert isinstance(im, GifImagePlugin.GifImageFile)
im.load()
im.close()

Expand Down Expand Up @@ -377,7 +378,8 @@ def test_save_netpbm_bmp_mode(tmp_path: Path) -> None:
img = img.convert("RGB")

tempfile = str(tmp_path / "temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
b = BytesIO()
GifImagePlugin._save_netpbm(img, b, tempfile)
with Image.open(tempfile) as reloaded:
assert_image_similar(img, reloaded.convert("RGB"), 0)

Expand All @@ -388,7 +390,8 @@ def test_save_netpbm_l_mode(tmp_path: Path) -> None:
img = img.convert("L")

tempfile = str(tmp_path / "temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
b = BytesIO()
GifImagePlugin._save_netpbm(img, b, tempfile)
with Image.open(tempfile) as reloaded:
assert_image_similar(img, reloaded.convert("L"), 0)

Expand Down Expand Up @@ -648,7 +651,7 @@ def test_dispose2_palette(tmp_path: Path) -> None:
assert rgb_img.getpixel((50, 50)) == circle

# Check that frame transparency wasn't added unnecessarily
assert img._frame_transparency is None
assert getattr(img, "_frame_transparency") is None


def test_dispose2_diff(tmp_path: Path) -> None:
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_file_gribstub.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from PIL import GribStubImagePlugin, Image
from PIL import GribStubImagePlugin, Image, ImageFile

from .helper import hopper

Expand Down Expand Up @@ -51,7 +51,7 @@ def test_save(tmp_path: Path) -> None:


def test_handler(tmp_path: Path) -> None:
class TestHandler:
class TestHandler(ImageFile.StubHandler):
opened = False
loaded = False
saved = False
Expand Down
7 changes: 4 additions & 3 deletions Tests/test_file_hdf5stub.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from __future__ import annotations

from io import BytesIO
from pathlib import Path
from typing import IO

import pytest

from PIL import Hdf5StubImagePlugin, Image
from PIL import Hdf5StubImagePlugin, Image, ImageFile

TEST_FILE = "Tests/images/hdf5.h5"

Expand Down Expand Up @@ -41,7 +42,7 @@ def test_load() -> None:
def test_save() -> None:
# Arrange
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_fp = BytesIO()
dummy_filename = "dummy.filename"

# Act / Assert: stub cannot save without an implemented handler
Expand All @@ -52,7 +53,7 @@ def test_save() -> None:


def test_handler(tmp_path: Path) -> None:
class TestHandler:
class TestHandler(ImageFile.StubHandler):
opened = False
loaded = False
saved = False
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def getchannels(im: JpegImagePlugin.JpegImageFile) -> tuple[int, int, int]:
[TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
)
def test_dpi(self, test_image_path: str) -> None:
def test(xdpi: int, ydpi: int | None = None):
def test(xdpi: int, ydpi: int | None = None) -> tuple[int, int] | None:
with Image.open(test_image_path) as im:
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
return im.info.get("dpi")
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_libtiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class TestFileLibTiff(LibTiffTestCase):
def test_version(self) -> None:
version = features.version_codec("libtiff")
assert version is not None
assert re.search(r"\d+\.\d+\.\d+$", version)
assert re.search(r"\d+\.\d+\.\d+t?$", version)

def test_g4_tiff(self, tmp_path: Path) -> None:
"""Test the ordinary file path load path"""
Expand Down
4 changes: 3 additions & 1 deletion Tests/test_file_webp.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ def test_file_pointer_could_be_reused(self) -> None:
(0, (0,), (-1, 0, 1, 2), (253, 254, 255, 256)),
)
@skip_unless_feature("webp_anim")
def test_invalid_background(self, background, tmp_path: Path) -> None:
def test_invalid_background(
self, background: int | tuple[int, ...], tmp_path: Path
) -> None:
temp_file = str(tmp_path / "temp.webp")
im = hopper()
with pytest.raises(OSError):
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_webp_animated.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_write_animation_RGB(tmp_path: Path) -> None:
are visually similar to the originals.
"""

def check(temp_file) -> None:
def check(temp_file: str) -> None:
with Image.open(temp_file) as im:
assert im.n_frames == 2

Expand Down
12 changes: 8 additions & 4 deletions Tests/test_file_wmf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

from pathlib import Path
from typing import IO

import pytest

from PIL import Image, WmfImagePlugin
from PIL import Image, ImageFile, WmfImagePlugin

from .helper import assert_image_similar_tofile, hopper

Expand Down Expand Up @@ -34,10 +35,13 @@ def test_load() -> None:


def test_register_handler(tmp_path: Path) -> None:
class TestHandler:
class TestHandler(ImageFile.StubHandler):
methodCalled = False

def save(self, im, fp, filename) -> None:
def load(self, im: ImageFile.StubImageFile) -> Image.Image:
return Image.new("RGB", (1, 1))

def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
self.methodCalled = True

handler = TestHandler()
Expand Down Expand Up @@ -70,7 +74,7 @@ def test_load_set_dpi() -> None:


@pytest.mark.parametrize("ext", (".wmf", ".emf"))
def test_save(ext, tmp_path: Path) -> None:
def test_save(ext: str, tmp_path: Path) -> None:
im = hopper()

tmpfile = str(tmp_path / ("temp" + ext))
Expand Down
6 changes: 6 additions & 0 deletions Tests/test_image_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ def _test_get_access(self, im: Image.Image) -> None:
caccess = im.im.pixel_access(False)
with pytest.warns(DeprecationWarning):
access = PyAccess.new(im, False)
assert access is not None

w, h = im.size
for x in range(0, w, 10):
Expand Down Expand Up @@ -289,6 +290,7 @@ def _test_set_access(self, im: Image.Image, color: tuple[int, ...] | float) -> N
caccess = im.im.pixel_access(False)
with pytest.warns(DeprecationWarning):
access = PyAccess.new(im, False)
assert access is not None

w, h = im.size
for x in range(0, w, 10):
Expand All @@ -299,6 +301,8 @@ def _test_set_access(self, im: Image.Image, color: tuple[int, ...] | float) -> N
# Attempt to set the value on a read-only image
with pytest.warns(DeprecationWarning):
access = PyAccess.new(im, True)
assert access is not None

with pytest.raises(ValueError):
access[(0, 0)] = color

Expand Down Expand Up @@ -341,6 +345,8 @@ def test_p_putpixel_rgb_rgba(self, mode: str) -> None:
im = Image.new(mode, (1, 1))
with pytest.warns(DeprecationWarning):
access = PyAccess.new(im, False)
assert access is not None

access.putpixel((0, 0), color)

if len(color) == 3:
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_image_rotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ def test_fastpath_translate() -> None:
def test_center() -> None:
im = hopper()
rotate(im, im.mode, 45, center=(0, 0))
rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0))
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0))
rotate(im, im.mode, 45, translate=(im.size[0] // 2, 0))
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] // 2, 0))


def test_rotate_no_fill() -> None:
Expand Down
Loading

0 comments on commit 31a8da4

Please sign in to comment.