Skip to content

Commit fe1ca68

Browse files
authored
Merge branch 'main' into ios-libavif
2 parents c305b54 + 98d6c3b commit fe1ca68

File tree

8 files changed

+82
-31
lines changed

8 files changed

+82
-31
lines changed

Tests/test_features.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ def test_check() -> None:
1818
for codec in features.codecs:
1919
assert features.check_codec(codec) == features.check(codec)
2020
for feature in features.features:
21-
if "webp" in feature:
22-
with pytest.warns(DeprecationWarning, match="webp"):
23-
assert features.check_feature(feature) == features.check(feature)
24-
else:
25-
assert features.check_feature(feature) == features.check(feature)
21+
assert features.check_feature(feature) == features.check(feature)
2622

2723

2824
def test_version() -> None:
@@ -48,11 +44,7 @@ def test(name: str, function: Callable[[str], str | None]) -> None:
4844
for codec in features.codecs:
4945
test(codec, features.version_codec)
5046
for feature in features.features:
51-
if "webp" in feature:
52-
with pytest.warns(DeprecationWarning, match="webp"):
53-
test(feature, features.version_feature)
54-
else:
55-
test(feature, features.version_feature)
47+
test(feature, features.version_feature)
5648

5749

5850
@skip_unless_feature("libjpeg_turbo")
@@ -112,6 +104,25 @@ def test_unsupported_module() -> None:
112104
features.version_module(module)
113105

114106

107+
def test_unsupported_feature() -> None:
108+
# Arrange
109+
feature = "unsupported_feature"
110+
# Act / Assert
111+
with pytest.raises(ValueError):
112+
features.check_feature(feature)
113+
with pytest.raises(ValueError):
114+
features.version_feature(feature)
115+
116+
117+
def test_unsupported_version() -> None:
118+
assert features.version("unsupported_version") is None
119+
120+
121+
def test_modulenotfound(monkeypatch: pytest.MonkeyPatch) -> None:
122+
monkeypatch.setattr(features, "features", {"test": ("PIL._test", "", "")})
123+
assert features.check_feature("test") is None
124+
125+
115126
@pytest.mark.parametrize("supported_formats", (True, False))
116127
def test_pilinfo(supported_formats: bool) -> None:
117128
buf = io.StringIO()

Tests/test_image_access.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,8 @@ def test_embeddable(self) -> None:
317317
assert process.returncode == 0
318318

319319
def teardown_method(self) -> None:
320-
os.remove("embed_pil.c")
320+
try:
321+
os.remove("embed_pil.c")
322+
except FileNotFoundError:
323+
# If the test was skipped or failed, the file won't exist
324+
pass

Tests/test_image_histogram.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ def histogram(mode: str) -> tuple[int, int, int]:
1010

1111
assert histogram("1") == (256, 0, 10994)
1212
assert histogram("L") == (256, 0, 662)
13+
assert histogram("LA") == (512, 0, 16384)
14+
assert histogram("La") == (512, 0, 16384)
1315
assert histogram("I") == (256, 0, 662)
1416
assert histogram("F") == (256, 0, 662)
1517
assert histogram("P") == (256, 0, 1551)
18+
assert histogram("PA") == (512, 0, 16384)
1619
assert histogram("RGB") == (768, 4, 675)
1720
assert histogram("RGBA") == (1024, 0, 16384)
1821
assert histogram("CMYK") == (1024, 0, 16384)

Tests/test_pyroma.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
11
from __future__ import annotations
22

3+
from importlib.metadata import metadata
4+
35
import pytest
46

57
from PIL import __version__
68

79
pyroma = pytest.importorskip("pyroma", reason="Pyroma not installed")
810

911

12+
def map_metadata_keys(metadata):
13+
# Convert installed wheel metadata into canonical Core Metadata 2.4 format.
14+
# This was a utility method in pyroma 4.3.3; it was removed in 5.0.
15+
# This implementation is constructed from the relevant logic from
16+
# Pyroma 5.0's `build_metadata()` implementation. This has been submitted
17+
# upstream to Pyroma as https://github.com/regebro/pyroma/pull/116,
18+
# so it may be possible to simplify this test in future.
19+
data = {}
20+
for key in set(metadata.keys()):
21+
value = metadata.get_all(key)
22+
key = pyroma.projectdata.normalize(key)
23+
24+
if len(value) == 1:
25+
value = value[0]
26+
if value.strip() == "UNKNOWN":
27+
continue
28+
29+
data[key] = value
30+
return data
31+
32+
1033
def test_pyroma() -> None:
1134
# Arrange
12-
data = pyroma.projectdata.get_data(".")
35+
data = map_metadata_keys(metadata("Pillow"))
1336

