Skip to content

Raise the Python floor to >=3.11 and land the pillow 13.0.0 security update - #10

Merged
docxology merged 4 commits into
mainfrom
chore/requires-python-311
Nov 5, 2026
Merged

docxology merged 4 commits into
mainfrom
chore/requires-python-311

Conversation

@docxology

@docxology docxology commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

What this changes

  • pyproject.toml: requires-python >=3.10 -> >=3.11.
  • pyproject.toml: also [tool.uv] constraint-dependencies = ["pillow>=13.0.0"]. pillow is transitive here: the constraint forces the resolution without asserting a dependency the code never imports.
  • uv.lock: regenerated at the new floor, so pillow 12.3.0 -> 13.0.0 lands in this PR instead of waiting for a later updater run. The lock is the resolver's output, not a hand-edited file.
  • uv.lock: the regeneration also re-resolved packages the old 3.10 lanes were holding back: contourpy 1.3.2 -> 1.3.3, matplotlib 3.10.9 -> 3.11.2, numpy 2.2.6 -> 2.4.6, scipy 1.15.3 -> 1.17.1.

Why

Dependabot's updater resolves as the declared floor: its own log says Dependabot is using Python version '3.10.20' where requires-python is >=3.10. With that floor its security update for pillow 13.0.0 (Requires-Python >=3.11) is refused: Filtered out pillow 13.0.0 because python requirement >= 3.11 is not satisfied by python 3.10.20, recorded as security_update_not_possible. The control is a repository with the same advisories and a >=3.11 floor (active_inference_power): its Dependabot pillow runs succeed, so the floor is the cause and not the advisories.

Why the lock moves with the floor

A floor raise alone does not move an existing resolution: uv lock keeps a package that is still valid, and the lock kept pillow 12.x together with python_full_version < '3.11' lanes that no longer describe any supported interpreter. So the floor the fix needs is declared in the manifest and the lock is regenerated. That is the same shape already merged tonight in fundamentals #15 (pillow>=10.0 -> >=13.0.0, lock refreshed).

Scope

No workflow step changes beyond the matrix entry named above. The version moves listed above are the resolver's answer at the new floor; nothing in the lock was written by hand, and no pillow entry is left below 13.0.0 under any marker.

Notes

This repository pins no interpreter in CI (no python-version input to setup-uv), so the floor move is a claim with no CI backing before or after. Adding a matrix is a separate decision with a cost and is not part of this change.

The lint failure this floor causes (third commit)

uvx ruff check src scripts tests failed at the second head: this repository sets no [tool.ruff] target-version, so ruff derives its target from requires-python, and the >=3.11 floor enables UP017. Four datetime.now(timezone.utc) uses become datetime.now(UTC), with the import adjusted: scripts/reset_local_skilltree.py:68, src/release_readiness.py:156, src/skilltree/dependency_reconciler.py:101, src/skilltree/local_auth_state.py:364. datetime.UTC exists only from 3.11, so the fix belongs to the floor rather than beside it. After it, ruff check and ruff format --check pass exactly as CI runs them.

What has not been measured yet, and why a later red would not be this commit's

gates runs Lint and format before mypy, the ten validator scripts and pytest --cov-fail-under=90, so none of those had executed at the previous head: the lint failure masked them. They run for the first time at this floor in the new run, and a failure there is a masked gate rather than a regression from this commit. The larger unmeasured thing is the regenerated lock: pillow 13.0.0, and the jax / numpy / pandas moves the new floor forced, have not been exercised by any step of this job yet.

A second commit from the same run, and my own error caught by CI

The first lint commit rewrote scripts/reset_local_skilltree.py with mode 100644; the file ships as 100755, and ruff's EXE001 flags a shebang in a file that is not executable. So the run failed again, on a new error that my commit introduced rather than on the old one. Fixed by restoring the mode with the content unchanged. The lesson is in the tooling: a file written through the git data API carries the mode you pass, so the original mode has to be read and carried.

… can land

requires-python >=3.10 -> >=3.11 in pyproject.toml; the uv.lock project-level requires-python records the same floor (no package version moves).
pillow >= 13.0.0 is declared in the manifest and the resolution is regenerated, so the security fix lands with this PR instead of waiting for a later updater run. Shape (C), as chosen by the owner.
@docxology docxology changed the title Raise the Python floor to >=3.11 so the pillow 13.0.0 security update can land Raise the Python floor to >=3.11 and land the pillow 13.0.0 security update Nov 5, 2026
ruff infers target-version from requires-python here (no [tool.ruff] target-version), so the >=3.11 floor
enables UP017; datetime.UTC exists only from 3.11, so this is the floor's own consequence.
The lint commit rewrote scripts/reset_local_skilltree.py with mode 100644; the file ships
as 100755, and ruff's EXE001 flags a shebang in a file that is not executable. Content
is unchanged.
@docxology
docxology merged commit 58d4757 into main Nov 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant