diff --git a/.ci/requirements-cibw.txt b/.ci/requirements-cibw.txt index a2bf2a7b0..b8e6c3947 100644 --- a/.ci/requirements-cibw.txt +++ b/.ci/requirements-cibw.txt @@ -1 +1 @@ -cibuildwheel==2.19.2 +cibuildwheel==2.20.0 diff --git a/.ci/requirements-mypy.txt b/.ci/requirements-mypy.txt index 776bb0dbb..23792281b 100644 --- a/.ci/requirements-mypy.txt +++ b/.ci/requirements-mypy.txt @@ -1 +1,10 @@ -mypy==1.11.0 +mypy==1.11.1 +IceSpringPySideStubs-PyQt6 +IceSpringPySideStubs-PySide6 +ipython +numpy +packaging +pytest +types-defusedxml +types-olefile +types-setuptools diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 659409de4..74764752e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.0 + rev: v0.5.6 hooks: - id: ruff args: [--exit-non-zero-on-fix] @@ -50,7 +50,7 @@ repos: exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/ - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.6 + rev: 0.29.1 hooks: - id: check-github-workflows - id: check-readthedocs @@ -62,7 +62,7 @@ repos: - id: sphinx-lint - repo: https://github.com/tox-dev/pyproject-fmt - rev: 2.1.3 + rev: 2.2.1 hooks: - id: pyproject-fmt diff --git a/CHANGES.rst b/CHANGES.rst index bd8d3af03..ae995e0a0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,18 @@ Changelog (Pillow) 11.0.0 (unreleased) ------------------- +- Remove all WITH_* flags from _imaging.c and other flags #8211 + [homm] + +- Improve ImageDraw2 shape methods #8265 + [radarhere] + +- Lock around usages of imaging memory arenas #8238 + [lysnikolaou] + +- Deprecate JpegImageFile huffman_ac and huffman_dc #8274 + [radarhere] + - Deprecate ImageMath lambda_eval and unsafe_eval options argument #8242 [radarhere] diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index 574ccd124..4b083d689 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -106,101 +106,68 @@ class TestColorLut3DCoreAPI: with pytest.raises(TypeError): im.im.color_lut_3d("RGB", Image.Resampling.BILINEAR, 3, 2, 2, 2, 16) - def test_correct_args(self) -> None: - im = Image.new("RGB", (10, 10), 0) - assert im.im is not None - - im.im.color_lut_3d( - "RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - im.im.color_lut_3d( - "CMYK", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) - ) - - im.im.color_lut_3d( - "RGB", - Image.Resampling.BILINEAR, - *self.generate_identity_table(3, (2, 3, 3)), - ) - - im.im.color_lut_3d( - "RGB", - Image.Resampling.BILINEAR, - *self.generate_identity_table(3, (65, 3, 3)), - ) - - im.im.color_lut_3d( - "RGB", - Image.Resampling.BILINEAR, - *self.generate_identity_table(3, (3, 65, 3)), - ) - - im.im.color_lut_3d( - "RGB", - Image.Resampling.BILINEAR, - *self.generate_identity_table(3, (3, 3, 65)), - ) - - def test_wrong_mode(self) -> None: - with pytest.raises(ValueError, match="wrong mode"): - im = Image.new("L", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - with pytest.raises(ValueError, match="wrong mode"): - im = Image.new("RGB", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "L", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - with pytest.raises(ValueError, match="wrong mode"): - im = Image.new("L", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "L", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - with pytest.raises(ValueError, match="wrong mode"): - im = Image.new("RGB", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - with pytest.raises(ValueError, match="wrong mode"): - im = Image.new("RGB", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) - ) - - def test_correct_mode(self) -> None: - im = Image.new("RGBA", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) - ) - - im = Image.new("RGBA", (10, 10), 0) - assert im.im is not None - im.im.color_lut_3d( - "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) - ) - + @pytest.mark.parametrize( + "lut_mode, table_channels, table_size", + [ + ("RGB", 3, 3), + ("CMYK", 4, 3), + ("RGB", 3, (2, 3, 3)), + ("RGB", 3, (65, 3, 3)), + ("RGB", 3, (3, 65, 3)), + ("RGB", 3, (2, 3, 65)), + ], + ) + def test_correct_args( + self, lut_mode: str, table_channels: int, table_size: int | tuple[int, int, int] + ) -> None: im = Image.new("RGB", (10, 10), 0) assert im.im is not None im.im.color_lut_3d( - "HSV", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) + lut_mode, + Image.Resampling.BILINEAR, + *self.generate_identity_table(table_channels, table_size), ) - im = Image.new("RGB", (10, 10), 0) + @pytest.mark.parametrize( + "image_mode, lut_mode, table_channels, table_size", + [ + ("L", "RGB", 3, 3), + ("RGB", "L", 3, 3), + ("L", "L", 3, 3), + ("RGB", "RGBA", 3, 3), + ("RGB", "RGB", 4, 3), + ], + ) + def test_wrong_mode( + self, image_mode: str, lut_mode: str, table_channels: int, table_size: int + ) -> None: + with pytest.raises(ValueError, match="wrong mode"): + im = Image.new(image_mode, (10, 10), 0) + assert im.im is not None + im.im.color_lut_3d( + lut_mode, + Image.Resampling.BILINEAR, + *self.generate_identity_table(table_channels, table_size), + ) + + @pytest.mark.parametrize( + "image_mode, lut_mode, table_channels, table_size", + [ + ("RGBA", "RGBA", 3, 3), + ("RGBA", "RGBA", 4, 3), + ("RGB", "HSV", 3, 3), + ("RGB", "RGBA", 4, 3), + ], + ) + def test_correct_mode( + self, image_mode: str, lut_mode: str, table_channels: int, table_size: int + ) -> None: + im = Image.new(image_mode, (10, 10), 0) assert im.im is not None im.im.color_lut_3d( - "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) + lut_mode, + Image.Resampling.BILINEAR, + *self.generate_identity_table(table_channels, table_size), ) def test_identities(self) -> None: diff --git a/Tests/test_file_dds.py b/Tests/test_file_dds.py index ebc0e89a1..9a826ebe8 100644 --- a/Tests/test_file_dds.py +++ b/Tests/test_file_dds.py @@ -152,7 +152,7 @@ def test_sanity_ati2_bc5u(image_path: str) -> None: @pytest.mark.parametrize( - ("image_path", "expected_path"), + "image_path, expected_path", ( # hexeditted to be typeless (TEST_FILE_DX10_BC5_TYPELESS, TEST_FILE_DX10_BC5_UNORM), @@ -248,7 +248,7 @@ def test_dx10_r8g8b8a8_unorm_srgb() -> None: @pytest.mark.parametrize( - ("mode", "size", "test_file"), + "mode, size, test_file", [ ("L", (128, 128), TEST_FILE_UNCOMPRESSED_L), ("LA", (128, 128), TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA), @@ -373,7 +373,7 @@ def test_save_unsupported_mode(tmp_path: Path) -> None: @pytest.mark.parametrize( - ("mode", "test_file"), + "mode, test_file", [ ("L", "Tests/images/linear_gradient.png"), ("LA", "Tests/images/uncompressed_la.png"), diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index b54238132..d54deb515 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -80,9 +80,7 @@ simple_eps_file_with_long_binary_data = ( @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") -@pytest.mark.parametrize( - ("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252))) -) +@pytest.mark.parametrize("filename, size", ((FILE1, (460, 352)), (FILE2, (360, 252)))) @pytest.mark.parametrize("scale", (1, 2)) def test_sanity(filename: str, size: tuple[int, int], scale: int) -> None: expected_size = tuple(s * scale for s in size) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 854c79dae..bb30b462d 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -230,7 +230,7 @@ class TestImagePutPixelError: im.putpixel((0, 0), v) # type: ignore[arg-type] @pytest.mark.parametrize( - ("mode", "band_numbers", "match"), + "mode, band_numbers, match", ( ("L", (0, 2), "color must be int or single-element tuple"), ("LA", (0, 3), "color must be int, or tuple of one or two elements"), diff --git a/Tests/test_pickle.py b/Tests/test_pickle.py index ed415953f..be143e9c6 100644 --- a/Tests/test_pickle.py +++ b/Tests/test_pickle.py @@ -46,7 +46,7 @@ def helper_pickle_string(protocol: int, test_file: str, mode: str | None) -> Non @pytest.mark.parametrize( - ("test_file", "test_mode"), + "test_file, test_mode", [ ("Tests/images/hopper.jpg", None), ("Tests/images/hopper.jpg", "L"), diff --git a/pyproject.toml b/pyproject.toml index 0940664f3..8bb21019c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,6 +109,7 @@ lint.select = [ "ISC", # flake8-implicit-str-concat "LOG", # flake8-logging "PGH", # pygrep-hooks + "PT006", # pytest-parametrize-names-wrong-type "PYI", # flake8-pyi "RUF100", # unused noqa (yesqa) "UP", # pyupgrade @@ -129,6 +130,7 @@ lint.per-file-ignores."Tests/oss-fuzz/fuzz_font.py" = [ lint.per-file-ignores."Tests/oss-fuzz/fuzz_pillow.py" = [ "I002", ] +lint.flake8-pytest-style.parametrize-names-type = "csv" lint.isort.known-first-party = [ "PIL", ] diff --git a/src/_imagingft.c b/src/_imagingft.c index da03e3ba9..f8143e0cc 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -1243,7 +1243,7 @@ font_getvarnames(FontObject *self) { return PyErr_NoMemory(); } - for (int i = 0; i < num_namedstyles; i++) { + for (unsigned int i = 0; i < num_namedstyles; i++) { list_names_filled[i] = 0; } diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index 595ee42a0..55b5e7a55 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -308,11 +308,10 @@ mergesort_pixels(PixelList *head, int i) { #ifdef DEBUG static int test_sorted(PixelList *pl[3]) { - int i, n, l; + int i, l; PixelList *t; for (i = 0; i < 3; i++) { - n = 0; l = 256; for (t = pl[i]; t; t = t->next[i]) { if (l < t->p.a.v[i]) diff --git a/tox.ini b/tox.ini index c1bc3b17d..4b4059455 100644 --- a/tox.ini +++ b/tox.ini @@ -33,15 +33,6 @@ commands = skip_install = true deps = -r .ci/requirements-mypy.txt - IceSpringPySideStubs-PyQt6 - IceSpringPySideStubs-PySide6 - ipython - numpy - packaging - pytest - types-defusedxml - types-olefile - types-setuptools extras = typing commands =