Skip to content

build(deps): move to pgserviceparser 3, keep the GUI binding choice safe - #513

Merged
Guts merged 3 commits into
masterfrom
improve/pgserviceparser-3
Oct 18, 2026
Merged

Guts merged 3 commits into
masterfrom
improve/pgserviceparser-3

Conversation

@Guts

@Guts Guts commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

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

  • Bug fix (fix/… branch)
  • New feature or enhancement (feature/… branch)
  • Documentation (docs/… branch or *.md/docs/** changes)
  • Packaging / build (packaging/… branch or builder/** changes)
  • Tooling / CI-CD (tooling/… branch or .github/** changes)
  • Tests only (tests/** changes)

Checklist

  • I have read the Contributing Guidelines
  • pre-commit run --all-files passes locally (on the branch's changes)
  • I have added or updated tests covering my changes
  • I have updated the documentation where relevant (qt_compat docstring, CLAUDE.md)
  • pytest passes locally, apart from the environment failures listed above, identical on master

AI/LLM disclosure

https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ


Generated by Claude Code

@github-actions github-actions Bot added documentation Improvements or additions to documentation enhancement New feature or request packaging quality labels Oct 18, 2026
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.17%. Comparing base (ec7e96f) to head (d55ce15).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #513      +/-   ##
==========================================
+ Coverage   78.11%   78.17%   +0.05%     
==========================================
  Files          55       55              
  Lines        3473     3482       +9     
  Branches      424      425       +1     
==========================================
+ Hits         2713     2722       +9     
  Misses        639      639              
  Partials      121      121              
Flag Coverage Δ
unittests 78.11% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dicogis/ui/qt_compat/__init__.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Guts Guts mentioned this pull request Oct 18, 2026
7 of 11 tasks
@Guts
Guts force-pushed the improve/pgserviceparser-3 branch from 3973b67 to 8ec6a86 Compare October 18, 2026 08:09
@github-actions github-actions Bot added ci-cd Everything related to continuous integration and deployment tooling labels Oct 18, 2026
@Guts Guts changed the title build(deps): move to pgserviceparser 3 on Python 3.11+, keep the GUI binding choice safe build(deps): move to pgserviceparser 3, keep the GUI binding choice safe Oct 18, 2026
@Guts
Guts changed the base branch from master to packaging/drop-python-3.10 October 18, 2026 08:09
Guts added a commit that referenced this pull request Oct 18, 2026
## 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).

| Where | Change |
| --- | --- |
| `pyproject.toml` | `requires-python = ">=3.11, <4"`, 3.10 classifier
removed, ruff `target-version = "py311"` |
| `.pre-commit-config.yaml` | pyupgrade `--py311-plus` |
| `tester.yml` | 3.10 removed from the Ubuntu matrix (the Windows one
already started at 3.11, for lack of a cp310 GDAL wheel in the pinned
geospatial-wheels release) |
| `builder_releaser.yml` | Linux executables built with Python 3.11
instead of 3.10 — the Windows ones already used 3.11 |
| `docs_builder.yml` | docs built with 3.11 |
| `sonar-project.properties` | analyzed versions |
| `docs/development/` | Ubuntu and Windows setup pages |

No code change was needed: ruff with the py311 target and `pyupgrade
--py311-plus` find nothing to rewrite, and there was no 3.10-specific
code path. The `ExtendedEnum.has_value()` helper stays: membership
testing an `Enum` with a plain value still raises `TypeError` on 3.11
(it only works from 3.12).

### Verification

- `pre-commit run` passes on the branch's changes.
- Installing on Python 3.10 is now refused by the resolver
(`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

- [ ] 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)
- [ ] I have added or updated tests covering my changes (CI matrix
change only)
- [x] I have updated the documentation where relevant
- [x] `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

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Dwmm8jY9WWvgUJt9WQ7QWZ)_
Base automatically changed from packaging/drop-python-3.10 to master October 18, 2026 11:27
In auto mode, the Qt binding was qgis.PyQt as soon as a "qgis" package was imported. But some libraries import qgis.PyQt on their own when QGIS is installed: pgserviceparser >= 3 does, at import time, through its new gui subpackage. And QGIS's own qgis/__init__.py imports qgis.gui, hence qgis.core: a standalone dicogis-gui on a machine with QGIS installed (python3-qgis on Linux) would then load QGIS and could switch to its binding, possibly Qt 5 with QGIS 3. Today only the import order of dicogis-gui avoided it, by resolving the binding before pgserviceparser is imported.

auto now checks that the running Qt application is a QgsApplication, looking only at an already loaded qgis.core, never importing QGIS itself. Inside QGIS (desktop, plugin, qgis_process) one is running; in a standalone process it isn't, whatever got imported.

Tests cover QGIS absent, imported without application (the pgserviceparser case, failing on the previous detection), a plain Qt application, running, and a failing check, both in-process and in subprocesses with a fake qgis package.

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
pgserviceparser 3.0 (2026-02) requires Python >= 3.11, now DicoGIS's floor. Require >= 3.0.3, the latest fix release.

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: 3.x only adds functions, an optional sorted_alphabetically argument to service_names(), and retries writes on read-only service files.

Side effect of 3.x, out of DicoGIS's hands: "import pgserviceparser" now tries to import its new Qt GUI, through qgis.PyQt when QGIS is installed, else PyQt6 when installed, whatever extras were requested. dicogis-cli thus loads PyQt6 when the gui extra is installed (listing import: 16 -> 48 ms here); the previous commit keeps the GUI's binding choice safe from it.

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
The image runs Python 3.11+, so it resolves the new pgserviceparser range; update the exact pin accordingly. The Docker workflow builds and smoke-tests the image on this change.

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
@Guts
Guts force-pushed the improve/pgserviceparser-3 branch from 8ec6a86 to d55ce15 Compare October 18, 2026 11:34
@sonarqubecloud

Copy link
Copy Markdown

@Guts
Guts merged commit a6ff084 into master Oct 18, 2026
19 checks passed
@Guts
Guts deleted the improve/pgserviceparser-3 branch October 18, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cd Everything related to continuous integration and deployment documentation Improvements or additions to documentation enhancement New feature or request packaging quality tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants