Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/compare-dist-sizes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"""

# /// script
# requires-python = ">=3.10"
# requires-python = ">=3.11"
# dependencies = [
# "humanize",
# "prettytable",
Expand Down
2 changes: 1 addition & 1 deletion .github/generate-sbom.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def upstream_diff_b64(

def generate(version: str) -> dict:
serial = str(uuid.uuid4())
now = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
now = dt.datetime.now(dt.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
purl = f"pkg:pypi/pillow@{version}"
root = Path(__file__).parent.parent
thirdparty = root / "src" / "thirdparty"
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ jobs:
fedora-43-amd64,
fedora-44-amd64,
gentoo,
ubuntu-22.04-jammy-amd64,
ubuntu-24.04-noble-amd64,
ubuntu-26.04-resolute-amd64,
]
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/test-valgrind-memory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ jobs:
fail-fast: false
matrix:
docker: [
ubuntu-22.04-jammy-amd64-valgrind,
ubuntu-24.04-noble-amd64-valgrind,
]
dockerTag: [main]
split: [1, 2, 3, 4]

name: ${{ matrix.docker }}
name: ${{ matrix.docker }} ${{ matrix.split }}

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand All @@ -60,5 +61,5 @@ jobs:
run: |
# The Pillow user in the docker container is UID 1001
sudo chown -R 1001 $GITHUB_WORKSPACE
docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} /Pillow/depends/docker-test-valgrind-memory.sh
docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -e "SPLIT_COUNT=4" -e "SPLIT_INDEX=${{ matrix.split }}" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} /Pillow/depends/docker-test-valgrind-memory.sh
sudo chown -R runner $GITHUB_WORKSPACE
7 changes: 4 additions & 3 deletions .github/workflows/test-valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ jobs:
fail-fast: false
matrix:
docker: [
ubuntu-22.04-jammy-amd64-valgrind,
ubuntu-24.04-noble-amd64-valgrind,
]
dockerTag: [main]
split: [1, 2, 3, 4]

name: ${{ matrix.docker }}
name: ${{ matrix.docker }} ${{ matrix.split }}

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Expand All @@ -54,5 +55,5 @@ jobs:
run: |
# The Pillow user in the docker container is UID 1001
sudo chown -R 1001 $GITHUB_WORKSPACE
docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -e "SPLIT_COUNT=4" -e "SPLIT_INDEX=${{ matrix.split }}" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
sudo chown -R runner $GITHUB_WORKSPACE
4 changes: 2 additions & 2 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["pypy3.11", "3.11", "3.12", "3.13", "3.14", "3.15"]
python-version: ["pypy3.11", "3.12", "3.13", "3.14", "3.15"]
architecture: ["x64"]
os: ["windows-latest"]
include:
# Test the oldest Python on 32-bit
- { python-version: "3.10", architecture: "x86", os: "windows-2022" }
- { python-version: "3.11", architecture: "x86", os: "windows-2022" }

timeout-minutes: 45

Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@ jobs:
"3.13",
"3.12",
"3.11",
"3.10",
]
include:
- { python-version: "3.12", PYTHONOPTIMIZE: 1, REVERSE: "--reverse" }
- { python-version: "3.11", PYTHONOPTIMIZE: 2 }
- { python-version: "3.13", PYTHONOPTIMIZE: 1, REVERSE: "--reverse" }
- { python-version: "3.12", PYTHONOPTIMIZE: 2 }
# Intel
- { os: "macos-26-intel", python-version: "3.10" }
- { os: "macos-26-intel", python-version: "3.11" }
exclude:
- { os: "macos-latest", python-version: "3.10" }
- { os: "macos-latest", python-version: "3.11" }

runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ concurrency:
cancel-in-progress: true

env:
EXPECTED_DISTS: 87
EXPECTED_DISTS: 78
FORCE_COLOR: 1

jobs:
Expand Down Expand Up @@ -81,7 +81,7 @@ jobs:
platform: macos
os: macos-26-intel
cibw_arch: x86_64
build: "cp3{10,11}*"
build: "cp311*"
macosx_deployment_target: "10.10"
- name: "macOS 10.13 x86_64"
platform: macos
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ valgrind-leak:
PILLOW_VALGRIND_TEST=true PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp \
--leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \
--log-file=/tmp/valgrind-output \
python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output
python3 -m pytest -vv --valgrind --valgrind-log=/tmp/valgrind-output $(PYTEST_ARGS)

.PHONY: readme
readme:
Expand Down
8 changes: 3 additions & 5 deletions Tests/test_bmp_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ def test_bad() -> None:
either"""
for f in get_files("b"):
# Assert that there is no unclosed file warning
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
try:
with Image.open(f) as im:
im.load()
Expand Down Expand Up @@ -56,7 +54,7 @@ def test_questionable() -> None:
im.load()
if os.path.basename(f) not in supported:
print(f"Please add {f} to the partially supported bmp specs.")
except Exception: # noqa: PERF203
except Exception:
if os.path.basename(f) in supported:
raise

Expand Down Expand Up @@ -106,7 +104,7 @@ def get_compare(f: str) -> str:

assert_image_similar(im_converted, compare_converted, 5)

except Exception as msg: # noqa: PERF203
except Exception as msg:
# there are three here that are unsupported:
unsupported = (
os.path.join(base, "g", "rgb32bf.bmp"),
Expand Down
8 changes: 3 additions & 5 deletions Tests/test_file_avif.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,7 @@ def finish(self) -> None:

def test_no_resource_warning(self, tmp_path: Path) -> None:
with Image.open(TEST_AVIF_FILE) as im:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im.save(tmp_path / "temp.avif")

@pytest.mark.parametrize("major_brand", [b"avif", b"avis", b"mif1", b"msf1"])
Expand Down Expand Up @@ -603,7 +601,7 @@ def test_svt_optimizations(self, tmp_path: Path) -> None:
@skip_unless_feature("avif")
class TestAvifAnimation:
@contextmanager
def star_frames(self) -> Generator[list[Image.Image], None, None]:
def star_frames(self) -> Generator[list[Image.Image]]:
with Image.open("Tests/images/avif/star.png") as f:
yield [f, f.rotate(90), f.rotate(180), f.rotate(270)]

Expand Down Expand Up @@ -676,7 +674,7 @@ def check(temp_file: Path) -> None:
# Test appending using a generator
def imGenerator(
ims: list[Image.Image],
) -> Generator[Image.Image, None, None]:
) -> Generator[Image.Image]:
yield from ims

temp_file2 = tmp_path / "temp_generator.avif"
Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_dcx.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,14 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(TEST_FILE)
im.load()
im.close()


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(TEST_FILE) as im:
im.load()

Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_fli.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(static_test_file)
im.load()
im.close()
Expand All @@ -91,9 +89,7 @@ def test_seek_after_close() -> None:


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(static_test_file) as im:
im.load()

Expand Down
10 changes: 3 additions & 7 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(TEST_GIF)
im.load()
im.close()
Expand All @@ -66,9 +64,7 @@ def test_seek_after_close() -> None:


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(TEST_GIF) as im:
im.load()

Expand Down Expand Up @@ -1191,7 +1187,7 @@ def test_append_images(tmp_path: Path) -> None:
assert reread.n_frames == 3

# Tests appending using a generator
def im_generator(ims: list[Image.Image]) -> Generator[Image.Image, None, None]:
def im_generator(ims: list[Image.Image]) -> Generator[Image.Image]:
yield from ims

im.save(out, save_all=True, append_images=im_generator(ims))
Expand Down
4 changes: 1 addition & 3 deletions Tests/test_file_icns.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ def test_sanity() -> None:
# (512x512@2x) being loaded
with Image.open(TEST_FILE) as im:
# Assert that there is no unclosed file warning
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im.load()

assert im.mode == "RGBA"
Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_im.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,14 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(TEST_IM)
im.load()
im.close()


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(TEST_IM) as im:
im.load()

Expand Down
4 changes: 1 addition & 3 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -880,9 +880,7 @@ def test_exif_x_resolution(self, tmp_path: Path) -> None:
assert exif[282] == 180

out = tmp_path / "out.jpg"
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im.save(out, exif=exif)

with Image.open(out) as reloaded:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@


@pytest.fixture
def card() -> Generator[ImageFile.ImageFile, None, None]:
def card() -> Generator[ImageFile.ImageFile]:
with Image.open("Tests/images/test-card.png") as im:
im.load()
try:
Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_mpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(test_files[0])
im.load()
im.close()
Expand All @@ -76,9 +74,7 @@ def test_seek_after_close() -> None:


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(test_files[0]) as im:
im.load()

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def test_save_all(tmp_path: Path) -> None:
assert os.path.getsize(outfile) > 0

# Test appending using a generator
def im_generator(ims: list[Image.Image]) -> Generator[Image.Image, None, None]:
def im_generator(ims: list[Image.Image]) -> Generator[Image.Image]:
yield from ims

im.save(outfile, save_all=True, append_images=im_generator(ims))
Expand Down
4 changes: 1 addition & 3 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,7 @@ def test_load_verify(self) -> None:

with Image.open(TEST_PNG_FILE) as im:
# Assert that there is no unclosed file warning
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im.verify()

with Image.open(TEST_PNG_FILE) as im:
Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_psd.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,14 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(test_file)
im.load()
im.close()


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(test_file) as im:
im.load()

Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_spider.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,14 @@ def open_test_image() -> None:


def test_closed_file() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
im = Image.open(TEST_FILE)
im.load()
im.close()


def test_context_manager() -> None:
with warnings.catch_warnings():
warnings.simplefilter("error")

with warnings.catch_warnings(action="error"):
with Image.open(TEST_FILE) as im:
im.load()

Expand Down
Loading
Loading