From 0c2dc2047edcd69a29445b7c91a75dfe0b85f3eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 17:25:35 +0000 Subject: [PATCH 1/3] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.14 → v0.15.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.14...v0.15.4) - [github.com/PyCQA/bandit: 1.9.3 → 1.9.4](https://github.com/PyCQA/bandit/compare/1.9.3...1.9.4) - [github.com/pre-commit/mirrors-clang-format: v21.1.8 → v22.1.0](https://github.com/pre-commit/mirrors-clang-format/compare/v21.1.8...v22.1.0) - [github.com/python-jsonschema/check-jsonschema: 0.36.1 → 0.37.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.36.1...0.37.0) - [github.com/tox-dev/pyproject-fmt: v2.12.1 → v2.16.2](https://github.com/tox-dev/pyproject-fmt/compare/v2.12.1...v2.16.2) - [github.com/abravalheri/validate-pyproject: v0.24.1 → v0.25](https://github.com/abravalheri/validate-pyproject/compare/v0.24.1...v0.25) --- .pre-commit-config.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 19be90c1610..53fd0a3ca59 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.14.14 + rev: v0.15.4 hooks: - id: ruff-check args: [--exit-non-zero-on-fix] @@ -11,7 +11,7 @@ repos: - id: black - repo: https://github.com/PyCQA/bandit - rev: 1.9.3 + rev: 1.9.4 hooks: - id: bandit args: [--severity-level=high] @@ -24,7 +24,7 @@ repos: exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$) - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v21.1.8 + rev: v22.1.0 hooks: - id: clang-format types: [c] @@ -52,7 +52,7 @@ repos: exclude: ^\.github/.*TEMPLATE|^Tests/(fonts|images)/ - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.36.1 + rev: 0.37.0 hooks: - id: check-github-workflows - id: check-readthedocs @@ -69,12 +69,12 @@ repos: - id: sphinx-lint - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.12.1 + rev: v2.16.2 hooks: - id: pyproject-fmt - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.24.1 + rev: v0.25 hooks: - id: validate-pyproject additional_dependencies: [trove-classifiers>=2024.10.12] From 7fc49a5cf413833d14c857d5829cd908d09ec7b6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 17:27:42 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyproject.toml | 60 ++++++++--------------- src/Tk/tkImaging.c | 6 ++- src/encode.c | 5 +- src/libImaging/Arrow.c | 90 ++++++++++++++++++----------------- src/libImaging/Convert.c | 14 ++++-- src/libImaging/Draw.c | 11 +++-- src/libImaging/GetBBox.c | 10 ++-- src/libImaging/Jpeg2KEncode.c | 6 ++- src/libImaging/JpegDecode.c | 6 ++- src/libImaging/Matrix.c | 5 +- 10 files changed, 106 insertions(+), 107 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 91f4750e46a..4b969dbc426 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,6 @@ optional-dependencies.test-arrow = [ "nanoarrow", "pyarrow", ] - optional-dependencies.tests = [ "check-manifest", "coverage>=7.4.2", @@ -77,16 +76,15 @@ optional-dependencies.tests = [ "pytest-xdist", "trove-classifiers>=2024.10.12", ] - optional-dependencies.xmp = [ "defusedxml", ] +urls."Release notes" = "https://pillow.readthedocs.io/en/stable/releasenotes/index.html" urls.Changelog = "https://github.com/python-pillow/Pillow/releases" urls.Documentation = "https://pillow.readthedocs.io" urls.Funding = "https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=pypi" urls.Homepage = "https://python-pillow.github.io" urls.Mastodon = "https://fosstodon.org/@pillow" -urls."Release notes" = "https://pillow.readthedocs.io/en/stable/releasenotes/index.html" urls.Source = "https://github.com/python-pillow/Pillow" [tool.setuptools] @@ -95,70 +93,50 @@ packages = [ ] include-package-data = true package-dir = { "" = "src" } - -[tool.setuptools.dynamic] -version = { attr = "PIL.__version__" } +dynamic.version = { attr = "PIL.__version__" } [tool.cibuildwheel] before-all = ".github/workflows/wheels-dependencies.sh" build-verbosity = 1 - config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable" - test-command = "cd {project} && .github/workflows/wheels-test.sh" test-extras = "tests" test-requires = [ "numpy", ] -xbuild-tools = [ ] - -[tool.cibuildwheel.ios] +xbuild-tools = [] # Disable platform guessing on iOS, and disable raqm (since there won't be a # vendor version, and we can't distribute it due to licensing) -config-settings = "raqm=disable imagequant=disable platform-guessing=disable" - +ios.config-settings = "raqm=disable imagequant=disable platform-guessing=disable" # iOS needs to be given a specific pytest invocation and list of test sources. -test-sources = [ +ios.test-sources = [ "checks", "Tests", "selftest.py", ] -test-command = [ +ios.test-command = [ "python -m selftest", "python -m pytest -vv -x -W always checks/check_wheel.py Tests", ] - # There's no numpy wheel for iOS (yet...) -test-requires = [ ] - -[tool.cibuildwheel.macos] +ios.test-requires = [] # Disable platform guessing on macOS to avoid picking up Homebrew etc. -config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable platform-guessing=disable" - -[tool.cibuildwheel.macos.environment] +macos.config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable platform-guessing=disable" # Isolate macOS build environment from Homebrew etc. -PATH = "$(pwd)/build/deps/darwin/bin:$(dirname $(which python3)):/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" - -[[tool.cibuildwheel.overrides]] -# iOS environment is isolated by cibuildwheel, but needs the dependencies -select = "*_iphoneos" -environment.PATH = "$(pwd)/build/deps/iphoneos/bin:$PATH" - -[[tool.cibuildwheel.overrides]] -# iOS simulator environment is isolated by cibuildwheel, but needs the dependencies -select = "*_iphonesimulator" -environment.PATH = "$(pwd)/build/deps/iphonesimulator/bin:$PATH" - -[[tool.cibuildwheel.overrides]] -select = "*-win32" -test-requires = [ ] +macos.environment.PATH = "$(pwd)/build/deps/darwin/bin:$(dirname $(which python3)):/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" +overrides = [ + # iOS environment is isolated by cibuildwheel, but needs the dependencies + { select = "*_iphoneos", environment.PATH = "$(pwd)/build/deps/iphoneos/bin:$PATH" }, + # iOS simulator environment is isolated by cibuildwheel, but needs the dependencies + { select = "*_iphonesimulator", environment.PATH = "$(pwd)/build/deps/iphonesimulator/bin:$PATH" }, + { select = "*-win32", test-requires = [] }, +] [tool.black] exclude = "wheels/multibuild" [tool.ruff] exclude = [ "wheels/multibuild" ] - fix = true lint.select = [ "C4", # flake8-comprehensions @@ -207,9 +185,9 @@ lint.isort.required-imports = [ [tool.pyproject-fmt] max_supported_python = "3.14" -[tool.pytest.ini_options] -addopts = "-ra --color=auto" -testpaths = [ +[tool.pytest] +ini_options.addopts = "-ra --color=auto" +ini_options.testpaths = [ "Tests", ] diff --git a/src/Tk/tkImaging.c b/src/Tk/tkImaging.c index 834634bd7fa..3e35f885f61 100644 --- a/src/Tk/tkImaging.c +++ b/src/Tk/tkImaging.c @@ -124,8 +124,10 @@ PyImagingPhotoPut( if (im->mode == IMAGING_MODE_1 || im->mode == IMAGING_MODE_L) { block.pixelSize = 1; block.offset[0] = block.offset[1] = block.offset[2] = block.offset[3] = 0; - } else if (im->mode == IMAGING_MODE_RGB || im->mode == IMAGING_MODE_RGBA || - im->mode == IMAGING_MODE_RGBX || im->mode == IMAGING_MODE_RGBa) { + } else if ( + im->mode == IMAGING_MODE_RGB || im->mode == IMAGING_MODE_RGBA || + im->mode == IMAGING_MODE_RGBX || im->mode == IMAGING_MODE_RGBa + ) { block.pixelSize = 4; block.offset[0] = 0; block.offset[1] = 1; diff --git a/src/encode.c b/src/encode.c index 06e4a089380..ea57615bec8 100644 --- a/src/encode.c +++ b/src/encode.c @@ -999,8 +999,9 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) { status = ImagingLibTiffSetField( &encoder->state, (ttag_t)key_int, PyBytes_AsString(value) ); - } else if (type == TIFF_DOUBLE || type == TIFF_SRATIONAL || - type == TIFF_RATIONAL) { + } else if ( + type == TIFF_DOUBLE || type == TIFF_SRATIONAL || type == TIFF_RATIONAL + ) { status = ImagingLibTiffSetField( &encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value) ); diff --git a/src/libImaging/Arrow.c b/src/libImaging/Arrow.c index d2ed10f0a6e..de4d3568eda 100644 --- a/src/libImaging/Arrow.c +++ b/src/libImaging/Arrow.c @@ -170,16 +170,17 @@ export_named_type(struct ArrowSchema *schema, char *format, const char *name) { strncpy(formatp, format, format_len); strncpy(namep, name, name_len); - *schema = (struct ArrowSchema){// Type description - .format = formatp, - .name = namep, - .metadata = NULL, - .flags = 0, - .n_children = 0, - .children = NULL, - .dictionary = NULL, - // Bookkeeping - .release = &ReleaseExportedSchema + *schema = (struct ArrowSchema){ + // Type description + .format = formatp, + .name = namep, + .metadata = NULL, + .flags = 0, + .n_children = 0, + .children = NULL, + .dictionary = NULL, + // Bookkeeping + .release = &ReleaseExportedSchema }; return 0; } @@ -287,17 +288,18 @@ export_single_channel_array(Imaging im, struct ArrowArray *array) { im->refcount++; MUTEX_UNLOCK(&im->mutex); // Initialize primitive fields - *array = (struct ArrowArray){// Data description - .length = length, - .offset = 0, - .null_count = 0, - .n_buffers = 2, - .n_children = 0, - .children = NULL, - .dictionary = NULL, - // Bookkeeping - .release = &release_const_array, - .private_data = im + *array = (struct ArrowArray){ + // Data description + .length = length, + .offset = 0, + .null_count = 0, + .n_buffers = 2, + .n_children = 0, + .children = NULL, + .dictionary = NULL, + // Bookkeeping + .release = &release_const_array, + .private_data = im }; // Allocate list of buffers @@ -332,17 +334,18 @@ export_fixed_pixel_array(Imaging im, struct ArrowArray *array) { // Initialize primitive fields // Fixed length arrays are 1 buffer of validity, and the length in pixels. // Data is in a child array. - *array = (struct ArrowArray){// Data description - .length = length, - .offset = 0, - .null_count = 0, - .n_buffers = 1, - .n_children = 1, - .children = NULL, - .dictionary = NULL, - // Bookkeeping - .release = &release_const_array, - .private_data = im + *array = (struct ArrowArray){ + // Data description + .length = length, + .offset = 0, + .null_count = 0, + .n_buffers = 1, + .n_children = 1, + .children = NULL, + .dictionary = NULL, + // Bookkeeping + .release = &release_const_array, + .private_data = im }; // Allocate list of buffers @@ -367,17 +370,18 @@ export_fixed_pixel_array(Imaging im, struct ArrowArray *array) { MUTEX_LOCK(&im->mutex); im->refcount++; MUTEX_UNLOCK(&im->mutex); - *array->children[0] = (struct ArrowArray){// Data description - .length = length * 4, - .offset = 0, - .null_count = 0, - .n_buffers = 2, - .n_children = 0, - .children = NULL, - .dictionary = NULL, - // Bookkeeping - .release = &release_const_array, - .private_data = im + *array->children[0] = (struct ArrowArray){ + // Data description + .length = length * 4, + .offset = 0, + .null_count = 0, + .n_buffers = 2, + .n_children = 0, + .children = NULL, + .dictionary = NULL, + // Bookkeeping + .release = &release_const_array, + .private_data = im }; array->children[0]->buffers = diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 330e5325c33..002497c3264 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -1695,16 +1695,20 @@ ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b) if (mode == IMAGING_MODE_RGBa) { premultiplied = 1; } - } else if (imIn->mode == IMAGING_MODE_RGB && - (mode == IMAGING_MODE_LA || mode == IMAGING_MODE_La)) { + } else if ( + imIn->mode == IMAGING_MODE_RGB && + (mode == IMAGING_MODE_LA || mode == IMAGING_MODE_La) + ) { convert = rgb2la; source_transparency = 1; if (mode == IMAGING_MODE_La) { premultiplied = 1; } - } else if ((imIn->mode == IMAGING_MODE_1 || imIn->mode == IMAGING_MODE_I || - imIn->mode == IMAGING_MODE_I_16 || imIn->mode == IMAGING_MODE_L) && - (mode == IMAGING_MODE_RGBA || mode == IMAGING_MODE_LA)) { + } else if ( + (imIn->mode == IMAGING_MODE_1 || imIn->mode == IMAGING_MODE_I || + imIn->mode == IMAGING_MODE_I_16 || imIn->mode == IMAGING_MODE_L) && + (mode == IMAGING_MODE_RGBA || mode == IMAGING_MODE_LA) + ) { if (imIn->mode == IMAGING_MODE_1) { convert = bit2rgb; } else if (imIn->mode == IMAGING_MODE_I) { diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index d2898043256..0d28069f000 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -537,8 +537,9 @@ polygon_generic( // Needed to draw consistent polygons xx[j] = xx[j - 1]; j++; - } else if ((ymin == current->ymin || ymin == current->ymax) && - current->dx != 0) { + } else if ( + (ymin == current->ymin || ymin == current->ymax) && current->dx != 0 + ) { // Connect discontiguous corners for (k = 0; k < i; k++) { Edge *other_edge = edge_table[k]; @@ -570,8 +571,10 @@ polygon_generic( adjacent_line_x, adjacent_line_x_other_edge )) + 1; - } else if (xx[j - 1] < adjacent_line_x - 1 && - xx[j - 1] < adjacent_line_x_other_edge - 1) { + } else if ( + xx[j - 1] < adjacent_line_x - 1 && + xx[j - 1] < adjacent_line_x_other_edge - 1 + ) { xx[j - 1] = roundf(fmin( adjacent_line_x, adjacent_line_x_other_edge diff --git a/src/libImaging/GetBBox.c b/src/libImaging/GetBBox.c index d336121d5cc..7a57f6894a0 100644 --- a/src/libImaging/GetBBox.c +++ b/src/libImaging/GetBBox.c @@ -89,10 +89,12 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) { INT32 mask = 0xffffffff; if (im->bands == 3) { ((UINT8 *)&mask)[3] = 0; - } else if (alpha_only && - (im->mode == IMAGING_MODE_RGBa || im->mode == IMAGING_MODE_RGBA || - im->mode == IMAGING_MODE_La || im->mode == IMAGING_MODE_LA || - im->mode == IMAGING_MODE_PA)) { + } else if ( + alpha_only && + (im->mode == IMAGING_MODE_RGBa || im->mode == IMAGING_MODE_RGBA || + im->mode == IMAGING_MODE_La || im->mode == IMAGING_MODE_LA || + im->mode == IMAGING_MODE_PA) + ) { #ifdef WORDS_BIGENDIAN mask = 0x000000ff; #else diff --git a/src/libImaging/Jpeg2KEncode.c b/src/libImaging/Jpeg2KEncode.c index fdfbde2d76b..3012783a2e4 100644 --- a/src/libImaging/Jpeg2KEncode.c +++ b/src/libImaging/Jpeg2KEncode.c @@ -330,8 +330,10 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) { components = 4; color_space = OPJ_CLRSPC_SRGB; pack = j2k_pack_rgba; -#if ((OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR == 5 && OPJ_VERSION_BUILD >= 3) || \ - (OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR > 5) || OPJ_VERSION_MAJOR > 2) +#if ( \ + (OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR == 5 && OPJ_VERSION_BUILD >= 3) || \ + (OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR > 5) || OPJ_VERSION_MAJOR > 2 \ +) } else if (im->mode == IMAGING_MODE_CMYK) { components = 4; color_space = OPJ_CLRSPC_CMYK; diff --git a/src/libImaging/JpegDecode.c b/src/libImaging/JpegDecode.c index ae3274456d3..05cb37554b3 100644 --- a/src/libImaging/JpegDecode.c +++ b/src/libImaging/JpegDecode.c @@ -206,8 +206,10 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t by context->cinfo.out_color_space = JCS_EXT_RGBX; } #endif - else if (context->rawmode == IMAGING_RAWMODE_CMYK || - context->rawmode == IMAGING_RAWMODE_CMYK_I) { + else if ( + context->rawmode == IMAGING_RAWMODE_CMYK || + context->rawmode == IMAGING_RAWMODE_CMYK_I + ) { context->cinfo.out_color_space = JCS_CMYK; } else if (context->rawmode == IMAGING_RAWMODE_YCbCr) { context->cinfo.out_color_space = JCS_YCbCr; diff --git a/src/libImaging/Matrix.c b/src/libImaging/Matrix.c index d28e04edfaa..acd59ba7f39 100644 --- a/src/libImaging/Matrix.c +++ b/src/libImaging/Matrix.c @@ -46,8 +46,9 @@ ImagingConvertMatrix(Imaging im, const ModeID mode, float m[]) { } } ImagingSectionLeave(&cookie); - } else if (mode == IMAGING_MODE_HSV || mode == IMAGING_MODE_LAB || - mode == IMAGING_MODE_RGB) { + } else if ( + mode == IMAGING_MODE_HSV || mode == IMAGING_MODE_LAB || mode == IMAGING_MODE_RGB + ) { imOut = ImagingNewDirty(mode, im->xsize, im->ysize); if (!imOut) { return NULL; From a8cf13010b7c76203b26dcd5c7534363a351b5ed Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:02:49 +1100 Subject: [PATCH 3/3] Use native configuration Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4b969dbc426..6d9910ca140 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -186,8 +186,8 @@ lint.isort.required-imports = [ max_supported_python = "3.14" [tool.pytest] -ini_options.addopts = "-ra --color=auto" -ini_options.testpaths = [ +addopts = [ "-ra", "--color=auto" ] +testpaths = [ "Tests", ]