From 80406a7c9b4956250025b7b5438a9a5d1ef44f0a Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 30 Oct 2023 19:53:20 +0200 Subject: [PATCH 1/4] editorconfig: specify 2-space indent for TOML Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index d74549fe2ac..c3627ae4fad 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ indent_style = space trim_trailing_whitespace = true -[*.yml] +[*.{toml,yml}] # Two-space indentation indent_size = 2 From de6c4b09d72b321e916dee9089eec425a9c827bc Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 23 Feb 2023 14:02:58 +0200 Subject: [PATCH 2/4] Switch linting to ruff Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- .flake8 | 3 --- .pre-commit-config.yaml | 26 ++++---------------------- MANIFEST.in | 1 + Makefile | 6 +++--- pyproject.toml | 30 ++++++++++++++++++++++++++++-- 5 files changed, 36 insertions(+), 30 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index e19c0a58536..00000000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -extend-ignore = E203 -max-line-length = 88 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a8c7696df62..5812e726bd1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,9 @@ repos: - - repo: https://github.com/asottile/pyupgrade - rev: v3.13.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.4 hooks: - - id: pyupgrade - args: [--py38-plus] + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/psf/black-pre-commit-mirror rev: 23.9.1 @@ -11,11 +11,6 @@ repos: - id: black args: [--target-version=py38] - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - - repo: https://github.com/PyCQA/bandit rev: 1.7.5 hooks: @@ -23,28 +18,15 @@ repos: args: [--severity-level=high] files: ^src/ - - repo: https://github.com/asottile/yesqa - rev: v1.5.0 - hooks: - - id: yesqa - - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.4 hooks: - id: remove-tabs exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$) - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - additional_dependencies: - [flake8-2020, flake8-errmsg, flake8-implicit-str-concat, flake8-logging] - - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: - - id: python-check-blanket-noqa - id: rst-backticks - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/MANIFEST.in b/MANIFEST.in index 9401ebbbf37..af25dfd2db5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,6 +5,7 @@ include *.md include *.py include *.rst include *.sh +include *.toml include *.txt include *.yaml include .flake8 diff --git a/Makefile b/Makefile index 57d756b47e3..b7f07e24d07 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ help: @echo " install make and install" @echo " install-coverage make and install with C coverage" @echo " lint run the lint checks" - @echo " lint-fix run Black and isort to (mostly) fix lint issues" + @echo " lint-fix run Ruff to (mostly) fix lint issues" @echo " release-test run code and package tests before release" @echo " test run tests on installed Pillow" @@ -118,6 +118,6 @@ lint: .PHONY: lint-fix lint-fix: python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black - python3 -c "import isort" > /dev/null 2>&1 || python3 -m pip install isort python3 -m black --target-version py38 . - python3 -m isort . + python3 -c "import ruff" > /dev/null 2>&1 || python3 -m pip install ruff + python3 -m ruff --fix . diff --git a/pyproject.toml b/pyproject.toml index 6f6ed6e9336..59d8da44e4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,8 +77,34 @@ package-dir = {"" = "src"} [tool.setuptools.dynamic] version = {attr = "PIL.__version__"} -[tool.isort] -profile = "black" +[tool.ruff] +target-version = "py38" +line-length = 88 +select = [ + "E", # pycodestyle errors + "EM", # flake8-errmsg + "F", # pyflakes errors + "I", # isort + "ISC", # flake8-implicit-str-concat + "PGH", # pygrep-hooks + "RUF100", # unused noqa (yesqa) + "UP", # pyupgrade + "W", # pycodestyle warnings + "YTT", # flake8-2020 + # "LOG", # TODO: enable flake8-logging when it's not in preview anymore +] +extend-ignore = [ + "E203", # Whitespace before ':' + "E221", # Multiple spaces before operator + "E226", # Missing whitespace around arithmetic operator + "E241", # Multiple spaces after ',' +] + +[tool.ruff.per-file-ignores] +"Tests/*.py" = ["I001"] + +[tool.ruff.isort] +known-first-party = ["PIL"] [tool.pytest.ini_options] addopts = "-ra --color=yes" From 307d00b44de2c6f7ff0565843b848b2b0dea0f62 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 23 Feb 2023 15:45:11 +0200 Subject: [PATCH 3/4] Apply ruff autofixes --- _custom_build/backend.py | 2 +- docs/conf.py | 14 +++++++------- src/PIL/ImageFilter.py | 2 +- src/PIL/IptcImagePlugin.py | 3 +-- src/PIL/PyAccess.py | 4 ++-- winbuild/build_prepare.py | 4 ++-- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/_custom_build/backend.py b/_custom_build/backend.py index 9b3265a949f..23225d6b8eb 100644 --- a/_custom_build/backend.py +++ b/_custom_build/backend.py @@ -1,6 +1,6 @@ import sys -from setuptools.build_meta import * # noqa: F401, F403 +from setuptools.build_meta import * # noqa: F403 from setuptools.build_meta import build_wheel backend_class = build_wheel.__self__.__class__ diff --git a/docs/conf.py b/docs/conf.py index fdcda3a7c26..ef2cb5b8826 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -318,14 +318,14 @@ def setup(app): linkcheck_allowed_redirects = { - r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*", # noqa: E501 - r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg", # noqa: E501 - r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*", # noqa: E501 - r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest", # noqa: E501 + r"https://www.bestpractices.dev/projects/6331": r"https://www.bestpractices.dev/en/.*", + r"https://badges.gitter.im/python-pillow/Pillow.svg": r"https://badges.gitter.im/repo.svg", + r"https://gitter.im/python-pillow/Pillow?.*": r"https://app.gitter.im/#/room/#python-pillow_Pillow:gitter.im?.*", + r"https://pillow.readthedocs.io/?badge=latest": r"https://pillow.readthedocs.io/en/stable/?badge=latest", r"https://pillow.readthedocs.io": r"https://pillow.readthedocs.io/en/stable/", - r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*", # noqa: E501 - r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg", # noqa: E501 - r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+", # noqa: E501 + r"https://tidelift.com/badges/package/pypi/Pillow?.*": r"https://img.shields.io/badge/.*", + r"https://zenodo.org/badge/17549/python-pillow/Pillow.svg": r"https://zenodo.org/badge/doi/[\.0-9]+/zenodo.[0-9]+.svg", + r"https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow": r"https://zenodo.org/record/[0-9]+", } # sphinx.ext.extlinks diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 57268b8f53d..c24f86ef38f 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -222,7 +222,7 @@ class UnsharpMask(MultibandFilter): .. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking - """ # noqa: E501 + """ name = "UnsharpMask" diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index 316cd17c732..3a40cf987f4 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -18,10 +18,9 @@ import tempfile from . import Image, ImageFile -from ._binary import i8 +from ._binary import i8, o8 from ._binary import i16be as i16 from ._binary import i32be as i32 -from ._binary import o8 COMPRESSION = {1: "raw", 5: "jpeg"} diff --git a/src/PIL/PyAccess.py b/src/PIL/PyAccess.py index 99b46a4a66c..24d30d2a6eb 100644 --- a/src/PIL/PyAccess.py +++ b/src/PIL/PyAccess.py @@ -244,7 +244,7 @@ def set_pixel(self, x, y, color): except TypeError: color = min(color[0], 65535) - pixel.l = color & 0xFF # noqa: E741 + pixel.l = color & 0xFF pixel.r = color >> 8 @@ -265,7 +265,7 @@ def set_pixel(self, x, y, color): except Exception: color = min(color[0], 65535) - pixel.l = color >> 8 # noqa: E741 + pixel.l = color >> 8 pixel.r = color & 0xFF diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index a1f1755be6c..4c47db1fb2a 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -239,7 +239,7 @@ def cmd_msbuild( "libs": ["*.lib"], }, "freetype": { - "url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz", # noqa: E501 + "url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz", "filename": "freetype-2.13.2.tar.gz", "dir": "freetype-2.13.2", "license": ["LICENSE.TXT", r"docs\FTL.TXT", r"docs\GPLv2.TXT"], @@ -321,7 +321,7 @@ def cmd_msbuild( }, "libimagequant": { # commit: Merge branch 'master' into msvc (matches 2.17.0 tag) - "url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip", # noqa: E501 + "url": "https://github.com/ImageOptim/libimagequant/archive/e4c1334be0eff290af5e2b4155057c2953a313ab.zip", "filename": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab.zip", "dir": "libimagequant-e4c1334be0eff290af5e2b4155057c2953a313ab", "license": "COPYRIGHT", From 9e615b6ad38d1f20e0ad61ed9334f224a4030ce4 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 30 Oct 2023 20:04:44 +0200 Subject: [PATCH 4/4] Add noqas for UP031 --- Tests/bench_cffi_access.py | 2 +- src/PIL/EpsImagePlugin.py | 2 +- src/PIL/IcnsImagePlugin.py | 2 +- src/PIL/Image.py | 2 +- src/PIL/PdfParser.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/bench_cffi_access.py b/Tests/bench_cffi_access.py index 69ebef9b458..d94b1985b17 100644 --- a/Tests/bench_cffi_access.py +++ b/Tests/bench_cffi_access.py @@ -45,7 +45,7 @@ def test_direct(): assert caccess[(0, 0)] == access[(0, 0)] - print("Size: %sx%s" % im.size) + print("Size: %sx%s" % im.size) # noqa: UP031 timer(iterate_get, "PyAccess - get", im.size, access) timer(iterate_set, "PyAccess - set", im.size, access) timer(iterate_get, "C-api - get", im.size, caccess) diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 9b2fce0ac01..63369eb64f1 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -122,7 +122,7 @@ def Ghostscript(tile, size, fp, scale=1, transparency=False): gs_binary, "-q", # quiet mode "-g%dx%d" % size, # set output geometry (pixels) - "-r%fx%f" % res, # set input DPI (dots per inch) + "-r%fx%f" % res, # set input DPI (dots per inch) # noqa: UP031 "-dBATCH", # exit after processing "-dNOPAUSE", # don't pause between pages "-dSAFER", # safe mode diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py index 0aa4f7a8458..5226c986d61 100644 --- a/src/PIL/IcnsImagePlugin.py +++ b/src/PIL/IcnsImagePlugin.py @@ -392,7 +392,7 @@ def _accept(prefix): imf = IcnsImageFile(fp) for size in imf.info["sizes"]: imf.size = size - imf.save("out-%s-%s-%s.png" % size) + imf.save("out-%s-%s-%s.png" % size) # noqa: UP031 with Image.open(sys.argv[1]) as im: im.save("out.png") if sys.platform == "windows": diff --git a/src/PIL/Image.py b/src/PIL/Image.py index cb092f1ae1f..930ca060bb1 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -3100,7 +3100,7 @@ def fromarray(obj, mode=None): try: mode, rawmode = _fromarray_typemap[typekey] except KeyError as e: - msg = "Cannot handle this data type: %s, %s" % typekey + msg = "Cannot handle this data type: %s, %s" % typekey # noqa: UP031 raise TypeError(msg) from e else: rawmode = mode diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index dc1012f54d3..07df577ae6d 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -82,7 +82,7 @@ class IndirectReference( collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"]) ): def __str__(self): - return "%s %s R" % self + return "%s %s R" % self # noqa: UP031 def __bytes__(self): return self.__str__().encode("us-ascii") @@ -103,7 +103,7 @@ def __hash__(self): class IndirectObjectDef(IndirectReference): def __str__(self): - return "%s %s obj" % self + return "%s %s obj" % self # noqa: UP031 class XrefTable: