Skip to content

Require Python 3.10 and test through 3.14 - #141

Merged
ESultanik merged 1 commit into
masterfrom
139-drop-python-38
Sep 8, 2026
Merged

Require Python 3.10 and test through 3.14#141
ESultanik merged 1 commit into
masterfrom
139-drop-python-38

Conversation

@ESultanik

Copy link
Copy Markdown
Collaborator

Raises the minimum supported Python to 3.10 and adds 3.14 to the test matrix.

Closes #139.

Why

Python 3.8 reached end of life in October 2024 and 3.9 on 2025-10-31, so neither is a supported target. Because requires-python still admitted 3.8, uv had to resolve the entire dependency tree down to versions that support it. That is the root cause of the stale pins in uv.lock, and of most of the repository's open Dependabot alerts.

The clearest symptom was #139. On Python 3.9 and below, cryptography 50.0.0 cannot be installed, so uv resolved secretstorage back to 2.2.1 — a 2016 release whose dependency is pycrypto rather than cryptography and jeepney. pycrypto has been abandoned since 2014 and carries a critical and a high advisory with no patched version available. Raising the floor removes that path entirely.

What changes

  • requires-python becomes >=3.10; the 3.8 and 3.9 classifiers are dropped and a 3.14 classifier added.
  • The CI matrix becomes ["3.10", "3.11", "3.12", "3.13", "3.14"].
  • uv.lock is regenerated. Collapsing the duplicate old-Python resolution branches removes about 900 lines, and both pycrypto and an unpatched wheel pin disappear because their paths are no longer reachable.
  • CLAUDE.md's two references to 3.8 compatibility are updated.
  • Ruff's target-version moves to py310 to match requires-python.

Other pins are deliberately left alone. This is uv lock, not uv lock --upgrade, so the only packages that moved are those the floor change forced. The remaining advisories stay for Dependabot to raise individually, which is what it is doing — #116 is the current one.

On the ruff change

Setting target-version = "py310" surfaces about 530 new pyupgrade findings, taking the total from 207 to 736. They are all annotation modernizations that were previously blocked by 3.8 compatibility: typing.List to list, Optional[X] to X | None, and similar. Every one is a suggestion rather than a defect, and ruff does not gate CI — pythonpackage.yml runs flake8 --select=E9,F63,F7,F82, which is clean.

Applying them is a mechanical change across most of the package, so it is tracked in #140 rather than folded in here, which would have buried a small configuration diff in several hundred edits. #140 also notes that typing_extensions becomes removable and that the sys.version_info < 3.7 guards are unreachable.

Verification

  • 136 tests pass on Python 3.10 and on Python 3.14.
  • pycrypto no longer appears in uv.lock; every runtime dependency still resolves.
  • flake8 graphtage test --select=E9,F63,F7,F82 clean.
  • cd docs && make html succeeds.

One note on 3.14. Earlier work in this repository hit a fickling failure on a Python 3.14 free-threaded build, which was a concern for adding it to CI. It does not reproduce here: actions/setup-python provides the GIL build rather than 3.14t, and CI installs the current fickling (0.1.12) rather than the 0.1.3 that uv.lock used to pin. The full suite passes.

uv.lock was regenerated in an environment that sets uv's exclude-newer to 2026-09-01, so a small number of pins may lag the newest releases by about a week. The injected [options] block was removed from the committed file. Re-running uv lock elsewhere is harmless if you want the difference closed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GypKU5KdLfs2Cf8kS2TzJa

Python 3.8 reached end of life in October 2024 and 3.9 on 2025-10-31, so
neither is a supported target. Because requires-python still admitted 3.8, uv
had to resolve the whole dependency tree down to versions compatible with it,
which is why uv.lock pinned packages old enough to carry security advisories.

Raising the floor to 3.10 removes the abandoned pycrypto package (#139). uv
selected it only for Python 3.9 and below, where cryptography 50.0.0 cannot be
installed and secretstorage fell back to 2.2.1, a 2016 release that depends on
pycrypto rather than cryptography. It also drops the unpatched wheel pin.
Collapsing the duplicate old-Python resolution branches removes about 900 lines
from the lockfile.

Adds 3.14 to the test matrix. The suite passes on 3.10 and 3.14.

Ruff's target-version moves to py310 to match. That surfaces about 530 new
pyupgrade findings for annotations that no longer need to be 3.8 compatible;
those are tracked separately rather than mixed into this change.

Closes #139

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GypKU5KdLfs2Cf8kS2TzJa
@ESultanik
ESultanik merged commit 198c50f into master Sep 8, 2026
11 checks passed
@ESultanik
ESultanik deleted the 139-drop-python-38 branch September 8, 2026 20:25
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.

uv.lock resolves abandoned pycrypto via secretstorage 2.2.1 on Python <= 3.9

1 participant