Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions BlocksScreen/lib/panels/networkWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2710,9 +2710,6 @@ def _setup_saved_details_page(self) -> None:
self.low_priority_btn.setMaximumSize(QtCore.QSize(100, 100))
self.low_priority_btn.setCheckable(True)
self.low_priority_btn.setFlat(True)
self.low_priority_btn.setProperty(
"icon_pixmap", PixmapCache.get(":/ui/media/btn_icons/indf_svg.svg")
)
self.low_priority_btn.setText("Low")
self.low_priority_btn.setProperty("class", "back_btn")
self.low_priority_btn.setProperty("button_type", "icon")
Expand All @@ -2726,9 +2723,6 @@ def _setup_saved_details_page(self) -> None:
self.med_priority_btn.setCheckable(True)
self.med_priority_btn.setChecked(False) # Don't set default checked
self.med_priority_btn.setFlat(True)
self.med_priority_btn.setProperty(
"icon_pixmap", PixmapCache.get(":/ui/media/btn_icons/indf_svg.svg")
)
self.med_priority_btn.setText("Medium")
self.med_priority_btn.setProperty("class", "back_btn")
self.med_priority_btn.setProperty("button_type", "icon")
Expand All @@ -2742,9 +2736,6 @@ def _setup_saved_details_page(self) -> None:
self.high_priority_btn.setCheckable(True)
self.high_priority_btn.setChecked(False)
self.high_priority_btn.setFlat(True)
self.high_priority_btn.setProperty(
"icon_pixmap", PixmapCache.get(":/ui/media/btn_icons/indf_svg.svg")
)
self.high_priority_btn.setText("High")
self.high_priority_btn.setProperty("class", "back_btn")
self.high_priority_btn.setProperty("button_type", "icon")
Expand Down
10 changes: 0 additions & 10 deletions BlocksScreen/lib/panels/printTab.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,6 @@ def _on_delete_file_confirmed(self, filename: str, directory: str) -> None:
except (RuntimeError, TypeError):
pass

def setProperty(self, name: str, value: typing.Any) -> bool:
"""Intercept property changes."""
if name == "backgroundPixmap":
self.background = value
return super().setProperty(name, value)

def handle_cancel_print(self) -> None:
"""Handles the print cancel action"""
if (
Expand Down Expand Up @@ -493,10 +487,6 @@ def setupMainPrintPage(self) -> None:
self.setSizePolicy(sizePolicy)
self.setMinimumSize(QtCore.QSize(710, 410))
self.setMaximumSize(QtCore.QSize(720, 420))
self.setProperty(
"backgroundPixmap",
QtGui.QPixmap(":/background/media/graphics/scroll_list_window.svg"),
)
self.print_page = QtWidgets.QWidget()
sizePolicy = QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.Policy.MinimumExpanding,
Expand Down
5 changes: 4 additions & 1 deletion BlocksScreen/lib/panels/widgets/Common/popupDialogWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def __init__(self, parent) -> None:
self.message_type: Popup.MessageType = Popup.MessageType.INFO
self.default_background_color = QtGui.QColor(164, 164, 164)
self.info_icon = QtGui.QPixmap(":ui/media/btn_icons/info.svg")
self.warning_icon = QtGui.QPixmap(":ui/media/btn_icons/warning.svg")
# no warning asset yet; the yellow ColorCode signals severity
self.warning_icon = QtGui.QPixmap(":ui/media/btn_icons/error.svg")
self.error_icon = QtGui.QPixmap(":ui/media/btn_icons/error.svg")
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True)
self.setMouseTracking(True)
Expand Down Expand Up @@ -179,6 +180,8 @@ def _add_popup(self) -> None:
self.icon_label.setPixmap(self.warning_icon)
case Popup.MessageType.ERROR:
self.icon_label.setPixmap(self.error_icon)
case _:
self.icon_label.clear()

end_rect = self._calculate_target_geometry()
start_rect = end_rect.translated(0, -end_rect.height() * 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, parent) -> None:
self.decrease_button_icon = QtGui.QPixmap(
":/arrow_icons/media/btn_icons/left_arrow.svg"
)
self.background = QtGui.QPixmap(":/ui/background/media/1st_background.png")
self.background = QtGui.QPixmap(":/background/media/1st_background.png")
self.setStyleSheet(
"#SliderPage{background-image: url(:/background/media/1st_background.png);}\n"
)
Expand Down
3 changes: 0 additions & 3 deletions BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,6 @@ def _setup_ui(self) -> None:
self.current_offset_info.setFont(font)
self.current_offset_info.setStyleSheet("background: transparent; color: white;")
self.current_offset_info.setText("Z:0.000mm")
self.current_offset_info.setPixmap(
QtGui.QPixmap(":/graphics/media/btn_icons/z_offset_adjust.svg")
)
self.current_offset_info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.current_offset_info.setObjectName("current_offset_info")
# Add graphic frame AFTER the offset buttons group box
Expand Down
3 changes: 0 additions & 3 deletions BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,6 @@ def _setup_ui(self) -> None:
self.bbp_z_offset_current_value.setText(
f"Z: {round(self._pending_z_offset, 3) or 0.0:.3f} mm"
)
self.bbp_z_offset_current_value.setPixmap(
QtGui.QPixmap(":/graphics/media/btn_icons/z_offset_adjust.svg")
)
self.bbp_z_offset_current_value.setAlignment(
QtCore.Qt.AlignmentFlag.AlignCenter
)
Expand Down
2 changes: 1 addition & 1 deletion BlocksScreen/lib/utils/blocks_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
else:
qp.fillRect(rect, self._background_color)

if self.icon_pixmap:
if self.icon_pixmap is not None and not self.icon_pixmap.isNull():
icon_rect = QtCore.QRectF(
0.0 + self.icon_margin,
0.0 + self.icon_margin,
Expand Down
49 changes: 9 additions & 40 deletions tests/ui/test_resource_keys_unit.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
"""Guards Qt resource keys: no broken ':/' literal, no stale compiled blob.

Qt resolves an unknown ':/' key to a null QPixmap with no exception, no warning
and no log line. The only feedback is a blank rectangle on the panel, which is
how the keys in XFAIL_KEYS survived for months. These tests turn that silent
failure into a red test.
"""
"""Guards Qt resource keys: Qt renders an unknown ':/' key blank, silently."""

import importlib
import re
Expand All @@ -16,38 +10,15 @@
RESOURCES = PKG_ROOT / "lib" / "ui" / "resources"
RC_PACKAGE = "BlocksScreen.lib.ui.resources"

# Known-broken keys, measured 2026-08-31. This dict may only ever shrink:
# test_xfail_keys_are_still_broken fails once an entry stops being broken.
# Known-broken keys; may only shrink, enforced by the stale-entry test.
XFAIL_KEYS = {
":/background/media/graphics/scroll_list_window.svg": (
"asset is on disk but declared by no .qrc; retired by PR 3"
),
":/graphics/media/btn_icons/z_offset_adjust.svg": (
"asset deleted from the qrc in 927e43c (2025-06-04) and absent from "
"disk, yet 3 call sites still request it; retired by PR 3"
),
":/network/media/btn_icons/network/{b}bar_wifi{": (
"not broken at runtime: an f-string template the scanner cannot "
"evaluate, whose real keys are the 0bar..3bar matrix; the literal "
"disappears when the Icon enum replaces it in PR 8"
),
":/ui/background/media/1st_background.png": (
"duplicated prefix segment, real key is "
":/background/media/1st_background.png; retired by PR 3"
),
":/ui/media/btn_icons/indf_svg.svg": (
"no such file in any .qrc or on disk; retired by PR 3"
),
":/ui/media/btn_icons/warning.svg": (
"no such file in any .qrc or on disk, so the warning popup renders a "
"blank icon; needs a new asset, not just a key fix; retired by PR 3"
"evaluate, whose real keys are the 0bar..3bar matrix; retired by #324"
),
}

# Deliberately a text scan, not an AST walk: an AST walk only sees ast.Constant,
# so it would silently drop the wifi f-string template above. The optional slash
# catches ":ui/..." too, which Qt resolves the same as ":/ui/..." (verified) and
# which 6 sites in this package use. The trailing + excludes a bare ":".
# Text scan, not AST: AST misses f-strings; '/?' also matches ':ui/...'.
_LITERAL = re.compile(r'["\'](:/?[^"\'\s]+)["\']')


Expand All @@ -70,7 +41,7 @@ def _qrc_entries() -> list[tuple[str, Path]]:


def _qrc_keys() -> set[str]:
"""Return the resource keys declared by the .qrc XML, the developer-facing source."""
"""Return the resource keys declared by the .qrc XML."""
return {key for key, _ in _qrc_entries()}


Expand All @@ -80,7 +51,7 @@ def _literal_sites() -> dict[str, list[str]]:
for module in sorted((PKG_ROOT / "lib").rglob("*.py")):
if module.name.endswith("_rc.py"):
continue
text = module.read_text(errors="replace")
text = module.read_text(encoding="utf-8", errors="replace")
for number, line in enumerate(text.splitlines(), 1):
for match in _LITERAL.finditer(line):
where = f"{module.relative_to(REPO_ROOT)}:{number}"
Expand All @@ -94,15 +65,13 @@ def _qrc_prefix_roots() -> set[str]:


def _compiled_keys() -> set[str]:
"""Return the resource keys compiled into the _rc.py blobs, under our prefixes only."""
"""Return the resource keys compiled into the _rc.py blobs, our prefixes only."""
from PyQt6.QtCore import QDir, QDirIterator

for blob in sorted(RESOURCES.glob("*_rc.py")):
importlib.import_module(f"{RC_PACKAGE}.{blob.stem}")

# Walk our own prefixes, never ':/'. Qt registers its own style and PDF
# resources into the same tree as soon as QtGui/QtWidgets is imported, and
# which of those appear depends on what the rest of the suite imported first.
# Skip ':/': Qt's own resources land there, import-order dependent.
keys = set()
for root in _qrc_prefix_roots():
walk = QDirIterator(
Expand All @@ -123,7 +92,7 @@ def _report(header: str, detail: dict[str, list[str]]) -> str:


def test_resources_dir_is_findable():
"""Fail loudly if the path derivation breaks, so the other tests cannot pass empty."""
"""Fail loudly if path derivation breaks, so the other tests cannot pass empty."""
assert RESOURCES.is_dir(), f"resources dir not found at {RESOURCES}"
assert list(RESOURCES.glob("*.qrc")), f"no .qrc files under {RESOURCES}"

Expand Down
Loading