1437
# Act
1538
rating = pyroma.ratings.rate(data)
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
Python,3.13,3.12,3.11,3.10,3.9,3.8,3.7,3.6,3.5
2-
Pillow >= 11,Yes,Yes,Yes,Yes,Yes,,,,
3-
Pillow 10.1 - 10.4,,Yes,Yes,Yes,Yes,Yes,,,
4-
Pillow 10.0,,,Yes,Yes,Yes,Yes,,,
5-
Pillow 9.3 - 9.5,,,Yes,Yes,Yes,Yes,Yes,,
6-
Pillow 9.0 - 9.2,,,,Yes,Yes,Yes,Yes,,
7-
Pillow 8.3.2 - 8.4,,,,Yes,Yes,Yes,Yes,Yes,
8-
Pillow 8.0 - 8.3.1,,,,,Yes,Yes,Yes,Yes,
9-
Pillow 7.0 - 7.2,,,,,,Yes,Yes,Yes,Yes
1+
Python,3.14,3.13,3.12,3.11,3.10,3.9,3.8,3.7,3.6,3.5
2+
Pillow 12,Yes,Yes,Yes,Yes,Yes,,,,,
3+
Pillow 11,,Yes,Yes,Yes,Yes,Yes,,,,
4+
Pillow 10.1 - 10.4,,,Yes,Yes,Yes,Yes,Yes,,,
5+
Pillow 10.0,,,,Yes,Yes,Yes,Yes,,,
6+
Pillow 9.3 - 9.5,,,,Yes,Yes,Yes,Yes,Yes,,
7+
Pillow 9.0 - 9.2,,,,,Yes,Yes,Yes,Yes,,
8+
Pillow 8.3.2 - 8.4,,,,,Yes,Yes,Yes,Yes,Yes,
9+
Pillow 8.0 - 8.3.1,,,,,,Yes,Yes,Yes,Yes,
10+
Pillow 7.0 - 7.2,,,,,,,Yes,Yes,Yes,Yes

docs/releasenotes/12.0.0.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@ TODO
136136
Other changes
137137
=============
138138

139-
TODO
140-
^^^^
139+
Python 3.14
140+
^^^^^^^^^^^
141141

142-
TODO
142+
Pillow 11.3.0 had wheels built against Python 3.14 beta, available as a preview to help
143+
others prepare for 3.14, and to ensure Pillow could be used immediately at the release
144+
of 3.14.0 final (2025-10-07, :pep:`745`).
145+
146+
Pillow 12.0.0 now officially supports Python 3.14.

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ classifiers = [
2929
"Programming Language :: Python :: 3.11",
3030
"Programming Language :: Python :: 3.12",
3131
"Programming Language :: Python :: 3.13",
32+
"Programming Language :: Python :: 3.14",
3233
"Programming Language :: Python :: Implementation :: CPython",
3334
"Programming Language :: Python :: Implementation :: PyPy",
3435
"Topic :: Multimedia :: Graphics",
@@ -67,7 +68,7 @@ optional-dependencies.tests = [
6768
"markdown2",
6869
"olefile",
6970
"packaging",
70-
"pyroma",
71+
"pyroma>=5",
7172
"pytest",
7273
"pytest-cov",
7374
"pytest-timeout",
@@ -206,7 +207,7 @@ lint.isort.required-imports = [
206207
]
207208

208209
[tool.pyproject-fmt]
209-
max_supported_python = "3.13"
210+
max_supported_python = "3.14"
210211

211212
[tool.pytest.ini_options]
212213
addopts = "-ra --color=auto"

src/libImaging/Histo.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,15 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void *minmax) {
132132
ImagingSectionEnter(&cookie);
133133
for (y = 0; y < im->ysize; y++) {
134134
UINT8 *in = (UINT8 *)im->image[y];
135-
for (x = 0; x < im->xsize; x++) {
136-
h->histogram[(*in++)]++;
137-
h->histogram[(*in++) + 256]++;
138-
h->histogram[(*in++) + 512]++;
139-
h->histogram[(*in++) + 768]++;
135+
for (x = 0; x < im->xsize; x++, in += 4) {
136+
h->histogram[*in]++;
137+
if (im->bands == 2) {
138+
h->histogram[*(in + 3) + 256]++;
139+
} else {
140+
h->histogram[*(in + 1) + 256]++;
141+
h->histogram[*(in + 2) + 512]++;
142+
h->histogram[*(in + 3) + 768]++;
143+
}
140144
}
141145
}
142146
ImagingSectionLeave(&cookie);

0 commit comments

Comments
 (0)