Skip to content

Commit

Permalink
Merge branch 'main' into bugreport
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere authored Mar 2, 2024
2 parents ca63a12 + 2bd5426 commit 01fdf2f
Show file tree
Hide file tree
Showing 49 changed files with 239 additions and 127 deletions.
1 change: 1 addition & 0 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ init:
# Uncomment previous line to get RDP access during the build.

environment:
COVERAGE_CORE: sysmon
EXECUTABLE: python.exe
TEST_OPTIONS:
DEPLOY: YES
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ on:
paths:
- ".github/workflows/docs.yml"
- "docs/**"
- "src/PIL/**"
pull_request:
paths:
- ".github/workflows/docs.yml"
- "docs/**"
- "src/PIL/**"
workflow_dispatch:

permissions:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/test-cygwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
COVERAGE_CORE: sysmon

jobs:
build:
runs-on: windows-latest
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/test-mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
COVERAGE_CORE: sysmon

jobs:
build:
runs-on: windows-latest
Expand Down Expand Up @@ -64,10 +67,10 @@ jobs:
mingw-w64-x86_64-python3-cffi \
mingw-w64-x86_64-python3-numpy \
mingw-w64-x86_64-python3-olefile \
mingw-w64-x86_64-python3-pip \
mingw-w64-x86_64-python3-setuptools \
mingw-w64-x86_64-python-pyqt6
python3 -m ensurepip
python3 -m pip install pyroma pytest pytest-cov pytest-timeout
pushd depends && ./install_extra_test_images.sh && popd
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
COVERAGE_CORE: sysmon

jobs:
build:
runs-on: windows-latest
Expand Down Expand Up @@ -66,8 +69,16 @@ jobs:
- name: Print build system information
run: python3 .github/workflows/system-info.py

- name: python3 -m pip install pytest pytest-cov pytest-timeout defusedxml olefile pyroma
run: python3 -m pip install pytest pytest-cov pytest-timeout defusedxml olefile pyroma
- name: Install Python dependencies
run: >
python3 -m pip install
coverage>=7.4.2
defusedxml
olefile
pyroma
pytest
pytest-cov
pytest-timeout
- name: Install dependencies
id: install
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ concurrency:
cancel-in-progress: true

env:
COVERAGE_CORE: sysmon
FORCE_COLOR: 1

jobs:
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/wheels-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ FREETYPE_VERSION=2.13.2
HARFBUZZ_VERSION=8.3.0
LIBPNG_VERSION=1.6.40
JPEGTURBO_VERSION=3.0.1
OPENJPEG_VERSION=2.5.0
OPENJPEG_VERSION=2.5.2
XZ_VERSION=5.4.5
TIFF_VERSION=4.6.0
LCMS2_VERSION=2.16
Expand All @@ -40,7 +40,7 @@ BROTLI_VERSION=1.1.0

if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "x86_64" ]]; then
function build_openjpeg {
local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz openjpeg-2.5.0.tar.gz)
local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz openjpeg-${OPENJPEG_VERSION}.tar.gz)
(cd $out_dir \
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
&& make install)
Expand Down Expand Up @@ -93,6 +93,9 @@ function build {
done
fi
build_openjpeg
if [ -f /usr/local/lib64/libopenjp2.so ]; then
cp /usr/local/lib64/libopenjp2.so /usr/local/lib
fi

ORIGINAL_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -O3 -DNDEBUG"
Expand Down
12 changes: 12 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ Changelog (Pillow)
10.3.0 (unreleased)
-------------------

- Handle truncated chunks at the end of PNG images #7709
[lajiyuan, radarhere]

- Match mask size to pasted image size in GifImagePlugin #7779
[radarhere]

- Release GIL while calling ``WebPAnimDecoderGetNext`` #7782
[evanmiller, radarhere]

- Fixed reading FLI/FLC images with a prefix chunk #7804
[twolife]

- Update wl-paste handling and return None for some errors in grabclipboard() on Linux #7745
[nik012003, radarhere]

Expand Down
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ As of 2019, Pillow development is
<a href="https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img
alt="Join the chat at https://gitter.im/python-pillow/Pillow"
src="https://badges.gitter.im/python-pillow/Pillow.svg"></a>
<a href="https://twitter.com/PythonPillow"><img
alt="Follow on https://twitter.com/PythonPillow"
src="https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg"></a>
<a href="https://fosstodon.org/@pillow"><img
alt="Follow on https://fosstodon.org/@pillow"
src="https://img.shields.io/badge/publish-on%20Mastodon-595aff.svg"
Expand Down
2 changes: 1 addition & 1 deletion RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Released as needed privately to individual vendors for critical security-related

## Publicize Release

* [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) and [Mastodon](https://fosstodon.org/@pillow) e.g. https://twitter.com/PythonPillow/status/1013789184354603010
* [ ] Announce release availability via [Mastodon](https://fosstodon.org/@pillow) e.g. https://fosstodon.org/@pillow/110639450470725321

## Documentation

Expand Down
Binary file added Tests/images/2422.flc
Binary file not shown.
Binary file added Tests/images/truncated_end_chunk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions Tests/test_deprecate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
),
],
)
def test_version(version, expected) -> None:
def test_version(version: int | None, expected: str) -> None:
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", version, "new thing")

Expand All @@ -46,7 +46,7 @@ def test_unknown_version() -> None:
),
],
)
def test_old_version(deprecated, plural, expected) -> None:
def test_old_version(deprecated: str, plural: bool, expected: str) -> None:
expected = r""
with pytest.raises(RuntimeError, match=expected):
_deprecate.deprecate(deprecated, 1, plural=plural)
Expand Down Expand Up @@ -76,7 +76,7 @@ def test_replacement_and_action() -> None:
"Upgrade to new thing.",
],
)
def test_action(action) -> None:
def test_action(action: str) -> None:
expected = (
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
r"Upgrade to new thing\."
Expand Down
41 changes: 10 additions & 31 deletions Tests/test_file_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,16 @@ def test_isatty() -> None:
assert container.isatty() is False


def test_seek_mode_0() -> None:
@pytest.mark.parametrize(
"mode, expected_value",
(
(0, 33),
(1, 66),
(2, 100),
),
)
def test_seek_mode(mode: int, expected_value: int) -> None:
# Arrange
mode = 0
with open(TEST_FILE, "rb") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100)

Expand All @@ -32,35 +39,7 @@ def test_seek_mode_0() -> None:
container.seek(33, mode)

# Assert
assert container.tell() == 33


def test_seek_mode_1() -> None:
# Arrange
mode = 1
with open(TEST_FILE, "rb") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100)

# Act
container.seek(33, mode)
container.seek(33, mode)

# Assert
assert container.tell() == 66


def test_seek_mode_2() -> None:
# Arrange
mode = 2
with open(TEST_FILE, "rb") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100)

# Act
container.seek(33, mode)
container.seek(33, mode)

# Assert
assert container.tell() == 100
assert container.tell() == expected_value


@pytest.mark.parametrize("bytesmode", (True, False))
Expand Down
25 changes: 23 additions & 2 deletions Tests/test_file_fli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@

import pytest

from PIL import FliImagePlugin, Image
from PIL import FliImagePlugin, Image, ImageFile

from .helper import assert_image_equal, assert_image_equal_tofile, is_pypy

# created as an export of a palette image from Gimp2.6
# save as...-> hopper.fli, default options.
static_test_file = "Tests/images/hopper.fli"

# From https://samples.libav.org/fli-flc/
# From https://samples.ffmpeg.org/fli-flc/
animated_test_file = "Tests/images/a.fli"

# From https://samples.ffmpeg.org/fli-flc/
animated_test_file_with_prefix_chunk = "Tests/images/2422.flc"


def test_sanity() -> None:
with Image.open(static_test_file) as im:
Expand All @@ -32,6 +35,24 @@ def test_sanity() -> None:
assert im.is_animated


def test_prefix_chunk() -> None:
ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
with Image.open(animated_test_file_with_prefix_chunk) as im:
assert im.mode == "P"
assert im.size == (320, 200)
assert im.format == "FLI"
assert im.info["duration"] == 171
assert im.is_animated

palette = im.getpalette()
assert palette[3:6] == [255, 255, 255]
assert palette[381:384] == [204, 204, 12]
assert palette[765:] == [252, 0, 0]
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False


@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file() -> None:
def open() -> None:
Expand Down
15 changes: 15 additions & 0 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,21 @@ def im_generator(ims: list[Image.Image]) -> Generator[Image.Image, None, None]:
assert reread.n_frames == 10


def test_append_different_size_image(tmp_path: Path) -> None:
out = str(tmp_path / "temp.gif")

im = Image.new("RGB", (100, 100))
bigger_im = Image.new("RGB", (200, 200), "#f00")

im.save(out, save_all=True, append_images=[bigger_im])

with Image.open(out) as reread:
assert reread.size == (100, 100)

reread.seek(1)
assert reread.size == (100, 100)


def test_transparent_optimize(tmp_path: Path) -> None:
# From issue #2195, if the transparent color is incorrectly optimized out, GIF loses
# transparency.
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_ico.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def test_different_bit_depths(tmp_path: Path) -> None:


@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA"))
def test_save_to_bytes_bmp(mode) -> None:
def test_save_to_bytes_bmp(mode: str) -> None:
output = io.BytesIO()
im = hopper(mode)
im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)])
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_iptc.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_i() -> None:
assert ret == 97


def test_dump(monkeypatch) -> None:
def test_dump(monkeypatch: pytest.MonkeyPatch) -> None:
# Arrange
c = b"abc"
# Temporarily redirect stdout
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_msp.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_open_windows_v1() -> None:
assert isinstance(im, MspImagePlugin.MspImageFile)


def _assert_file_image_equal(source_path, target_path) -> None:
def _assert_file_image_equal(source_path: str, target_path: str) -> None:
with Image.open(source_path) as im:
assert_image_equal_tofile(im, target_path)

Expand Down
14 changes: 14 additions & 0 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import zlib
from io import BytesIO
from pathlib import Path
from types import ModuleType
from typing import Any

import pytest
Expand All @@ -23,6 +24,7 @@
skip_unless_feature,
)

ElementTree: ModuleType | None
try:
from defusedxml import ElementTree
except ImportError:
Expand Down Expand Up @@ -781,6 +783,18 @@ class MyStdOut:
with Image.open(mystdout) as reloaded:
assert_image_equal_tofile(reloaded, TEST_PNG_FILE)

def test_truncated_end_chunk(self) -> None:
with Image.open("Tests/images/truncated_end_chunk.png") as im:
with pytest.raises(OSError):
im.load()

ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
with Image.open("Tests/images/truncated_end_chunk.png") as im:
assert_image_equal_tofile(im, "Tests/images/hopper.png")
finally:
ImageFile.LOAD_TRUNCATED_IMAGES = False


@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
@skip_unless_feature("zlib")
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_psd.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def test_combined_larger_than_size() -> None:
("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError),
],
)
def test_crashes(test_file, raises) -> None:
def test_crashes(test_file: str, raises) -> None:
with open(test_file, "rb") as f:
with pytest.raises(raises):
with Image.open(f):
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_file_tga.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@


@pytest.mark.parametrize("mode", _MODES)
def test_sanity(mode, tmp_path: Path) -> None:
def roundtrip(original_im) -> None:
def test_sanity(mode: str, tmp_path: Path) -> None:
def roundtrip(original_im: Image.Image) -> None:
out = str(tmp_path / "temp.tga")

original_im.save(out, rle=rle)
Expand Down
Loading

0 comments on commit 01fdf2f

Please sign in to comment.