Repository navigation
build!: drop Python 3.10 support - #514
Merged
Merged
Conversation
Python 3.10 reaches its end of life this month (October 2026), and dependencies already move on: pgserviceparser 3 requires Python >= 3.11. Raise the floor to 3.11: - pyproject.toml: requires-python ">=3.11, <4", 3.10 classifier removed, ruff target-version py311; - pre-commit: pyupgrade --py311-plus; - CI: 3.10 removed from the Ubuntu test matrix (Windows already started at 3.11, for lack of a cp310 GDAL wheel), Linux executables and docs built with 3.11 instead of 3.10, like the Windows executables already were; - SonarCloud analyzed Python versions, and the development setup docs. BREAKING CHANGE: DicoGIS no longer installs on Python 3.10. AI-Level: 7 (human specced, bots coded) AI-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ
|
8 of 11 tasks
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #514 +/- ##
=======================================
Coverage 78.11% 78.11%
=======================================
Files 55 55
Lines 3473 3473
Branches 424 424
=======================================
Hits 2713 2713
Misses 639 639
Partials 121 121
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
5 of 11 tasks
Guts
added a commit
that referenced
this pull request
Oct 18, 2026
> Stacked on #514 (base `packaging/drop-python-3.10`). **The build workflow only runs on pull requests targeting `master`**, so it will run once GitHub retargets this PR, after #514 is merged: that run is the real validation of the executables. ## Description Builds the Linux and Windows executables with **Python 3.14** instead of 3.11. Set once, in the workflow's global `PYTHON_VERSION`: the Windows job no longer overrides it. ### GDAL on Windows GDAL comes from a [cgohlke/geospatial-wheels](https://github.com/cgohlke/geospatial-wheels) wheel, previously hardcoded (GDAL 3.11.1, cp311, release v2025.7.4). That release does contain a cp314 wheel, but it was built on 4 July 2025, against a Python 3.14 **pre-release**, before the ABI was frozen at 3.14.0rc1. This PR uses **v2025.10.25**, the first release built after Python 3.14.0 final, with **GDAL 3.11.4**: same minor version as the Linux build (`3.11.*`). The wheel URL is now built from `GDAL_VERSION`, `GEOSPATIAL_WHEELS_RELEASE` and `PYTHON_VERSION` (the way `tester.yml` already does); the resulting URL was checked to resolve. ### Checked beforehand - **PyInstaller** allows Python 3.14 from 6.15.0 on (`requires_python` of earlier releases stops at `<3.14`); the current range `>=6.8.0,<6.23` resolves to 6.22.3 there, so no pin change. - **Compiled runtime dependencies** — PyQt6, PyQt6-Qt6, PyQt6-sip, lxml, numpy, charset-normalizer — all publish cp314 or abi3 wheels for Windows and Linux x86_64: no build from source during packaging. - **Linux GDAL bindings** are built from source against the system `libgdal`, as the Ubuntu 3.14 test job already does successfully. ### Windows tests aligned The Windows **test** matrix used the v2025.7.4 wheels (GDAL 3.11.1) and stopped at 3.13. It now uses the same release and GDAL version as the builder (v2025.10.25, GDAL 3.11.4, set through the same `GEOSPATIAL_WHEELS_RELEASE`/`GDAL_VERSION` env variables, with a note in both workflows to keep them in sync) and runs on **3.11 to 3.14**, like Ubuntu: the Python version shipped in the Windows executable is now unit-tested on Windows. The example wheel name in `docs/development/windows.md` follows. ## Related issue(s) Follows #514. ## Type of change - [ ] Bug fix (`fix/…` branch) - [ ] New feature or enhancement (`feature/…` branch) - [x] Documentation (`docs/…` branch or `*.md`/`docs/**` changes) - [x] Packaging / build (`packaging/…` branch or `builder/**` changes) - [x] Tooling / CI-CD (`tooling/…` branch or `.github/**` changes) - [ ] Tests only (`tests/**` changes) ## Checklist - [x] I have read the [Contributing Guidelines](/CONTRIBUTING.md) - [x] `pre-commit run --all-files` passes locally (on the branch's changes; workflow YAML validated, pre-commit.ci runs on the PR) - [ ] I have added or updated tests covering my changes (workflow change, validated by the build job itself) - [ ] I have updated the documentation where relevant (nothing documents the build's Python version) - [ ] `pytest` passes locally (no code change) ## AI/LLM disclosure - **Level**: 7 — human specced, bots coded. - **Model**: claude-opus-5-5 - **Session**: https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ --- _Generated by [Claude Code](https://claude.ai/code)_
Guts
added a commit
that referenced
this pull request
Oct 18, 2026
…afe (#513) ## Description Moves to pgserviceparser 3 (3.0.3, latest), and fixes a GUI binding issue its upgrade exposed. ### Dependency `pgserviceparser>=3.0.3,<4`. pgserviceparser 3.0 requires Python >= 3.11: Python 3.10 support was dropped in #514 (it previously kept 2.x on 3.10 through environment markers, no longer needed). The API DicoGIS uses (`conf_path`, `service_names`, `write_service`, `remove_service`, `ServiceFileNotFound`) has the same signatures in 2.5.0 and 3.0.3 (compared on both sources): 3.x only adds functions, an optional `sorted_alphabetically` argument to `service_names()`, and a retry on read-only service files. The Docker image pin moves to 3.0.3. ### The issue it exposed (first commit) `import pgserviceparser` 3.x tries to import its new Qt GUI, through `qgis.PyQt` when QGIS is installed, PyQt6 otherwise. And QGIS's own `qgis/__init__.py` imports `qgis.gui`, hence `qgis.core`. Measured, with a fake `qgis.PyQt` on the path standing in for an installed QGIS: - `dicogis.ui.qt_compat`'s `auto` mode picked `qgis.PyQt` as soon as a `qgis` package was imported: importing pgserviceparser before the GUI made a **standalone** run believe it was inside QGIS. Only the current import order of `dicogis-gui` (binding resolved before pgserviceparser is imported) avoided it. - With a QGIS 3 (Qt 5) `qgis.PyQt`, a standalone `dicogis-gui` ends up loading PyQt5 next to PyQt6 in the same process. No crash observed offscreen here, but that's fragile — and out of DicoGIS's hands, it's pgserviceparser importing QGIS. `auto` now selects `qgis.PyQt` only when the running Qt application is a `QgsApplication`, looking at an already loaded `qgis.core` without ever importing QGIS. Inside QGIS (desktop, plugin, `qgis_process`) one runs; standalone it doesn't, whatever got imported. Tests cover QGIS absent / imported without application (the pgserviceparser case — fails on the previous detection) / a plain Qt application / running / a failing check, in-process and in subprocesses. ### Remaining side effect, not fixable here pgserviceparser only has a `gui` extra (adding PyQt6), no GUI-free variant: its `__init__` tries to import the GUI in any case, and it succeeds whenever PyQt6 or `qgis.PyQt` is importable. So `dicogis-cli` now loads PyQt6 at import when DicoGIS's `gui` extra is installed (listing import: 16 → 48 ms here), and QGIS's libraries when QGIS is installed, both through pgserviceparser. Worth raising with pgserviceparser upstream: importing the core package shouldn't import a GUI toolkit. ### Verification - Real DicoGIS calls against a real `pg_service.conf` (missing file → `ServiceFileNotFound`, `store_in_pgservice_file()`, `service_names()`, connection string/URI, `check_usable_pg_services()`, `remove_service()`): identical results with 2.5.0 and 3.0.3. - Full suite on Python 3.12 with pgserviceparser 3.0.3: 482 passed, exactly the same failures as `master` with 2.5.0 in the same environment (no PostGIS instance, missing fixtures). - The Docker workflow built and smoke-tested the image with the 3.0.3 pin (first CI run of this PR, all green). ## Related issue(s) None. ## Type of change - [x] Bug fix (`fix/…` branch) - [x] New feature or enhancement (`feature/…` branch) - [ ] Documentation (`docs/…` branch or `*.md`/`docs/**` changes) - [x] Packaging / build (`packaging/…` branch or `builder/**` changes) - [ ] Tooling / CI-CD (`tooling/…` branch or `.github/**` changes) - [ ] Tests only (`tests/**` changes) ## Checklist - [x] I have read the [Contributing Guidelines](/CONTRIBUTING.md) - [x] `pre-commit run --all-files` passes locally (on the branch's changes) - [x] I have added or updated tests covering my changes - [x] I have updated the documentation where relevant (`qt_compat` docstring, `CLAUDE.md`) - [x] `pytest` passes locally, apart from the environment failures listed above, identical on `master` ## AI/LLM disclosure - **Level**: 7 — human specced, bots coded. - **Model**: claude-opus-5-5 - **Session**: https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ --- _Generated by [Claude Code](https://claude.ai/code)_
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Drops Python 3.10 support. 3.10 reaches its end of life this month (October 2026), and dependencies already move on: pgserviceparser 3 requires Python >= 3.11 (see #513, which needs environment markers only because of 3.10).
pyproject.tomlrequires-python = ">=3.11, <4", 3.10 classifier removed, rufftarget-version = "py311".pre-commit-config.yaml--py311-plustester.ymlbuilder_releaser.ymldocs_builder.ymlsonar-project.propertiesdocs/development/No code change was needed: ruff with the py311 target and
pyupgrade --py311-plusfind nothing to rewrite, and there was no 3.10-specific code path. TheExtendedEnum.has_value()helper stays: membership testing anEnumwith a plain value still raisesTypeErroron 3.11 (it only works from 3.12).Verification
pre-commit runpasses on the branch's changes.requires-python).Breaking change
DicoGIS no longer installs on Python 3.10. The executables are unaffected for end users (they embed their own Python), but the Linux ones are now built with 3.11: worth a quick smoke test of the next release build.
Related issue(s)
Unblocks a simpler #513 (no more environment markers for pgserviceparser).
Type of change
fix/…branch)feature/…branch)docs/…branch or*.md/docs/**changes)packaging/…branch orbuilder/**changes)tooling/…branch or.github/**changes)tests/**changes)Checklist
pre-commit run --all-filespasses locally (on the branch's changes)pytestpasses locally (no code change)AI/LLM disclosure
Generated by Claude Code