fix: tray icons + QScreen import + CI system deps #3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/assets-and-ci"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fix: tray icons, QScreen import, and CI system deps
Three bugs in one PR — the first two you hit directly, the third was the CI failure.
1. Tray icons not loading (blue square)
Root cause:
ASSETS_DIRpointed tosrc/assets/which doesn't exist — the SVGs were at repo-rootassets/. Even if the path had been correct, the assets wouldn't be packaged withpip installbecause they were outside the Python package.Fix:
src/zai_tray_checker/assets/(inside the package)__init__.pyso it's a proper sub-packageASSETS_DIRwithimportlib.resources.files("zai_tray_checker.assets")— works from both source checkout and pip installlogger.warning()when fallback is used (was silently failing with no log message)pyproject.tomlpackage-data from../assets/*.svgtoassets/*.svg2. QScreen ImportError (from unmerged PR #2)
Still on main —
QScreenimported fromQtWidgets(wrong module), andQSvgRendererwas an inline import inside_load_svg_icon.Fix:
QScreen,QCursor→ module-level import fromPySide6.QtGuiQSvgRenderer→ module-level import fromPySide6.QtSvgfrom PySide6... importfrom method bodies3. CI fails on headless runner
The Debian runner has no
libGL.so.1/libglib-2.0.so.0, soimport PySide6itself fails.Fix:
apt-get installsystem GL/runtime libs before installing@pytest.mark.skipifto skip gracefully when PySide6 can't importTests: 45 total, all passing
test_api_client.pytest_config.pytest_peak_hours.pytest_gui_imports.pyNew
TestAssetBundlingclass verifies SVGs exist inside the package and__init__.pyis present.🤖 Hermes automated review: no blocking issues found
Reviewed base
50efb8c→ head82ae173(8 files, +279/−26). CI/CD: CI / test ✅ (21s) passed for head82ae173— local test run skipped per CI policy.This PR cleanly fixes three real bugs. All three root causes are correctly diagnosed and the fixes are sound:
✅ 1. Tray icons not loading (asset packaging)
The original
ASSETS_DIR = Path(__file__).parent.parent / "assets"pointed outside the package, so (a) it was wrong in source checkout and (b) the SVGs would never ship in apip install/ wheel. The fix is the correct modern approach:src/zai_tray_checker/assets/with an__init__.pymaking it a proper sub-package ✓_load_svg_icon(main.py:66-86) now usesimportlib.resources.files("zai_tray_checker.assets").joinpath(name).read_bytes()— the canonical Python 3.9+ idiom that works identically from a source tree and an installed package ✓renderer.isValid()check before rendering, with a loggedValueErrorif the renderer rejects the bytes ✓QPixmapandlogger.warning(...)s — previously this failed silently with no log line ✓pyproject.tomlpackage-datacorrected from the non-functional"../assets/*.svg"to the in-package"assets/*.svg"✓The bundled SVGs are minimal static files (only
<rect>/<text>/<circle>, nohref/xlink/<script>/external refs) — no SVG-injection or XXE surface.✅ 2. QScreen ImportError
QScreenis inPySide6.QtGui, notQtWidgets— the old import would raiseImportErrorat runtime when the panel was first toggled. Fix is correct:QScreen,QCursor→ module-level import fromPySide6.QtGui(main.py:14-21) ✓QSvgRenderer→ module-level import fromPySide6.QtSvg(main.py:22) ✓from PySide6... importstatements in_toggle_panelare removed (main.py:474-480) ✓self._app.primaryScreen()returns the realQScreen✓The new AST-based test
test_no_inline_pyside6_imports_in_methods(test_gui_imports.py:131-163) statically enforces that nofrom PySide6... importappears inside a function body — a good guard that prevents the same class of bug (hidden import that only fails on a specific code path) from regressing.✅ 3. CI on headless runner
ci.ymlnowapt-get installslibgl1 libglib2.0-0 libegl1 libfontconfig1 libdbus-1-3 libxkbcommon0before installing — these are the actual runtime libsimport PySide6.QtCore/QtGui/QtWidgetsneeds ✓2>/dev/null || trueon the apt step means a stale package index won't hard-fail the job, which is a reasonable trade-off for a self-hosted runner ✓@pytest.mark.skipif(not _pyside6_available(), ...)and skip gracefully when the C++ extensions can't load ✓_pyside6_available()now actually importsQtCore/QtGui/QtWidgetsrather than justimport PySide6, because the top-level wrapper imports successfully even when the underlying.sofiles are missing libs. This prevents the skipif guard from incorrectly returningTrue. Good catch.Minor / non-blocking
test_qscreen_not_in_qtwidgets(test_gui_imports.py) asserts thatQScreenis not importable fromQtWidgets. If a future PySide release re-exports it there, the test's failure message already notes the import inmain.pyshould still useQtGui— so the guard remains valid. Non-issue, just noting the intent is encoded._load_svg_icon's fallback branch (main.py:88-90) duplicates thepm.fill(QColor("#2563eb"))color that's also the "ok" icon background. Harmless; could be a module constant if more states are added later.|| trueon the CI apt step means a genuinely broken package mirror would let the job proceed and then fail with a confusing PySide import error rather than a clear apt error. Acceptable for a single-runner setup; worth revisiting if CI flakiness appears.Verdict: Three well-targeted fixes with correct root-cause analysis and good regression coverage (the AST inline-import test and the asset-bundling test would both catch their respective original bugs). CI green. No blocking issues.
Automated daily review. I never merge PRs. Note: this is a PR conversation comment with file:line references, not a formal Forgejo review approval — the MCP integration cannot create inline review comments or approval states.