0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

fix(FPS): qtimer cleanup leaking

This commit is contained in:
2024-10-11 16:59:24 +02:00
committed by wyzula_j
parent f5f1f6c304
commit 3a22392780
2 changed files with 31 additions and 7 deletions

View File

@ -452,13 +452,14 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
self.fps_monitor.sigFpsUpdate.connect(self.update_fps_label) self.fps_monitor.sigFpsUpdate.connect(self.update_fps_label)
def unhook_fps_monitor(self): def unhook_fps_monitor(self, delete_label=True):
"""Unhook the FPS monitor from the plot.""" """Unhook the FPS monitor from the plot."""
if self.fps_monitor is not None: if self.fps_monitor is not None:
# Remove Monitor # Remove Monitor
self.fps_monitor.cleanup() self.fps_monitor.cleanup()
self.fps_monitor.deleteLater() self.fps_monitor.deleteLater()
self.fps_monitor = None self.fps_monitor = None
if self.fps_label is not None and delete_label:
# Remove Label # Remove Label
self.removeItem(self.fps_label) self.removeItem(self.fps_label)
self.fps_label.deleteLater() self.fps_label.deleteLater()
@ -490,6 +491,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
def cleanup_pyqtgraph(self): def cleanup_pyqtgraph(self):
"""Cleanup pyqtgraph items.""" """Cleanup pyqtgraph items."""
self.unhook_crosshair() self.unhook_crosshair()
self.unhook_fps_monitor(delete_label=False)
self.tick_item.cleanup() self.tick_item.cleanup()
self.arrow_item.cleanup() self.arrow_item.cleanup()
item = self.plot_item item = self.plot_item

View File

@ -1,5 +1,8 @@
from unittest import mock
import pytest import pytest
from pytestqt.exceptions import TimeoutError as QtBotTimeoutError from pytestqt.exceptions import TimeoutError as QtBotTimeoutError
from qtpy.QtCore import QTimer
from qtpy.QtWidgets import QApplication from qtpy.QtWidgets import QApplication
from bec_widgets.cli.rpc_register import RPCRegister from bec_widgets.cli.rpc_register import RPCRegister
@ -7,6 +10,22 @@ from bec_widgets.qt_utils import error_popups
from bec_widgets.utils import bec_dispatcher as bec_dispatcher_module from bec_widgets.utils import bec_dispatcher as bec_dispatcher_module
class TestableQTimer(QTimer):
_instances = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
TestableQTimer._instances.append(self)
@classmethod
def check_all_stopped(cls, qtbot):
try:
qtbot.waitUntil(lambda: all(not timer.isActive() for timer in cls._instances))
except QtBotTimeoutError as exc:
raise TimeoutError("Failed to stop all timers") from exc
cls._instances = []
@pytest.hookimpl(tryfirst=True, hookwrapper=True) @pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object # execute all other hooks to obtain the report object
@ -18,13 +37,16 @@ def pytest_runtest_makereport(item, call):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def qapplication(qtbot, request): # pylint: disable=unused-argument def qapplication(qtbot, request): # pylint: disable=unused-argument
yield with mock.patch("qtpy.QtCore.QTimer", new=TestableQTimer):
yield
# if the test failed, we don't want to check for open widgets as # if the test failed, we don't want to check for open widgets as
# it simply pollutes the output # it simply pollutes the output
if request.node.stash._storage.get("failed"): if request.node.stash._storage.get("failed"):
print("Test failed, skipping cleanup checks") print("Test failed, skipping cleanup checks")
return return
TestableQTimer.check_all_stopped(qtbot)
qapp = QApplication.instance() qapp = QApplication.instance()
qapp.processEvents() qapp.processEvents()