1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-03-04 16:02:51 +01:00

refactor(dock_area): change name to BECDockArea

This commit is contained in:
2026-01-30 12:29:12 +01:00
committed by Jan Wyzula
parent 577ca4301a
commit 40a666aa18
21 changed files with 118 additions and 131 deletions

View File

@@ -2,15 +2,15 @@ from __future__ import annotations
from bec_lib import bec_logger
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea
logger = bec_logger.logger
def dock_area(
object_name: str | None = None, profile: str | None = None, start_empty: bool = False
) -> AdvancedDockArea:
) -> BECDockArea:
"""
Create an advanced dock area using Qt Advanced Docking System.
@@ -20,7 +20,7 @@ def dock_area(
start_empty(bool): If True, start with an empty dock area when loading specified profile.
Returns:
AdvancedDockArea: The created advanced dock area.
BECDockArea: The created advanced dock area.
Note:
The "general" profile is mandatory and will always exist. If manually deleted,
@@ -29,7 +29,7 @@ def dock_area(
# Default to "general" profile when called from CLI without specifying a profile
effective_profile = profile if profile is not None else "general"
widget = AdvancedDockArea(
widget = BECDockArea(
object_name=object_name,
restore_initial_profile=True,
root_widget=True,
@@ -51,7 +51,7 @@ def auto_update_dock_area(object_name: str | None = None) -> AutoUpdates:
object_name(str): The name of the dock area.
Returns:
AdvancedDockArea: The created dock area.
BECDockArea: The created dock area.
"""
_auto_update = AutoUpdates(object_name=object_name)
return _auto_update

View File

@@ -29,12 +29,9 @@ from bec_widgets.utils.plugin_utils import get_plugin_auto_updates
from bec_widgets.utils.round_frame import RoundedFrame
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
from bec_widgets.utils.ui_loader import UILoader
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
get_last_profile,
list_profiles,
)
from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea
from bec_widgets.widgets.containers.dock_area.profile_utils import get_last_profile, list_profiles
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow, BECMainWindowNoRPC
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
@@ -428,7 +425,7 @@ class LaunchWindow(BECMainWindow):
from bec_widgets.applications import bw_launch
with RPCRegister.delayed_broadcast() as rpc_register:
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(AdvancedDockArea)
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(BECDockArea)
if name is not None:
WidgetContainerUtils.raise_for_invalid_name(name)
# If name already exists, generate a unique one with counter suffix

View File

@@ -7,7 +7,7 @@ from bec_widgets.applications.views.developer_view.developer_view import Develop
from bec_widgets.applications.views.device_manager_view.device_manager_view import DeviceManagerView
from bec_widgets.applications.views.view import ViewBase, WaveformViewInline, WaveformViewPopup
from bec_widgets.utils.colors import apply_theme
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
@@ -45,7 +45,7 @@ class BECMainApp(BECMainWindow):
def _add_views(self):
self.add_section("BEC Applications", "bec_apps")
self.ads = AdvancedDockArea(self, profile_namespace="bec", auto_profile_namespace=False)
self.ads = BECDockArea(self, profile_namespace="bec", auto_profile_namespace=False)
self.ads.setObjectName("MainWorkspace")
self.device_manager = DeviceManagerView(self)
self.developer_view = DeveloperView(self)

View File

@@ -13,8 +13,8 @@ from bec_widgets.utils.error_popups import SafeSlot
from bec_widgets.utils.toolbars.actions import MaterialIconAction
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea
from bec_widgets.widgets.containers.qt_ads import CDockWidget
from bec_widgets.widgets.editors.monaco.monaco_dock import MonacoDock
from bec_widgets.widgets.editors.monaco.monaco_widget import MonacoWidget
@@ -99,7 +99,7 @@ class DeveloperWidget(DockAreaWidget):
self.monaco = MonacoDock(self)
self.monaco.setObjectName("MonacoEditor")
self.monaco.save_enabled.connect(self._on_save_enabled_update)
self.plotting_ads = AdvancedDockArea(
self.plotting_ads = BECDockArea(
self,
mode="plot",
default_add_direction="bottom",

View File

@@ -38,7 +38,7 @@ from bec_widgets.utils.error_popups import SafeSlot
from bec_widgets.utils.toolbars.actions import MaterialIconAction
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.control.device_manager.components import (
DeviceTable,
DMConfigView,

View File

@@ -90,7 +90,63 @@ except ImportError as e:
logger.error(f"Failed loading plugins: \n{reduce(add, traceback.format_exception(e))}")
class AdvancedDockArea(RPCBase):
class AutoUpdates(RPCBase):
@property
@rpc_call
def enabled(self) -> "bool":
"""
Get the enabled status of the auto updates.
"""
@enabled.setter
@rpc_call
def enabled(self) -> "bool":
"""
Get the enabled status of the auto updates.
"""
@property
@rpc_call
def selected_device(self) -> "str | None":
"""
Get the selected device from the auto update config.
Returns:
str: The selected device. If no device is selected, None is returned.
"""
@selected_device.setter
@rpc_call
def selected_device(self) -> "str | None":
"""
Get the selected device from the auto update config.
Returns:
str: The selected device. If no device is selected, None is returned.
"""
class AvailableDeviceResources(RPCBase):
@rpc_call
def remove(self):
"""
Cleanup the BECConnector
"""
@rpc_call
def attach(self):
"""
None
"""
@rpc_call
def detach(self):
"""
Detach the widget from its parent dock widget (if widget is in the dock), making it a floating widget.
"""
class BECDockArea(RPCBase):
@rpc_call
def new(
self,
@@ -320,62 +376,6 @@ class AdvancedDockArea(RPCBase):
"""
class AutoUpdates(RPCBase):
@property
@rpc_call
def enabled(self) -> "bool":
"""
Get the enabled status of the auto updates.
"""
@enabled.setter
@rpc_call
def enabled(self) -> "bool":
"""
Get the enabled status of the auto updates.
"""
@property
@rpc_call
def selected_device(self) -> "str | None":
"""
Get the selected device from the auto update config.
Returns:
str: The selected device. If no device is selected, None is returned.
"""
@selected_device.setter
@rpc_call
def selected_device(self) -> "str | None":
"""
Get the selected device from the auto update config.
Returns:
str: The selected device. If no device is selected, None is returned.
"""
class AvailableDeviceResources(RPCBase):
@rpc_call
def remove(self):
"""
Cleanup the BECConnector
"""
@rpc_call
def attach(self):
"""
None
"""
@rpc_call
def detach(self):
"""
Detach the widget from its parent dock widget (if widget is in the dock), making it a floating widget.
"""
class BECMainWindow(RPCBase):
@rpc_call
def remove(self):

View File

@@ -7,7 +7,7 @@ from bec_lib.logger import bec_logger
from bec_lib.messages import ScanStatusMessage
from bec_widgets.utils.error_popups import SafeSlot
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
from bec_widgets.widgets.containers.qt_ads import CDockWidget
@@ -37,7 +37,7 @@ class AutoUpdates(BECMainWindow):
):
super().__init__(parent=parent, gui_id=gui_id, window_title=window_title, **kwargs)
self.dock_area = AdvancedDockArea(
self.dock_area = BECDockArea(
parent=self,
object_name="dock_area",
enable_profile_management=False,

View File

@@ -5,7 +5,7 @@ from typing import Literal, Mapping, Sequence
import slugify
from bec_lib import bec_logger
from qtpy.QtCore import QTimer, Signal
from qtpy.QtCore import Signal
from qtpy.QtGui import QPixmap
from qtpy.QtWidgets import (
QApplication,
@@ -31,8 +31,8 @@ from bec_widgets.utils.toolbars.actions import (
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
from bec_widgets.utils.widget_state_manager import WidgetStateManager
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
from bec_widgets.widgets.containers.dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.dock_area.profile_utils import (
SETTINGS_KEYS,
default_profile_candidates,
delete_profile_files,
@@ -55,14 +55,12 @@ from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
user_profile_candidates,
write_manifest,
)
from bec_widgets.widgets.containers.advanced_dock_area.settings.dialogs import (
from bec_widgets.widgets.containers.dock_area.settings.dialogs import (
RestoreProfileDialog,
SaveProfileDialog,
)
from bec_widgets.widgets.containers.advanced_dock_area.settings.workspace_manager import (
WorkSpaceManager,
)
from bec_widgets.widgets.containers.advanced_dock_area.toolbar_components.workspace_actions import (
from bec_widgets.widgets.containers.dock_area.settings.workspace_manager import WorkSpaceManager
from bec_widgets.widgets.containers.dock_area.toolbar_components.workspace_actions import (
WorkspaceConnection,
workspace_bundle,
)
@@ -90,7 +88,7 @@ _PROFILE_NAMESPACE_UNSET = object()
PROFILE_STATE_KEYS = {key: SETTINGS_KEYS[key] for key in ("geom", "state", "ads_state")}
class AdvancedDockArea(DockAreaWidget):
class BECDockArea(DockAreaWidget):
RPC = True
PLUGIN = False
USER_ACCESS = [
@@ -1163,7 +1161,7 @@ if __name__ == "__main__": # pragma: no cover
dispatcher = BECDispatcher(gui_id="ads")
window = BECMainWindowNoRPC()
ads = AdvancedDockArea(mode="creator", enable_profile_management=True, root_widget=True)
ads = BECDockArea(mode="creator", enable_profile_management=True, root_widget=True)
window.setCentralWidget(ads)
window.show()

View File

@@ -28,7 +28,7 @@ from qtpy.QtWidgets import (
from bec_widgets import BECWidget, SafeSlot
from bec_widgets.utils.colors import get_accent_colors
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
from bec_widgets.widgets.containers.dock_area.profile_utils import (
get_profile_info,
is_quick_select,
list_profiles,

View File

@@ -10,7 +10,7 @@ from bec_widgets import SafeSlot
from bec_widgets.utils.toolbars.actions import MaterialIconAction, WidgetAction
from bec_widgets.utils.toolbars.bundles import ToolbarBundle, ToolbarComponents
from bec_widgets.utils.toolbars.connections import BundleConnection
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import list_quick_profiles
from bec_widgets.widgets.containers.dock_area.profile_utils import list_quick_profiles
class ProfileComboBox(QComboBox):

View File

@@ -9,7 +9,7 @@ from bec_lib.macro_update_handler import has_executable_code
from qtpy.QtCore import QEvent, QTimer, Signal
from qtpy.QtWidgets import QFileDialog, QMessageBox, QToolButton, QWidget
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.containers.qt_ads import CDockAreaWidget, CDockWidget
from bec_widgets.widgets.editors.monaco.monaco_widget import MonacoWidget

View File

@@ -122,12 +122,12 @@ def test_rpc_gui_obj(connected_client_gui_obj, qtbot):
assert gui.windows["bec"] is gui.bec
mw = gui.bec
assert mw.__class__.__name__ == "RPCReference"
assert gui._ipython_registry[mw._gui_id].__class__.__name__ == "AdvancedDockArea"
assert gui._ipython_registry[mw._gui_id].__class__.__name__ == "BECDockArea"
xw = gui.new("X")
xw.delete_all()
assert xw.__class__.__name__ == "RPCReference"
assert gui._ipython_registry[xw._gui_id].__class__.__name__ == "AdvancedDockArea"
assert gui._ipython_registry[xw._gui_id].__class__.__name__ == "BECDockArea"
assert len(gui.windows) == 2
assert gui._gui_is_alive()

View File

@@ -3,13 +3,13 @@ from unittest import mock
import pytest
from bec_widgets.cli.client import AdvancedDockArea
from bec_widgets.cli.client import BECDockArea
from bec_widgets.cli.client_utils import BECGuiClient, _start_plot_process
@pytest.fixture
def cli_dock_area():
dock_area = AdvancedDockArea(gui_id="test")
dock_area = BECDockArea(gui_id="test")
with mock.patch.object(dock_area, "_run_rpc") as mock_rpc_call:
with mock.patch.object(dock_area, "_gui_is_alive", return_value=True):
yield dock_area, mock_rpc_call

View File

@@ -10,17 +10,14 @@ from qtpy.QtCore import QSettings, Qt, QTimer
from qtpy.QtGui import QPixmap
from qtpy.QtWidgets import QDialog, QMessageBox, QWidget
import bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area as basic_dock_module
import bec_widgets.widgets.containers.advanced_dock_area.profile_utils as profile_utils
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import (
AdvancedDockArea,
SaveProfileDialog,
)
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import (
import bec_widgets.widgets.containers.dock_area.basic_dock_area as basic_dock_module
import bec_widgets.widgets.containers.dock_area.profile_utils as profile_utils
from bec_widgets.widgets.containers.dock_area.basic_dock_area import (
DockAreaWidget,
DockSettingsDialog,
)
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
from bec_widgets.widgets.containers.dock_area.dock_area import BECDockArea, SaveProfileDialog
from bec_widgets.widgets.containers.dock_area.profile_utils import (
SETTINGS_KEYS,
default_profile_path,
get_profile_info,
@@ -31,20 +28,17 @@ from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
load_user_profile_screenshot,
open_default_settings,
open_user_settings,
plugin_profiles_dir,
read_manifest,
restore_user_from_default,
set_quick_select,
user_profile_path,
write_manifest,
)
from bec_widgets.widgets.containers.advanced_dock_area.settings.dialogs import (
from bec_widgets.widgets.containers.dock_area.settings.dialogs import (
PreviewPanel,
RestoreProfileDialog,
)
from bec_widgets.widgets.containers.advanced_dock_area.settings.workspace_manager import (
WorkSpaceManager,
)
from bec_widgets.widgets.containers.dock_area.settings.workspace_manager import WorkSpaceManager
from .client_mocks import mocked_client
@@ -52,7 +46,7 @@ from .client_mocks import mocked_client
@pytest.fixture
def advanced_dock_area(qtbot, mocked_client):
"""Create an AdvancedDockArea instance for testing."""
widget = AdvancedDockArea(client=mocked_client)
widget = BECDockArea(client=mocked_client)
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
yield widget
@@ -152,7 +146,7 @@ def workspace_manager_target():
"""Mock delete_profile that performs actual file deletion."""
from qtpy.QtWidgets import QMessageBox
from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
from bec_widgets.widgets.containers.dock_area.profile_utils import (
delete_profile_files,
is_profile_read_only,
)
@@ -190,7 +184,7 @@ def basic_dock_area(qtbot, mocked_client):
class _NamespaceProfiles:
"""Helper that routes profile file helpers through a namespace."""
def __init__(self, widget: AdvancedDockArea):
def __init__(self, widget: BECDockArea):
self.namespace = widget.profile_namespace
def open_user(self, name: str):
@@ -215,7 +209,7 @@ class _NamespaceProfiles:
return is_quick_select(name, namespace=self.namespace)
def profile_helper(widget: AdvancedDockArea) -> _NamespaceProfiles:
def profile_helper(widget: BECDockArea) -> _NamespaceProfiles:
"""Return a helper wired to the widget's profile namespace."""
return _NamespaceProfiles(widget)
@@ -590,7 +584,7 @@ class TestAdvancedDockAreaInit:
def test_init(self, advanced_dock_area):
assert advanced_dock_area is not None
assert isinstance(advanced_dock_area, AdvancedDockArea)
assert isinstance(advanced_dock_area, BECDockArea)
assert advanced_dock_area.mode == "creator"
assert hasattr(advanced_dock_area, "dock_manager")
assert hasattr(advanced_dock_area, "toolbar")
@@ -598,8 +592,8 @@ class TestAdvancedDockAreaInit:
assert hasattr(advanced_dock_area, "state_manager")
def test_rpc_and_plugin_flags(self):
assert AdvancedDockArea.RPC is True
assert AdvancedDockArea.PLUGIN is False
assert BECDockArea.RPC is True
assert BECDockArea.PLUGIN is False
def test_user_access_list(self):
expected_methods = [
@@ -611,7 +605,7 @@ class TestAdvancedDockAreaInit:
"delete_all",
]
for method in expected_methods:
assert method in AdvancedDockArea.USER_ACCESS
assert method in BECDockArea.USER_ACCESS
class TestDockManagement:
@@ -1421,21 +1415,21 @@ class TestAdvancedDockAreaRestoreAndDialogs:
pix = QPixmap(8, 8)
pix.fill(Qt.red)
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.load_user_profile_screenshot",
"bec_widgets.widgets.containers.dock_area.dock_area.load_user_profile_screenshot",
lambda name, namespace=None: pix,
)
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.load_default_profile_screenshot",
"bec_widgets.widgets.containers.dock_area.dock_area.load_default_profile_screenshot",
lambda name, namespace=None: pix,
)
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.RestoreProfileDialog.confirm",
"bec_widgets.widgets.containers.dock_area.dock_area.RestoreProfileDialog.confirm",
lambda *args, **kwargs: True,
)
with (
patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.restore_user_from_default"
"bec_widgets.widgets.containers.dock_area.dock_area.restore_user_from_default"
) as mock_restore,
patch.object(advanced_dock_area, "delete_all") as mock_delete_all,
patch.object(advanced_dock_area, "load_profile") as mock_load_profile,
@@ -1457,20 +1451,20 @@ class TestAdvancedDockAreaRestoreAndDialogs:
advanced_dock_area._current_profile_name = profile_name
advanced_dock_area.isVisible = lambda: False
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.load_user_profile_screenshot",
"bec_widgets.widgets.containers.dock_area.dock_area.load_user_profile_screenshot",
lambda name: QPixmap(),
)
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.load_default_profile_screenshot",
"bec_widgets.widgets.containers.dock_area.dock_area.load_default_profile_screenshot",
lambda name: QPixmap(),
)
monkeypatch.setattr(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.RestoreProfileDialog.confirm",
"bec_widgets.widgets.containers.dock_area.dock_area.RestoreProfileDialog.confirm",
lambda *args, **kwargs: False,
)
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.restore_user_from_default"
"bec_widgets.widgets.containers.dock_area.dock_area.restore_user_from_default"
) as mock_restore:
advanced_dock_area.restore_user_profile_from_default()
@@ -1479,7 +1473,7 @@ class TestAdvancedDockAreaRestoreAndDialogs:
def test_restore_user_profile_from_default_no_target(self, advanced_dock_area, monkeypatch):
advanced_dock_area._current_profile_name = None
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.RestoreProfileDialog.confirm"
"bec_widgets.widgets.containers.dock_area.dock_area.RestoreProfileDialog.confirm"
) as mock_confirm:
advanced_dock_area.restore_user_profile_from_default()
mock_confirm.assert_not_called()
@@ -1723,8 +1717,7 @@ class TestWorkspaceProfileOperations:
return False
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.SaveProfileDialog",
StubDialog,
"bec_widgets.widgets.containers.dock_area.dock_area.SaveProfileDialog", StubDialog
):
advanced_dock_area.save_profile(profile_name, show_dialog=True)
@@ -1795,8 +1788,7 @@ class TestWorkspaceProfileOperations:
return False
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.SaveProfileDialog",
StubDialog,
"bec_widgets.widgets.containers.dock_area.dock_area.SaveProfileDialog", StubDialog
):
advanced_dock_area.save_profile(show_dialog=True)
@@ -1859,11 +1851,11 @@ class TestWorkspaceProfileOperations:
with (
patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.question",
"bec_widgets.widgets.containers.dock_area.dock_area.QMessageBox.question",
return_value=QMessageBox.Yes,
) as mock_question,
patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.information",
"bec_widgets.widgets.containers.dock_area.dock_area.QMessageBox.information",
return_value=None,
) as mock_info,
):
@@ -1893,7 +1885,7 @@ class TestWorkspaceProfileOperations:
mock_get_action.return_value.widget = mock_combo
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.question"
"bec_widgets.widgets.containers.dock_area.dock_area.QMessageBox.question"
) as mock_question:
mock_question.return_value = QMessageBox.Yes

View File

@@ -9,7 +9,7 @@ def test_rpc_widget_handler():
handler = RPCWidgetHandler()
assert "Image" in handler.widget_classes
assert "RingProgressBar" in handler.widget_classes
assert "AdvancedDockArea" in handler.widget_classes
assert "BECDockArea" in handler.widget_classes
class _TestPluginWidget(BECWidget): ...