From 5b56f1952c58000219f8eb4b0a52f5550660cafc Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:12:54 +0000 Subject: [PATCH 01/11] Update copyright year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 6b55ca9..7e35444 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2024, Developer Society Limited +Copyright (c) 2024-2026, Developer Society Limited All rights reserved. Redistribution and use in source and binary forms, with or without From d1ac0630c899e0a44c0759771e82ff197c3e6f04 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:10:21 +0000 Subject: [PATCH 02/11] Drop Python 3.9 support --- pyproject.toml | 5 ++--- tox.ini | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f10603d..96977e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = '0.1' description = 'ExifTool optimizer for Willow' readme = 'README.md' maintainers = [{ name = 'The Developer Society', email = 'studio@dev.ngo' }] -requires-python = '>= 3.9' +requires-python = '>= 3.10' dependencies = [ 'Willow>=1.6.0', ] @@ -14,7 +14,6 @@ classifiers = [ 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', @@ -36,7 +35,7 @@ include = ['willow_exiftool*'] [tool.ruff] line-length = 99 -target-version = 'py39' +target-version = 'py310' [tool.ruff.lint] select = [ diff --git a/tox.ini b/tox.ini index 6ff5415..e449e33 100644 --- a/tox.ini +++ b/tox.ini @@ -2,9 +2,9 @@ env_list = check lint - {py39,py310,py311,py312}-willow1.6 - {py39,py310,py311,py312}-willow1.8 - {py39,py310,py311,py312,py313}-willow1.9 + {py310,py311,py312}-willow1.6 + {py310,py311,py312}-willow1.8 + {py310,py311,py312,py313}-willow1.9 coverage no_package = true From debdacb7a7a040039a5eb0f023353317d68f4bc4 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:10:49 +0000 Subject: [PATCH 03/11] Only support Willow 1.11 and above --- pyproject.toml | 3 ++- tox.ini | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 96977e6..21afe4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ readme = 'README.md' maintainers = [{ name = 'The Developer Society', email = 'studio@dev.ngo' }] requires-python = '>= 3.10' dependencies = [ - 'Willow>=1.6.0', + 'Willow>=1.11.0', ] classifiers = [ 'Intended Audience :: Developers', @@ -18,6 +18,7 @@ classifiers = [ 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', ] [project.urls] diff --git a/tox.ini b/tox.ini index e449e33..3d86563 100644 --- a/tox.ini +++ b/tox.ini @@ -2,18 +2,16 @@ env_list = check lint - {py310,py311,py312}-willow1.6 - {py310,py311,py312}-willow1.8 - {py310,py311,py312,py313}-willow1.9 + {py310,py311,py312,py313}-willow1.11 + {py310,py311,py312,py313,py314}-willow1.12 coverage no_package = true [testenv] deps = -rrequirements/testing.txt - willow1.6: Willow[heif]>=1.6,<1.7 - willow1.8: Willow[heif]>=1.8,<1.9 - willow1.9: Willow[heif]>=1.9,<2.0 + willow1.11: Willow[heif]>=1.11,<1.12 + willow1.12: Willow[heif]>=1.12,<1.13 allowlist_externals = make commands = make test package = editable From 7ec5f47f6fb57f5916a35f0542ed40f135cf75c6 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:11:37 +0000 Subject: [PATCH 04/11] Python package upgrades --- requirements/local.txt | 6 +++--- requirements/testing.txt | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/requirements/local.txt b/requirements/local.txt index 0ead760..157162e 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -1,6 +1,6 @@ -r testing.txt -bump-my-version==0.28.1 -tox==4.23.2 -tox-uv==1.16.1 +bump-my-version==1.2.6 +tox==4.34.1 +tox-uv==1.29.0 Willow<2.0 diff --git a/requirements/testing.txt b/requirements/testing.txt index 3b44e98..b4193d3 100644 --- a/requirements/testing.txt +++ b/requirements/testing.txt @@ -1,8 +1,8 @@ -build==1.2.2.post1 -check-wheel-contents==0.6.1 -coverage==7.6.9 -mypy==1.13.0 -pipdeptree==2.24.0 -pytest==8.3.4 +build==1.4.0 +check-wheel-contents==0.6.3 +coverage==7.13.3 +mypy==1.19.1 +pipdeptree==2.30.0 +pytest==9.0.2 ruff==0.8.3 -twine==6.0.1 +twine==6.2.0 From 203cc74b3bdd50f4a7d39e3d1a9f1ed5eb581f82 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:12:31 +0000 Subject: [PATCH 05/11] Python 3.14 for testing --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 2 +- tox.ini | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be659df..abab6ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/*.txt" - name: Run tox @@ -73,7 +73,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/*.txt" - uses: actions/download-artifact@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d6c0130..d78e570 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" - name: Build packages run: | pip install -r requirements/testing.txt diff --git a/tox.ini b/tox.ini index 3d86563..457ce32 100644 --- a/tox.ini +++ b/tox.ini @@ -17,14 +17,14 @@ commands = make test package = editable [testenv:check] -base_python = python3.13 +base_python = python3.14 commands = make check uv_seed = true [testenv:lint] -base_python = python3.13 +base_python = python3.14 commands = make lint [testenv:coverage] -base_python = python3.13 +base_python = python3.14 commands = make coverage-report From 2c8f396fe833a61a6f48df0a8a9031b2ce554c12 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:15:14 +0000 Subject: [PATCH 06/11] Upgrade GitHub Actions --- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/publish.yml | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abab6ba..d3d9cc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false ref: ${{ github.event.pull_request.head.sha }} - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" cache: "pip" @@ -37,12 +37,12 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false ref: ${{ github.event.pull_request.head.sha }} - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} cache: "pip" @@ -52,7 +52,7 @@ jobs: pip install $(grep -E "^(tox|tox-uv)==" requirements/local.txt) tox -e ${{ matrix.tox_env }} - name: Upload coverage data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: coverage-data-${{ matrix.tox_env }} include-hidden-files: true @@ -66,17 +66,17 @@ jobs: if: always() steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false ref: ${{ github.event.pull_request.head.sha }} - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/*.txt" - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: pattern: coverage-data-* merge-multiple: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d78e570..cda130b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,11 +13,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" - name: Build packages @@ -25,7 +25,7 @@ jobs: pip install -r requirements/testing.txt make package - name: Upload packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: python-package-distributions path: dist/ @@ -44,7 +44,7 @@ jobs: steps: - name: Download packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: name: python-package-distributions path: dist/ @@ -65,12 +65,12 @@ jobs: steps: - name: Download packages - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v7 with: name: python-package-distributions path: dist/ - name: Sign packages - uses: sigstore/gh-action-sigstore-python@v3.0.0 + uses: sigstore/gh-action-sigstore-python@v3.2.0 with: inputs: >- ./dist/*.tar.gz From e7619f9ebba0a4cd341d85b3bd9fd7c6e65d3f25 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:17:00 +0000 Subject: [PATCH 07/11] Standard env var for publish workflow --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cda130b..cc62dfc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -81,7 +81,7 @@ jobs: run: >- gh release create "$GITHUB_REF_NAME" - --repo '${{ github.repository }}' + --repo "$GITHUB_REPOSITORY" --title "${GITHUB_REPOSITORY#*/} $GITHUB_REF_NAME" - name: Upload artifact signatures to GitHub Release env: @@ -89,4 +89,4 @@ jobs: run: >- gh release upload "$GITHUB_REF_NAME" dist/** - --repo '${{ github.repository }}' + --repo "$GITHUB_REPOSITORY" From 47de1165da6fe55ce46205aa50f3cadaea721f70 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:20:47 +0000 Subject: [PATCH 08/11] Updated ruff, and ruff rules --- .github/matrix.py | 32 +++++------ pyproject.toml | 103 +++++++++++++++++++++++++++--------- requirements/testing.txt | 2 +- willow_exiftool/__init__.py | 10 +++- 4 files changed, 103 insertions(+), 44 deletions(-) diff --git a/.github/matrix.py b/.github/matrix.py index 17a63d3..34883f1 100644 --- a/.github/matrix.py +++ b/.github/matrix.py @@ -1,3 +1,4 @@ +# noqa:INP001 import fileinput import json import re @@ -9,21 +10,22 @@ def main(): actions_matrix = [] - for tox_env in fileinput.input(): - tox_env = tox_env.rstrip() - - if python_match := PY_VERSIONS_RE.match(tox_env): - version_tuple = python_match.groups() - else: - version_tuple = sys.version_info[0:2] - - python_version = "{}.{}".format(*version_tuple) - actions_matrix.append( - { - "python": python_version, - "tox_env": tox_env, - } - ) + with fileinput.input() as f: + for tox_env_line in f: + tox_env = tox_env_line.rstrip() + + if python_match := PY_VERSIONS_RE.match(tox_env): + version_tuple = python_match.groups() + else: + version_tuple = sys.version_info[0:2] + + python_version = "{}.{}".format(*version_tuple) + actions_matrix.append( + { + "python": python_version, + "tox_env": tox_env, + } + ) print(json.dumps(actions_matrix)) # noqa:T201 diff --git a/pyproject.toml b/pyproject.toml index 21afe4c..e9e3a2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,19 +6,19 @@ readme = 'README.md' maintainers = [{ name = 'The Developer Society', email = 'studio@dev.ngo' }] requires-python = '>= 3.10' dependencies = [ - 'Willow>=1.11.0', + 'Willow>=1.11.0', ] classifiers = [ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - 'Programming Language :: Python :: 3.14', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', ] [project.urls] @@ -39,27 +39,78 @@ line-length = 99 target-version = 'py310' [tool.ruff.lint] -select = [ - 'F', # pyflakes - 'E', # pycodestyle - 'W', # pycodestyle - 'I', # isort - 'N', # pep8-naming - 'UP', # pyupgrade - 'S', # flake8-bandit - 'BLE', # flake8-blind-except - 'C4', # flake8-comprehensions - 'EM', # flake8-errmsg - 'T20', # flake8-print - 'RET', # flake8-return - 'RUF', # ruff +extend-select = [ + 'ERA', # eradicate + 'YTT', # flake8-2020 + 'ASYNC', # flake8-async + 'S', # flake8-bandit + 'BLE', # flake8-blind-except + 'B', # flake8-bugbear + 'A', # flake8-builtins + 'COM', # flake8-commas + 'C4', # flake8-comprehensions + 'DTZ', # flake8-datetimez + 'T10', # flake8-debugger + 'DJ', # flake8-django + 'EM', # flake8-errmsg + 'EXE', # flake8-executable + 'FA', # flake8-future-annotations + 'INT', # flake8-gettext + 'ISC', # flake8-implicit-str-concat + 'ICN', # flake8-import-conventions + 'LOG', # flake8-logging + 'G', # flake8-logging-format + 'INP', # flake8-no-pep420 + 'PIE', # flake8-pie + 'T20', # flake8-print + 'PYI', # flake8-pyi + 'Q', # flake8-quotes + 'RSE', # flake8-raise + 'RET', # flake8-return + 'SLOT', # flake8-slots + 'SIM', # flake8-simplify + 'TID', # flake8-tidy-imports + 'TD', # flake8-todos + 'TCH', # flake8-type-checking + 'PTH', # flake8-use-pathlib + 'FLY', # flynt + 'I', # isort + 'NPY', # numpy-specific rules + 'PD', # pandas-vet + 'N', # pep8-naming + 'PERF', # perflint + 'E', # pycodestyle + 'W', # pycodestyle + 'F', # pyflakes + 'PGH', # pygrep-hooks + 'PLC', # pylint + 'PLE', # pylint + 'PLW', # pylint + 'UP', # pyupgrade + 'FURB', # refurb + 'RUF', # ruff-specific rules + 'TRY', # tryceratops ] ignore = [ - 'EM101', # flake8-errmsg: raw-string-in-exception + 'COM812', # flake8-commas: missing-trailing-comma + 'EM101', # flake8-errmsg: raw-string-in-exception + 'ISC001', # flake8-implicit-str-concat: single-line-implicit-string-concatenation + 'RUF012', # ruff-specific rules: mutable-class-default + 'SIM105', # flake8-simplify: suppressible-exception + 'SIM108', # flake8-simplify: if-else-block-instead-of-if-exp + 'TD002', # flake8-todos: missing-todo-author + 'TRY003', # tryceratops: raise-vanilla-args ] [tool.ruff.lint.isort] combine-as-imports = true +[tool.ruff.lint.pep8-naming] +extend-ignore-names = ['assert*'] + [tool.mypy] mypy_path = "$MYPY_CONFIG_FILE_DIR/stubs" + +[[tool.mypy.overrides]] +module = 'willow.registry' +ignore_missing_imports = true diff --git a/requirements/testing.txt b/requirements/testing.txt index b4193d3..79206f6 100644 --- a/requirements/testing.txt +++ b/requirements/testing.txt @@ -4,5 +4,5 @@ coverage==7.13.3 mypy==1.19.1 pipdeptree==2.30.0 pytest==9.0.2 -ruff==0.8.3 +ruff==0.15.0 twine==6.2.0 diff --git a/willow_exiftool/__init__.py b/willow_exiftool/__init__.py index 1446e01..9cb1bbb 100644 --- a/willow_exiftool/__init__.py +++ b/willow_exiftool/__init__.py @@ -1,7 +1,13 @@ def setup() -> None: - from willow.registry import registry # type: ignore + from willow.registry import registry # noqa:PLC0415 - from .stripexif import ExifToolAVIF, ExifToolHEIC, ExifToolJPEG, ExifToolPNG, ExifToolWEBP + from .stripexif import ( # noqa:PLC0415 + ExifToolAVIF, + ExifToolHEIC, + ExifToolJPEG, + ExifToolPNG, + ExifToolWEBP, + ) registry.register_optimizer(ExifToolAVIF) registry.register_optimizer(ExifToolHEIC) From 53706966190f646be676a993058d64d7401a8933 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:32:32 +0000 Subject: [PATCH 09/11] Switch to newer license setup instead of classifier --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e9e3a2f..144e317 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,9 +8,9 @@ requires-python = '>= 3.10' dependencies = [ 'Willow>=1.11.0', ] +license = 'BSD-3-Clause' classifiers = [ 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', @@ -25,7 +25,7 @@ classifiers = [ Homepage = "https://github.com/developersociety/willow-exiftool" [build-system] -requires = ['setuptools >= 61.0'] +requires = ['setuptools >= 77.0.3'] build-backend = 'setuptools.build_meta' [tool.setuptools] From 487e76da767eca28e83fecaf98d9aa0c4e0756eb Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:36:07 +0000 Subject: [PATCH 10/11] Updated editorconfig --- .editorconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index cc8c24e..6c5964a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,8 +14,12 @@ charset = utf-8 [*.py] max_line_length = 99 -# Smaller indent for YAML -[*.{yaml,yml}] +# Smaller indent for TOML/YAML +[*.{toml,yaml,yml}] +indent_size = 2 + +# Use 2 spaces for the HTML files +[*.html] indent_size = 2 # Makefiles always use tabs for indentation From 9491ce06462bb9cc27d311f3d1a9a90b86c95781 Mon Sep 17 00:00:00 2001 From: Alex Tomkins Date: Sat, 7 Feb 2026 17:45:33 +0000 Subject: [PATCH 11/11] Drop gh-action-sigstore-python Leaving signing to gh-action-pypi-publish --- .github/workflows/publish.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cc62dfc..5de63f3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -69,12 +69,6 @@ jobs: with: name: python-package-distributions path: dist/ - - name: Sign packages - uses: sigstore/gh-action-sigstore-python@v3.2.0 - with: - inputs: >- - ./dist/*.tar.gz - ./dist/*.whl - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} @@ -83,7 +77,7 @@ jobs: "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --title "${GITHUB_REPOSITORY#*/} $GITHUB_REF_NAME" - - name: Upload artifact signatures to GitHub Release + - name: Upload files to GitHub Release env: GH_TOKEN: ${{ github.token }} run: >-