diff --git a/bec_widgets/__init__.py b/bec_widgets/__init__.py index f88f7db64..db034b2c0 100644 --- a/bec_widgets/__init__.py +++ b/bec_widgets/__init__.py @@ -1,19 +1,21 @@ import os import sys -import bec_widgets.widgets.containers.qt_ads as QtAds -from bec_widgets.utils.bec_widget import BECWidget -from bec_widgets.utils.error_popups import SafeProperty, SafeSlot - if sys.platform.startswith("linux"): qt_platform = os.environ.get("QT_QPA_PLATFORM", "") if qt_platform != "offscreen": os.environ["QT_QPA_PLATFORM"] = "xcb" -# Default QtAds configuration -QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.eConfigFlag.FocusHighlighting, True) -QtAds.CDockManager.setConfigFlag( - QtAds.CDockManager.eConfigFlag.RetainTabSizeWhenCloseButtonHidden, True -) - __all__ = ["BECWidget", "SafeSlot", "SafeProperty"] + + +def __getattr__(name: str): + if name == "BECWidget": + from bec_widgets.utils.bec_widget import BECWidget + + return BECWidget + if name in {"SafeProperty", "SafeSlot"}: + from bec_widgets.utils.error_popups import SafeProperty, SafeSlot + + return {"SafeProperty": SafeProperty, "SafeSlot": SafeSlot}[name] + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/__init__.py b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/__init__.py index b507c9d9f..e69de29bb 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/__init__.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/__init__.py @@ -1,2 +0,0 @@ -from .config_choice_dialog import ConfigChoiceDialog -from .device_form_dialog import DeviceFormDialog diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/device_form_dialog.py b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/device_form_dialog.py index 11f5f7019..736fa39ff 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/device_form_dialog.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/device_form_dialog.py @@ -8,14 +8,16 @@ from qtpy import QtCore, QtWidgets from bec_widgets.utils.error_popups import SafeSlot -from bec_widgets.widgets.control.device_manager.components import OphydValidation from bec_widgets.widgets.control.device_manager.components.device_config_template.device_config_template import ( DeviceConfigTemplate, ) from bec_widgets.widgets.control.device_manager.components.device_config_template.template_items import ( validate_name, ) -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation import ( + OphydValidation, +) +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, format_error_to_md, diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py index a192a7482..8d6574abc 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py @@ -12,7 +12,7 @@ from bec_widgets.utils.colors import get_accent_colors from bec_widgets.utils.error_popups import SafeSlot -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, get_validation_icons, diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_display_widget.py b/bec_widgets/applications/views/device_manager_view/device_manager_display_widget.py index d4d388a74..f7941d675 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_display_widget.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_display_widget.py @@ -13,6 +13,7 @@ from bec_lib.logger import bec_logger from bec_lib.messages import ConfigAction, ScanStatusMessage from bec_lib.plugin_helper import plugin_package_name, plugin_repo_path +from bec_lib.utils.import_utils import lazy_import_from from bec_qthemes import apply_theme, material_icon from qtpy.QtCore import QMetaObject, Qt, QThreadPool, Signal from qtpy.QtGui import QColor @@ -26,26 +27,18 @@ QWidget, ) -from bec_widgets.applications.views.device_manager_view.device_manager_dialogs import ( - ConfigChoiceDialog, - DeviceFormDialog, -) -from bec_widgets.applications.views.device_manager_view.device_manager_dialogs.upload_redis_dialog import ( - UploadRedisDialog, -) from bec_widgets.utils.colors import get_accent_colors 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.dock_area.basic_dock_area import DockAreaWidget -from bec_widgets.widgets.control.device_manager.components import ( +from bec_widgets.widgets.control.device_manager.components._util import SharedSelectionSignal +from bec_widgets.widgets.control.device_manager.components.device_table.device_table import ( DeviceTable, - DMConfigView, - DocstringView, - OphydValidation, ) -from bec_widgets.widgets.control.device_manager.components._util import SharedSelectionSignal +from bec_widgets.widgets.control.device_manager.components.dm_config_view import DMConfigView +from bec_widgets.widgets.control.device_manager.components.dm_docstring_view import DocstringView from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, @@ -61,8 +54,29 @@ if TYPE_CHECKING: # pragma: no cover from bec_lib.client import BECClient + from bec_widgets.applications.views.device_manager_view.device_manager_dialogs.upload_redis_dialog import ( + UploadRedisDialog, + ) + logger = bec_logger.logger +ConfigChoiceDialog = lazy_import_from( + "bec_widgets.applications.views.device_manager_view.device_manager_dialogs.config_choice_dialog", + ("ConfigChoiceDialog",), +) +DeviceFormDialog = lazy_import_from( + "bec_widgets.applications.views.device_manager_view.device_manager_dialogs.device_form_dialog", + ("DeviceFormDialog",), +) +UploadRedisDialog = lazy_import_from( + "bec_widgets.applications.views.device_manager_view.device_manager_dialogs.upload_redis_dialog", + ("UploadRedisDialog",), +) +OphydValidation = lazy_import_from( + "bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation", + ("OphydValidation",), +) + _yes_no_question = partial( QMessageBox.question, buttons=QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_view.py b/bec_widgets/applications/views/device_manager_view/device_manager_view.py index 797708479..36491fca2 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_view.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_view.py @@ -1,14 +1,17 @@ """Module for Device Manager View.""" +from bec_lib.utils.import_utils import lazy_import_from from qtpy.QtCore import QRect from qtpy.QtWidgets import QWidget -from bec_widgets.applications.views.device_manager_view.device_manager_widget import ( - DeviceManagerWidget, -) from bec_widgets.applications.views.view import ViewBase, ViewTourSteps from bec_widgets.utils.error_popups import SafeSlot +DeviceManagerWidget = lazy_import_from( + "bec_widgets.applications.views.device_manager_view.device_manager_widget", + ("DeviceManagerWidget",), +) + class DeviceManagerView(ViewBase): """ diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_widget.py b/bec_widgets/applications/views/device_manager_view/device_manager_widget.py index d6201500c..0658abcf4 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_widget.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_widget.py @@ -6,15 +6,18 @@ from bec_lib.bec_yaml_loader import yaml_load from bec_lib.logger import bec_logger +from bec_lib.utils.import_utils import lazy_import_from from bec_qthemes import material_icon from qtpy import QtCore, QtWidgets -from bec_widgets.applications.views.device_manager_view.device_manager_display_widget import ( - DeviceManagerDisplayWidget, -) from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.error_popups import SafeSlot +DeviceManagerDisplayWidget = lazy_import_from( + "bec_widgets.applications.views.device_manager_view.device_manager_display_widget", + ("DeviceManagerDisplayWidget",), +) + logger = bec_logger.logger diff --git a/bec_widgets/cli/rpc/rpc_widget_handler.py b/bec_widgets/cli/rpc/rpc_widget_handler.py index 83d9a04d4..ff7ae4fea 100644 --- a/bec_widgets/cli/rpc/rpc_widget_handler.py +++ b/bec_widgets/cli/rpc/rpc_widget_handler.py @@ -1,9 +1,19 @@ from __future__ import annotations -from bec_widgets.cli.client_utils import IGNORE_WIDGETS -from bec_widgets.utils.bec_plugin_helper import get_all_plugin_widgets -from bec_widgets.utils.bec_widget import BECWidget -from bec_widgets.utils.plugin_utils import get_custom_classes +from typing import TYPE_CHECKING + +from bec_lib.utils.import_utils import lazy_import_from + +from bec_widgets.utils.bec_plugin_helper import get_all_plugin_widget_references +from bec_widgets.utils.plugin_utils import get_custom_class_references + +try: + from bec_widgets.cli.constants import IGNORE_WIDGETS +except ModuleNotFoundError: # pragma: no cover + IGNORE_WIDGETS = ["LaunchWindow"] + +if TYPE_CHECKING: # pragma: no cover + from bec_widgets.utils.bec_widget import BECWidget class RPCWidgetHandler: @@ -13,7 +23,7 @@ def __init__(self): self._widget_classes = None @property - def widget_classes(self) -> dict[str, type[BECWidget]]: + def widget_classes(self) -> dict[str, type["BECWidget"]]: """ Get the available widget classes. @@ -31,12 +41,24 @@ def update_available_widgets(self): Returns: None """ - self._widget_classes = ( - get_custom_classes("bec_widgets", packages=("widgets", "applications")) - + get_all_plugin_widgets() - ).as_dict(IGNORE_WIDGETS) + ignored = set(IGNORE_WIDGETS) + widget_classes = { + reference.name: lazy_import_from(reference.module, (reference.name,)) + for reference in get_all_plugin_widget_references() + if reference.name not in ignored + } + widget_classes.update( + { + reference.name: lazy_import_from(reference.module, (reference.name,)) + for reference in get_custom_class_references( + "bec_widgets", packages=("widgets", "applications") + ) + if reference.name not in ignored + } + ) + self._widget_classes = widget_classes - def create_widget(self, widget_type, **kwargs) -> BECWidget: + def create_widget(self, widget_type, **kwargs) -> "BECWidget": """ Create a widget from an RPC message. diff --git a/bec_widgets/utils/__init__.py b/bec_widgets/utils/__init__.py index 9d5848498..e69de29bb 100644 --- a/bec_widgets/utils/__init__.py +++ b/bec_widgets/utils/__init__.py @@ -1,13 +0,0 @@ -from qtpy.QtWebEngineWidgets import QWebEngineView - -from .bec_connector import BECConnector, ConnectionConfig -from .bec_dispatcher import BECDispatcher -from .bec_table import BECTable -from .colors import Colors -from .container_utils import WidgetContainerUtils -from .crosshair import Crosshair -from .entry_validator import EntryValidator -from .layout_manager import GridLayoutManager -from .rpc_decorator import register_rpc_methods, rpc_public -from .ui_loader import UILoader -from .validator_delegate import DoubleValidationDelegate diff --git a/bec_widgets/utils/bec_plugin_helper.py b/bec_widgets/utils/bec_plugin_helper.py index 242adbdc0..c1fa88b94 100644 --- a/bec_widgets/utils/bec_plugin_helper.py +++ b/bec_widgets/utils/bec_plugin_helper.py @@ -1,7 +1,9 @@ from __future__ import annotations +import ast import importlib.metadata import inspect +import os import pkgutil import traceback from importlib import util as importlib_util @@ -11,11 +13,61 @@ from bec_lib.logger import bec_logger -from bec_widgets.utils.plugin_utils import BECClassContainer, BECClassInfo +from bec_widgets.utils.plugin_utils import ( + BECClassContainer, + BECClassInfo, + BECClassReference, + _ast_node_name, + _class_has_rpc_markers, +) logger = bec_logger.logger +def _plugin_class_is_candidate(node: ast.ClassDef) -> bool: + base_names = {_ast_node_name(base) for base in node.bases} + return bool({"BECWidget", "BECConnector"} & base_names) or _class_has_rpc_markers(node) + + +def get_all_plugin_widget_references() -> list[BECClassReference]: + references: list[BECClassReference] = [] + seen_names: set[str] = set() + for entry_point in importlib.metadata.entry_points(group="bec.widgets.user_widgets"): # type: ignore + spec = importlib_util.find_spec(entry_point.module) + if spec is None: + continue + + package_roots = list(spec.submodule_search_locations or ()) + if spec.origin and not package_roots: + package_roots = [os.path.dirname(spec.origin)] + + for package_root in package_roots: + for root, _, files in sorted(os.walk(package_root)): + for file_name in sorted(files): + if not file_name.endswith(".py") or file_name.startswith("__"): + continue + path = os.path.join(root, file_name) + with open(path, encoding="utf-8") as file_handle: + module = ast.parse(file_handle.read(), filename=path) + module_name = ".".join( + os.path.relpath(path, package_root).removesuffix(".py").split(os.sep) + ) + for node in module.body: + if not isinstance(node, ast.ClassDef) or not _plugin_class_is_candidate( + node + ): + continue + if node.name in seen_names: + continue + references.append( + BECClassReference( + name=node.name, module=f"{entry_point.module}.{module_name}" + ) + ) + seen_names.add(node.name) + return references + + def _submodule_specs(module: ModuleType) -> tuple[ModuleSpec | None, ...]: """Return specs for all submodules of the given module.""" return tuple( diff --git a/bec_widgets/utils/plugin_utils.py b/bec_widgets/utils/plugin_utils.py index 32ac9c9d1..433c35161 100644 --- a/bec_widgets/utils/plugin_utils.py +++ b/bec_widgets/utils/plugin_utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import ast import importlib import inspect import os @@ -7,16 +8,16 @@ from typing import TYPE_CHECKING, Iterable from bec_lib.plugin_helper import _get_available_plugins -from qtpy.QtWidgets import QWidget - -from bec_widgets.utils import BECConnector -from bec_widgets.utils.bec_widget import BECWidget if TYPE_CHECKING: # pragma: no cover + from bec_widgets.utils.bec_connector import BECConnector + from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates +_DISCOVERY_BASE_NAMES = frozenset({"BECConnector", "BECWidget", "ViewBase"}) + -def get_plugin_widgets() -> dict[str, BECConnector]: +def get_plugin_widgets() -> dict[str, "BECConnector"]: """ Get all available widgets from the plugin directory. Widgets are classes that inherit from BECConnector. The plugins are provided through python plugins and specified in the respective pyproject.toml file using @@ -48,6 +49,8 @@ def get_plugin_widgets() -> dict[str, BECConnector]: def _filter_plugins(obj): + from bec_widgets.utils.bec_connector import BECConnector + return inspect.isclass(obj) and issubclass(obj, BECConnector) @@ -90,14 +93,20 @@ class BECClassInfo: name: str module: str file: str - obj: type[BECWidget] + obj: type["BECWidget"] is_connector: bool = False is_widget: bool = False is_plugin: bool = False +@dataclass(frozen=True) +class BECClassReference: + name: str + module: str + + class BECClassContainer: - def __init__(self, initial: Iterable[BECClassInfo] = []): + def __init__(self, initial: Iterable[BECClassInfo] = ()): self._collection: list[BECClassInfo] = list(initial) def __repr__(self): @@ -109,12 +118,13 @@ def __iter__(self): def __add__(self, other: BECClassContainer): return BECClassContainer((*self, *(c for c in other if c.name not in self.names))) - def as_dict(self, ignores: list[str] = []) -> dict[str, type[BECWidget]]: + def as_dict(self, ignores: list[str] | None = None) -> dict[str, type["BECWidget"]]: """get a dict of {name: Type} for all the entries in the collection. Args: ignores(list[str]): a list of class names to exclude from the dictionary.""" - return {c.name: c.obj for c in self if c.name not in ignores} + ignore_set = set(ignores or ()) + return {c.name: c.obj for c in self if c.name not in ignore_set} def add_class(self, class_info: BECClassInfo): """ @@ -166,48 +176,126 @@ def classes(self): return [info.obj for info in self.collection] -def _collect_classes_from_package(repo_name: str, package: str) -> BECClassContainer: - """Collect classes from a package subtree (for example ``widgets`` or ``applications``).""" - collection = BECClassContainer() +def _ast_node_name(node: ast.expr) -> str | None: + if isinstance(node, ast.Name): + return node.id + if isinstance(node, ast.Attribute): + return node.attr + return None + + +def _class_has_rpc_markers(node: ast.ClassDef) -> bool: + for stmt in node.body: + if isinstance(stmt, ast.Assign): + target_names = {target.id for target in stmt.targets if isinstance(target, ast.Name)} + if ( + "PLUGIN" in target_names + and isinstance(stmt.value, ast.Constant) + and stmt.value.value + ): + return True + if {"RPC_CONTENT_CLASS", "USER_ACCESS"} & target_names: + return True + if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name): + if ( + stmt.target.id == "PLUGIN" + and isinstance(stmt.value, ast.Constant) + and stmt.value.value + ): + return True + if stmt.target.id in {"RPC_CONTENT_CLASS", "USER_ACCESS"}: + return True + return False + + +def _class_is_candidate(node: ast.ClassDef) -> bool: + base_names = {_ast_node_name(base) for base in node.bases} + return bool(_DISCOVERY_BASE_NAMES & base_names) or _class_has_rpc_markers(node) + + +def _candidate_top_level_class_names(path: str) -> list[str]: + with open(path, encoding="utf-8") as file_handle: + module = ast.parse(file_handle.read(), filename=path) + return [ + node.name + for node in module.body + if isinstance(node, ast.ClassDef) and _class_is_candidate(node) + ] + + +def _iter_candidate_modules(repo_name: str, package: str) -> Iterable[tuple[str, str, list[str]]]: try: anchor_module = importlib.import_module(f"{repo_name}.{package}") except ModuleNotFoundError as exc: - # Some plugin repositories expose only one subtree. Skip gracefully if it does not exist. if exc.name == f"{repo_name}.{package}": - return collection + return () raise directory = os.path.dirname(anchor_module.__file__) - for root, _, files in sorted(os.walk(directory)): - for file in files: - if not file.endswith(".py") or file.startswith("__"): - continue + return ( + (f"{repo_name}.{package}.{module_name}", path, class_names) + for root, _, files in sorted(os.walk(directory)) + for file_name in sorted(files) + if file_name.endswith(".py") + and not file_name.startswith("__") + and not file_name.startswith("register_") + and not file_name.endswith("_plugin.py") + for path in (os.path.join(root, file_name),) + for rel_dir in (os.path.dirname(os.path.relpath(path, directory)),) + for module_name in ( + [ + ( + file_name.removesuffix(".py") + if rel_dir in ("", ".") + else ".".join(rel_dir.split(os.sep) + [file_name.removesuffix(".py")]) + ) + ] + ) + for class_names in (_candidate_top_level_class_names(path),) + if class_names + ) - path = os.path.join(root, file) - rel_dir = os.path.dirname(os.path.relpath(path, directory)) - if rel_dir in ("", "."): - module_name = file.split(".")[0] - else: - module_name = ".".join(rel_dir.split(os.sep) + [file.split(".")[0]]) - module = importlib.import_module(f"{repo_name}.{package}.{module_name}") +def _collect_classes_from_package(repo_name: str, package: str) -> BECClassContainer: + """Collect classes from a package subtree (for example ``widgets`` or ``applications``).""" + collection = BECClassContainer() + for module_name, path, _ in _iter_candidate_modules(repo_name, package): + from qtpy.QtWidgets import QWidget - for name in dir(module): - obj = getattr(module, name) - if not hasattr(obj, "__module__") or obj.__module__ != module.__name__: - continue - if isinstance(obj, type): - class_info = BECClassInfo(name=name, module=module.__name__, file=path, obj=obj) - if issubclass(obj, BECConnector): - class_info.is_connector = True - if issubclass(obj, QWidget) or issubclass(obj, BECWidget): - class_info.is_widget = True - if hasattr(obj, "PLUGIN") and obj.PLUGIN: - class_info.is_plugin = True - collection.add_class(class_info) + from bec_widgets.utils.bec_connector import BECConnector + from bec_widgets.utils.bec_widget import BECWidget + + module = importlib.import_module(module_name) + for name, obj in inspect.getmembers(module, inspect.isclass): + if obj.__module__ != module.__name__: + continue + class_info = BECClassInfo(name=name, module=module.__name__, file=path, obj=obj) + if issubclass(obj, BECConnector): + class_info.is_connector = True + if issubclass(obj, QWidget) or issubclass(obj, BECWidget): + class_info.is_widget = True + if hasattr(obj, "PLUGIN") and obj.PLUGIN: + class_info.is_plugin = True + collection.add_class(class_info) return collection +def get_custom_class_references( + repo_name: str, packages: tuple[str, ...] | None = None +) -> list[BECClassReference]: + selected_packages = packages or ("widgets",) + references: list[BECClassReference] = [] + seen_names: set[str] = set() + for package in selected_packages: + for module_name, _, class_names in _iter_candidate_modules(repo_name, package): + for class_name in class_names: + if class_name in seen_names: + continue + references.append(BECClassReference(name=class_name, module=module_name)) + seen_names.add(class_name) + return references + + def get_custom_classes( repo_name: str, packages: tuple[str, ...] | None = None ) -> BECClassContainer: diff --git a/bec_widgets/utils/rpc_server.py b/bec_widgets/utils/rpc_server.py index 18b533c47..189393075 100644 --- a/bec_widgets/utils/rpc_server.py +++ b/bec_widgets/utils/rpc_server.py @@ -15,8 +15,8 @@ from redis.exceptions import RedisError from bec_widgets.cli.rpc.rpc_register import RPCRegister -from bec_widgets.utils import BECDispatcher from bec_widgets.utils.bec_connector import BECConnector +from bec_widgets.utils.bec_dispatcher import BECDispatcher from bec_widgets.utils.container_utils import WidgetContainerUtils from bec_widgets.utils.error_popups import ErrorPopupUtility from bec_widgets.utils.screen_utils import apply_window_geometry @@ -25,7 +25,6 @@ if TYPE_CHECKING: # pragma: no cover from bec_lib import messages - from qtpy.QtCore import QObject else: messages = lazy_import("bec_lib.messages") logger = bec_logger.logger diff --git a/bec_widgets/utils/widget_io.py b/bec_widgets/utils/widget_io.py index 9a454861f..aab7f29e5 100644 --- a/bec_widgets/utils/widget_io.py +++ b/bec_widgets/utils/widget_io.py @@ -26,7 +26,7 @@ from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch if TYPE_CHECKING: # pragma: no cover - from bec_widgets.utils import BECConnector + from bec_widgets.utils.bec_connector import BECConnector logger = bec_logger.logger @@ -418,7 +418,7 @@ def print_widget_hierarchy( only_bec_widgets(bool, optional): Whether to print only widgets that are instances of BECWidget. show_parent(bool, optional): Whether to display which BECWidget is the parent of each discovered BECWidget. """ - from bec_widgets.utils import BECConnector + from bec_widgets.utils.bec_connector import BECConnector from bec_widgets.widgets.plots.waveform.waveform import Waveform for node in WidgetHierarchy.iter_widget_tree( @@ -468,7 +468,7 @@ def print_becconnector_hierarchy_from_app(): from qtpy.QtWidgets import QApplication - from bec_widgets.utils import BECConnector + from bec_widgets.utils.bec_connector import BECConnector from bec_widgets.widgets.plots.plot_base import PlotBase # 1) Gather ALL QWidget-based BECConnector objects @@ -534,7 +534,7 @@ def get_becwidget_ancestor(widget): Returns: The nearest ancestor that is a BECConnector, or None if not found. """ - from bec_widgets.utils import BECConnector + from bec_widgets.utils.bec_connector import BECConnector # Guard against deleted/invalid Qt wrappers if not shb.isValid(widget): @@ -636,7 +636,7 @@ def get_bec_connectors_from_parent(widget) -> list: Return all BECConnector instances whose closest BECConnector ancestor is the given widget, including the widget itself if it is a BECConnector. """ - from bec_widgets.utils import BECConnector + from bec_widgets.utils.bec_connector import BECConnector connectors: list[BECConnector] = [] if isinstance(widget, BECConnector): @@ -664,7 +664,7 @@ def find_ancestor( return None try: - from bec_widgets.utils import BECConnector # local import to avoid cycles + from bec_widgets.utils.bec_connector import BECConnector # local import to avoid cycles is_bec_target = False if isinstance(ancestor_class, str): diff --git a/bec_widgets/widgets/containers/dock_area/dock_area.py b/bec_widgets/widgets/containers/dock_area/dock_area.py index 3a86e8c14..1ebd86736 100644 --- a/bec_widgets/widgets/containers/dock_area/dock_area.py +++ b/bec_widgets/widgets/containers/dock_area/dock_area.py @@ -21,7 +21,7 @@ from bec_widgets import BECWidget, SafeProperty, SafeSlot from bec_widgets.applications.views.view import ViewTourSteps from bec_widgets.cli.rpc.rpc_widget_handler import widget_handler -from bec_widgets.utils import BECDispatcher +from bec_widgets.utils.bec_dispatcher import BECDispatcher from bec_widgets.utils.colors import apply_theme from bec_widgets.utils.rpc_decorator import rpc_timeout from bec_widgets.utils.toolbars.actions import ( @@ -68,7 +68,7 @@ from bec_widgets.widgets.containers.main_window.main_window import BECMainWindowNoRPC from bec_widgets.widgets.containers.qt_ads import CDockWidget from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox, PositionerBox2D -from bec_widgets.widgets.control.scan_control import ScanControl +from bec_widgets.widgets.control.scan_control.scan_control import ScanControl from bec_widgets.widgets.editors.web_console.web_console import BECShell, WebConsole from bec_widgets.widgets.plots.heatmap.heatmap import Heatmap from bec_widgets.widgets.plots.image.image import Image diff --git a/bec_widgets/widgets/containers/main_window/addons/notification_center/notification_banner.py b/bec_widgets/widgets/containers/main_window/addons/notification_center/notification_banner.py index 4b99a48f8..53f7a204b 100644 --- a/bec_widgets/widgets/containers/main_window/addons/notification_center/notification_banner.py +++ b/bec_widgets/widgets/containers/main_window/addons/notification_center/notification_banner.py @@ -28,7 +28,7 @@ from qtpy.QtWidgets import QApplication, QFrame, QMainWindow, QScrollArea, QWidget from bec_widgets import SafeProperty, SafeSlot -from bec_widgets.utils import BECConnector +from bec_widgets.utils.bec_connector import BECConnector from bec_widgets.utils.colors import apply_theme from bec_widgets.utils.widget_io import WidgetIO diff --git a/bec_widgets/widgets/containers/main_window/main_window.py b/bec_widgets/widgets/containers/main_window/main_window.py index e0f84a08d..0d3713a0b 100644 --- a/bec_widgets/widgets/containers/main_window/main_window.py +++ b/bec_widgets/widgets/containers/main_window/main_window.py @@ -18,10 +18,10 @@ ) import bec_widgets -from bec_widgets.utils import UILoader from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.colors import apply_theme from bec_widgets.utils.error_popups import SafeSlot +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.widgets.containers.main_window.addons.hover_widget import HoverWidget from bec_widgets.widgets.containers.main_window.addons.notification_center.notification_banner import ( BECNotificationBroker, diff --git a/bec_widgets/widgets/containers/qt_ads/__init__.py b/bec_widgets/widgets/containers/qt_ads/__init__.py index aa837994c..d432e3fd3 100644 --- a/bec_widgets/widgets/containers/qt_ads/__init__.py +++ b/bec_widgets/widgets/containers/qt_ads/__init__.py @@ -1 +1,4 @@ from PySide6QtAds import * + +CDockManager.setConfigFlag(CDockManager.eConfigFlag.FocusHighlighting, True) +CDockManager.setConfigFlag(CDockManager.eConfigFlag.RetainTabSizeWhenCloseButtonHidden, True) diff --git a/bec_widgets/widgets/control/device_control/positioner_box/_base/__init__.py b/bec_widgets/widgets/control/device_control/positioner_box/_base/__init__.py index 007b19a27..e69de29bb 100644 --- a/bec_widgets/widgets/control/device_control/positioner_box/_base/__init__.py +++ b/bec_widgets/widgets/control/device_control/positioner_box/_base/__init__.py @@ -1,3 +0,0 @@ -from .positioner_box_base import PositionerBoxBase - -__ALL__ = ["PositionerBoxBase"] diff --git a/bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py b/bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py index f7cfaf4cc..7dd074a72 100644 --- a/bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +++ b/bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py @@ -11,12 +11,12 @@ from qtpy.QtGui import QDoubleValidator from qtpy.QtWidgets import QDoubleSpinBox -from bec_widgets.utils import UILoader from bec_widgets.utils.colors import apply_theme, get_accent_colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot -from bec_widgets.widgets.control.device_control.positioner_box._base import PositionerBoxBase +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base import ( DeviceUpdateUIComponents, + PositionerBoxBase, ) logger = bec_logger.logger diff --git a/bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py b/bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py index d57c22c6b..67375d30f 100644 --- a/bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py +++ b/bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py @@ -12,12 +12,12 @@ from qtpy.QtGui import QDoubleValidator from qtpy.QtWidgets import QDoubleSpinBox -from bec_widgets.utils import UILoader from bec_widgets.utils.colors import apply_theme from bec_widgets.utils.error_popups import SafeProperty, SafeSlot -from bec_widgets.widgets.control.device_control.positioner_box._base import PositionerBoxBase +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.widgets.control.device_control.positioner_box._base.positioner_box_base import ( DeviceUpdateUIComponents, + PositionerBoxBase, ) logger = bec_logger.logger diff --git a/bec_widgets/widgets/control/device_input/base_classes/device_input_base.py b/bec_widgets/widgets/control/device_input/base_classes/device_input_base.py index 8db1a14a5..a9a488bb3 100644 --- a/bec_widgets/widgets/control/device_input/base_classes/device_input_base.py +++ b/bec_widgets/widgets/control/device_input/base_classes/device_input_base.py @@ -7,7 +7,7 @@ from bec_lib.logger import bec_logger from pydantic import field_validator -from bec_widgets.utils import ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.filter_io import FilterIO diff --git a/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py b/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py index cc03c9a31..788dea835 100644 --- a/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +++ b/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py @@ -3,7 +3,7 @@ from bec_lib.logger import bec_logger from qtpy.QtCore import Property -from bec_widgets.utils import ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.filter_io import FilterIO diff --git a/bec_widgets/widgets/control/device_manager/__init__.py b/bec_widgets/widgets/control/device_manager/__init__.py index dca7392e7..e69de29bb 100644 --- a/bec_widgets/widgets/control/device_manager/__init__.py +++ b/bec_widgets/widgets/control/device_manager/__init__.py @@ -1 +0,0 @@ -from .components import DeviceTable, DMConfigView, DocstringView, OphydValidation diff --git a/bec_widgets/widgets/control/device_manager/components/__init__.py b/bec_widgets/widgets/control/device_manager/components/__init__.py index d33639770..e69de29bb 100644 --- a/bec_widgets/widgets/control/device_manager/components/__init__.py +++ b/bec_widgets/widgets/control/device_manager/components/__init__.py @@ -1,5 +0,0 @@ -# from .device_table_view import DeviceTableView -from .device_table.device_table import DeviceTable -from .dm_config_view import DMConfigView -from .dm_docstring_view import DocstringView, docstring_to_markdown -from .ophyd_validation.ophyd_validation import OphydValidation diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/__init__.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/__init__.py index 83d4d4d0f..e69de29bb 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/__init__.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/__init__.py @@ -1,3 +0,0 @@ -from .available_device_resources import AvailableDeviceResources - -__all__ = ["AvailableDeviceResources"] diff --git a/bec_widgets/widgets/control/device_manager/components/device_table/device_table.py b/bec_widgets/widgets/control/device_manager/components/device_table/device_table.py index a7b716cfa..b8219b160 100644 --- a/bec_widgets/widgets/control/device_manager/components/device_table/device_table.py +++ b/bec_widgets/widgets/control/device_manager/components/device_table/device_table.py @@ -22,7 +22,7 @@ from bec_widgets.widgets.control.device_manager.components.device_table.device_table_row import ( DeviceTableRow, ) -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, get_validation_icons, diff --git a/bec_widgets/widgets/control/device_manager/components/device_table/device_table_row.py b/bec_widgets/widgets/control/device_manager/components/device_table/device_table_row.py index 4a777e08a..9a9847642 100644 --- a/bec_widgets/widgets/control/device_manager/components/device_table/device_table_row.py +++ b/bec_widgets/widgets/control/device_manager/components/device_table/device_table_row.py @@ -2,7 +2,7 @@ from bec_lib.atlas_models import Device as DeviceModel -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, ) diff --git a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/__init__.py b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/__init__.py index 829937707..e69de29bb 100644 --- a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/__init__.py +++ b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/__init__.py @@ -1,8 +0,0 @@ -from .ophyd_validation_utils import ( - ConfigStatus, - ConnectionStatus, - DeviceTestModel, - format_error_to_md, - get_validation_icons, -) -from .validation_list_item import ValidationButton, ValidationListItem diff --git a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/ophyd_validation.py b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/ophyd_validation.py index a2cae41a0..3dc6f8ed0 100644 --- a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/ophyd_validation.py +++ b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/ophyd_validation.py @@ -22,15 +22,17 @@ from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.colors import get_accent_colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, DeviceTestModel, - ValidationButton, - ValidationListItem, format_error_to_md, get_validation_icons, ) +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.validation_list_item import ( + ValidationButton, + ValidationListItem, +) READY_TO_TEST = False diff --git a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/validation_list_item.py b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/validation_list_item.py index f8566f2de..ff4ee53c7 100644 --- a/bec_widgets/widgets/control/device_manager/components/ophyd_validation/validation_list_item.py +++ b/bec_widgets/widgets/control/device_manager/components/ophyd_validation/validation_list_item.py @@ -7,7 +7,7 @@ from bec_widgets.utils.colors import get_accent_colors from bec_widgets.utils.error_popups import SafeSlot -from bec_widgets.widgets.control.device_manager.components.ophyd_validation import ( +from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import ( ConfigStatus, ConnectionStatus, DeviceTestModel, diff --git a/bec_widgets/widgets/control/scan_control/__init__.py b/bec_widgets/widgets/control/scan_control/__init__.py index fbeb54be0..e69de29bb 100644 --- a/bec_widgets/widgets/control/scan_control/__init__.py +++ b/bec_widgets/widgets/control/scan_control/__init__.py @@ -1 +0,0 @@ -from .scan_control import ScanControl diff --git a/bec_widgets/widgets/control/scan_control/scan_control.py b/bec_widgets/widgets/control/scan_control/scan_control.py index c0bc1e24b..b5cb4722b 100644 --- a/bec_widgets/widgets/control/scan_control/scan_control.py +++ b/bec_widgets/widgets/control/scan_control/scan_control.py @@ -19,7 +19,7 @@ QWidget, ) -from bec_widgets.utils import ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.colors import apply_theme, get_accent_colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot diff --git a/bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py b/bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py index b9ab384b8..735461c35 100644 --- a/bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py +++ b/bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py @@ -4,10 +4,10 @@ from qtpy.QtCore import Signal from qtpy.QtWidgets import QPushButton, QTreeWidgetItem, QVBoxLayout, QWidget -from bec_widgets.utils import UILoader from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.colors import get_accent_colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot +from bec_widgets.utils.ui_loader import UILoader logger = bec_logger.logger diff --git a/bec_widgets/widgets/editors/jupyter_console/jupyter_console.py b/bec_widgets/widgets/editors/jupyter_console/jupyter_console.py index 40733201c..c9b617899 100644 --- a/bec_widgets/widgets/editors/jupyter_console/jupyter_console.py +++ b/bec_widgets/widgets/editors/jupyter_console/jupyter_console.py @@ -1,10 +1,12 @@ -from bec_ipython_client.main import BECIPythonClient +from bec_lib.utils.import_utils import lazy_import_from from qtconsole.inprocess import QtInProcessKernelManager from qtconsole.manager import QtKernelManager from qtconsole.rich_jupyter_widget import RichJupyterWidget from qtpy.QtCore import Qt from qtpy.QtWidgets import QApplication, QMainWindow +BECIPythonClient = lazy_import_from("bec_ipython_client.main", ("BECIPythonClient",)) + class BECJupyterConsole(RichJupyterWidget): # pragma: no cover: def __init__(self, inprocess: bool = False): diff --git a/bec_widgets/widgets/editors/monaco/scan_control_dialog.py b/bec_widgets/widgets/editors/monaco/scan_control_dialog.py index f77e62c55..b7975bf6a 100644 --- a/bec_widgets/widgets/editors/monaco/scan_control_dialog.py +++ b/bec_widgets/widgets/editors/monaco/scan_control_dialog.py @@ -11,7 +11,7 @@ from qtpy.QtCore import QSize, Qt from qtpy.QtWidgets import QDialog, QDialogButtonBox, QPushButton, QVBoxLayout -from bec_widgets.widgets.control.scan_control import ScanControl +from bec_widgets.widgets.control.scan_control.scan_control import ScanControl logger = bec_logger.logger diff --git a/bec_widgets/widgets/plots/heatmap/heatmap.py b/bec_widgets/widgets/plots/heatmap/heatmap.py index 22287ca3f..7dd6ff4d4 100644 --- a/bec_widgets/widgets/plots/heatmap/heatmap.py +++ b/bec_widgets/widgets/plots/heatmap/heatmap.py @@ -19,8 +19,8 @@ from scipy.spatial import cKDTree from toolz import partition -from bec_widgets.utils import Colors from bec_widgets.utils.bec_connector import ConnectionConfig +from bec_widgets.utils.colors import Colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.settings_dialog import SettingsDialog from bec_widgets.utils.toolbars.actions import MaterialIconAction diff --git a/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py b/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py index 8238caa77..dd60a38f5 100644 --- a/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py +++ b/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py @@ -4,9 +4,9 @@ from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader class HeatmapSettings(SettingWidget): diff --git a/bec_widgets/widgets/plots/image/image.py b/bec_widgets/widgets/plots/image/image.py index d2ed8e39f..14429080f 100644 --- a/bec_widgets/widgets/plots/image/image.py +++ b/bec_widgets/widgets/plots/image/image.py @@ -10,7 +10,7 @@ from qtpy.QtCore import QTimer from qtpy.QtWidgets import QWidget -from bec_widgets.utils import ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.colors import Colors, apply_theme from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.widgets.plots.image.image_base import ImageBase diff --git a/bec_widgets/widgets/plots/image/image_base.py b/bec_widgets/widgets/plots/image/image_base.py index 8a0bcaae9..57bbf95c5 100644 --- a/bec_widgets/widgets/plots/image/image_base.py +++ b/bec_widgets/widgets/plots/image/image_base.py @@ -9,7 +9,7 @@ from qtpy.QtCore import QPointF, Signal, SignalInstance from qtpy.QtWidgets import QDialog, QVBoxLayout -from bec_widgets.utils import Colors +from bec_widgets.utils.colors import Colors from bec_widgets.utils.container_utils import WidgetContainerUtils from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.side_panel import SidePanel diff --git a/bec_widgets/widgets/plots/image/image_item.py b/bec_widgets/widgets/plots/image/image_item.py index 6f24ca3b1..66ee0926e 100644 --- a/bec_widgets/widgets/plots/image/image_item.py +++ b/bec_widgets/widgets/plots/image/image_item.py @@ -9,7 +9,8 @@ from qtpy.QtCore import Signal from qtpy.QtGui import QTransform -from bec_widgets.utils import BECConnector, Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig +from bec_widgets.utils.colors import Colors from bec_widgets.widgets.plots.image.image_processor import ( ImageProcessor, ImageStats, diff --git a/bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py b/bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py index 91ed3dcb0..8c9d7b5bc 100644 --- a/bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py +++ b/bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py @@ -20,7 +20,8 @@ ) from bec_widgets import BECWidget -from bec_widgets.utils import BECDispatcher, ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig +from bec_widgets.utils.bec_dispatcher import BECDispatcher from bec_widgets.utils.toolbars.actions import WidgetAction from bec_widgets.utils.toolbars.bundles import ToolbarBundle from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar diff --git a/bec_widgets/widgets/plots/motor_map/motor_map.py b/bec_widgets/widgets/plots/motor_map/motor_map.py index d2f014866..32c3d1513 100644 --- a/bec_widgets/widgets/plots/motor_map/motor_map.py +++ b/bec_widgets/widgets/plots/motor_map/motor_map.py @@ -10,8 +10,8 @@ from qtpy.QtGui import QColor from qtpy.QtWidgets import QHBoxLayout, QMainWindow, QWidget -from bec_widgets.utils import Colors, ConnectionConfig -from bec_widgets.utils.colors import apply_theme +from bec_widgets.utils.bec_connector import ConnectionConfig +from bec_widgets.utils.colors import Colors, apply_theme from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.settings_dialog import SettingsDialog from bec_widgets.utils.toolbars.toolbar import MaterialIconAction diff --git a/bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py b/bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py index 0cab9d3ac..e67aecaf4 100644 --- a/bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py +++ b/bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py @@ -2,9 +2,9 @@ from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout, QWidget -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.utils.widget_io import WidgetIO diff --git a/bec_widgets/widgets/plots/multi_waveform/multi_waveform.py b/bec_widgets/widgets/plots/multi_waveform/multi_waveform.py index e0e214dbe..291a15cc2 100644 --- a/bec_widgets/widgets/plots/multi_waveform/multi_waveform.py +++ b/bec_widgets/widgets/plots/multi_waveform/multi_waveform.py @@ -10,7 +10,8 @@ from qtpy.QtCore import Signal from qtpy.QtWidgets import QWidget -from bec_widgets.utils import Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig +from bec_widgets.utils.colors import Colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.side_panel import SidePanel from bec_widgets.widgets.control.device_input.device_combobox.device_combobox import DeviceComboBox diff --git a/bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py b/bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py index 5ab4278b2..707a96a6d 100644 --- a/bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py +++ b/bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py @@ -2,9 +2,9 @@ from qtpy.QtWidgets import QVBoxLayout, QWidget -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.utils.widget_io import WidgetIO diff --git a/bec_widgets/widgets/plots/plot_base.py b/bec_widgets/widgets/plots/plot_base.py index 88c234829..f2041a90b 100644 --- a/bec_widgets/widgets/plots/plot_base.py +++ b/bec_widgets/widgets/plots/plot_base.py @@ -8,8 +8,10 @@ from qtpy.QtCore import QPoint, QPointF, Qt, Signal from qtpy.QtWidgets import QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget -from bec_widgets.utils import ConnectionConfig, Crosshair, EntryValidator +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget +from bec_widgets.utils.crosshair import Crosshair +from bec_widgets.utils.entry_validator import EntryValidator from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.fps_counter import FPSCounter from bec_widgets.utils.plot_indicator_items import BECArrowItem, BECTickItem diff --git a/bec_widgets/widgets/plots/roi/image_roi.py b/bec_widgets/widgets/plots/roi/image_roi.py index 9c22f7bcc..d6a45dbad 100644 --- a/bec_widgets/widgets/plots/roi/image_roi.py +++ b/bec_widgets/widgets/plots/roi/image_roi.py @@ -10,7 +10,7 @@ from qtpy.QtCore import QObject, Signal from bec_widgets import SafeProperty -from bec_widgets.utils import BECConnector, ConnectionConfig +from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig from bec_widgets.utils.colors import Colors if TYPE_CHECKING: diff --git a/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py b/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py index 4624e50cb..5ca0e6609 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +++ b/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py @@ -8,7 +8,8 @@ from pydantic import BaseModel, Field, ValidationError, field_validator from qtpy import QtCore -from bec_widgets.utils import BECConnector, Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig +from bec_widgets.utils.colors import Colors if TYPE_CHECKING: # pragma: no cover from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterWaveform diff --git a/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py b/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py index 94fb063f7..dcd905981 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +++ b/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py @@ -7,7 +7,8 @@ from qtpy.QtCore import QTimer, Signal from qtpy.QtWidgets import QHBoxLayout, QMainWindow, QWidget -from bec_widgets.utils import Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig +from bec_widgets.utils.colors import Colors from bec_widgets.utils.error_popups import SafeProperty, SafeSlot from bec_widgets.utils.settings_dialog import SettingsDialog from bec_widgets.utils.toolbars.toolbar import MaterialIconAction diff --git a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py index 46f211f55..b08fd1682 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +++ b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py @@ -2,9 +2,9 @@ from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader class ScatterCurveSettings(SettingWidget): diff --git a/bec_widgets/widgets/plots/setting_menus/axis_settings.py b/bec_widgets/widgets/plots/setting_menus/axis_settings.py index 68f4ba7b9..655adceb2 100644 --- a/bec_widgets/widgets/plots/setting_menus/axis_settings.py +++ b/bec_widgets/widgets/plots/setting_menus/axis_settings.py @@ -2,9 +2,9 @@ from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout, QWidget -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.utils.widget_io import WidgetIO diff --git a/bec_widgets/widgets/plots/waveform/curve.py b/bec_widgets/widgets/plots/waveform/curve.py index a4dca716e..f5bd030cd 100644 --- a/bec_widgets/widgets/plots/waveform/curve.py +++ b/bec_widgets/widgets/plots/waveform/curve.py @@ -8,7 +8,8 @@ from pydantic import BaseModel, Field, field_validator from qtpy import QtCore -from bec_widgets.utils import BECConnector, Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig +from bec_widgets.utils.colors import Colors if TYPE_CHECKING: # pragma: no cover from bec_widgets.widgets.plots.waveform.waveform import Waveform diff --git a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py index 10c78b461..3f73677e0 100644 --- a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +++ b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py @@ -50,9 +50,10 @@ def validate(self, input_str: str, pos: int): ) from bec_widgets import SafeSlot -from bec_widgets.utils import ConnectionConfig, EntryValidator +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.colors import Colors +from bec_widgets.utils.entry_validator import EntryValidator from bec_widgets.utils.toolbars.actions import WidgetAction from bec_widgets.utils.toolbars.bundles import ToolbarBundle from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar diff --git a/bec_widgets/widgets/plots/waveform/waveform.py b/bec_widgets/widgets/plots/waveform/waveform.py index 0c59e9dd9..c5145e64f 100644 --- a/bec_widgets/widgets/plots/waveform/waveform.py +++ b/bec_widgets/widgets/plots/waveform/waveform.py @@ -24,7 +24,7 @@ QWidget, ) -from bec_widgets.utils import ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_signal_proxy import BECSignalProxy from bec_widgets.utils.colors import Colors, apply_theme from bec_widgets.utils.container_utils import WidgetContainerUtils diff --git a/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py b/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py index 0a6c8dd8b..bb410cf61 100644 --- a/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py +++ b/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py @@ -6,8 +6,8 @@ from qtpy.QtCore import QSize, Qt from qtpy.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QWidget -from bec_widgets.utils import Colors from bec_widgets.utils.bec_widget import BECWidget +from bec_widgets.utils.colors import Colors from bec_widgets.utils.error_popups import SafeProperty from bec_widgets.utils.settings_dialog import SettingsDialog from bec_widgets.utils.toolbars.actions import MaterialIconAction diff --git a/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_settings_cards.py b/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_settings_cards.py index e3c0a9991..6a8e9413b 100644 --- a/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_settings_cards.py +++ b/bec_widgets/widgets/progress/ring_progress_bar/ring_progress_settings_cards.py @@ -19,9 +19,9 @@ QWidget, ) -from bec_widgets.utils import UILoader from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.settings_dialog import SettingWidget +from bec_widgets.utils.ui_loader import UILoader from bec_widgets.widgets.progress.ring_progress_bar.ring import Ring from bec_widgets.widgets.utility.visual.colormap_widget.colormap_widget import BECColorMapWidget diff --git a/bec_widgets/widgets/services/device_browser/device_browser.py b/bec_widgets/widgets/services/device_browser/device_browser.py index 9aa0e789f..e7343be02 100644 --- a/bec_widgets/widgets/services/device_browser/device_browser.py +++ b/bec_widgets/widgets/services/device_browser/device_browser.py @@ -17,10 +17,10 @@ from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.list_of_expandable_frames import ListOfExpandableFrames from bec_widgets.utils.ui_loader import UILoader -from bec_widgets.widgets.services.device_browser.device_item import DeviceItem from bec_widgets.widgets.services.device_browser.device_item.device_config_dialog import ( DirectUpdateDeviceConfigDialog, ) +from bec_widgets.widgets.services.device_browser.device_item.device_item import DeviceItem from bec_widgets.widgets.services.device_browser.util import map_device_type_to_icon logger = bec_logger.logger diff --git a/bec_widgets/widgets/services/device_browser/device_item/__init__.py b/bec_widgets/widgets/services/device_browser/device_item/__init__.py index 6ebb878ea..e69de29bb 100644 --- a/bec_widgets/widgets/services/device_browser/device_item/__init__.py +++ b/bec_widgets/widgets/services/device_browser/device_item/__init__.py @@ -1 +0,0 @@ -from .device_item import DeviceItem diff --git a/bec_widgets/widgets/services/scan_history_browser/components/__init__.py b/bec_widgets/widgets/services/scan_history_browser/components/__init__.py index aa2f5f93b..e69de29bb 100644 --- a/bec_widgets/widgets/services/scan_history_browser/components/__init__.py +++ b/bec_widgets/widgets/services/scan_history_browser/components/__init__.py @@ -1,5 +0,0 @@ -from .scan_history_device_viewer import ScanHistoryDeviceViewer -from .scan_history_metadata_viewer import ScanHistoryMetadataViewer -from .scan_history_view import ScanHistoryView - -__all__ = ["ScanHistoryDeviceViewer", "ScanHistoryMetadataViewer", "ScanHistoryView"] diff --git a/bec_widgets/widgets/services/scan_history_browser/components/scan_history_view.py b/bec_widgets/widgets/services/scan_history_browser/components/scan_history_view.py index 687d0b9cc..64c3fe6e1 100644 --- a/bec_widgets/widgets/services/scan_history_browser/components/scan_history_view.py +++ b/bec_widgets/widgets/services/scan_history_browser/components/scan_history_view.py @@ -330,8 +330,10 @@ def cleanup(self): if __name__ == "__main__": # pragma: no cover # pylint: disable=import-outside-toplevel - from bec_widgets.widgets.services.scan_history_browser.components import ( + from bec_widgets.widgets.services.scan_history_browser.components.scan_history_device_viewer import ( ScanHistoryDeviceViewer, + ) + from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import ( ScanHistoryMetadataViewer, ) from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton diff --git a/bec_widgets/widgets/services/scan_history_browser/scan_history_browser.py b/bec_widgets/widgets/services/scan_history_browser/scan_history_browser.py index c60a92584..c03105723 100644 --- a/bec_widgets/widgets/services/scan_history_browser/scan_history_browser.py +++ b/bec_widgets/widgets/services/scan_history_browser/scan_history_browser.py @@ -1,9 +1,13 @@ from qtpy import QtCore, QtWidgets from bec_widgets.utils.bec_widget import BECWidget, ConnectionConfig -from bec_widgets.widgets.services.scan_history_browser.components import ( +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_device_viewer import ( ScanHistoryDeviceViewer, +) +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import ( ScanHistoryMetadataViewer, +) +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_view import ( ScanHistoryView, ) diff --git a/bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py b/bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py index 5317843cb..91002af01 100644 --- a/bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +++ b/bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py @@ -3,8 +3,7 @@ from qtpy.QtCore import Property, Signal, Slot from qtpy.QtWidgets import QSizePolicy, QVBoxLayout, QWidget -from bec_widgets.utils import Colors -from bec_widgets.utils.bec_widget import BECWidget +from bec_widgets.utils.colors import Colors class RoundedColorMapButton(ColorMapButton): diff --git a/bec_widgets/widgets/utility/widget_hierarchy_tree/widget_hierarchy_tree.py b/bec_widgets/widgets/utility/widget_hierarchy_tree/widget_hierarchy_tree.py index c3ec02667..a77e82320 100644 --- a/bec_widgets/widgets/utility/widget_hierarchy_tree/widget_hierarchy_tree.py +++ b/bec_widgets/widgets/utility/widget_hierarchy_tree/widget_hierarchy_tree.py @@ -19,7 +19,7 @@ QWidget, ) -from bec_widgets.utils import BECConnector +from bec_widgets.utils.bec_connector import BECConnector from bec_widgets.utils.widget_highlighter import WidgetHighlighter from bec_widgets.utils.widget_io import WidgetHierarchy diff --git a/tests/end-2-end/conftest.py b/tests/end-2-end/conftest.py index dc4a123d1..60132562b 100644 --- a/tests/end-2-end/conftest.py +++ b/tests/end-2-end/conftest.py @@ -5,7 +5,7 @@ import pytest from bec_widgets.cli.client_utils import BECGuiClient -from bec_widgets.widgets.control.scan_control import ScanControl +from bec_widgets.widgets.control.scan_control.scan_control import ScanControl # pylint: disable=unused-argument # pylint: disable=redefined-outer-name diff --git a/tests/end-2-end/test_with_plugins_e2e.py b/tests/end-2-end/test_with_plugins_e2e.py index 84889f779..dc30951de 100644 --- a/tests/end-2-end/test_with_plugins_e2e.py +++ b/tests/end-2-end/test_with_plugins_e2e.py @@ -10,7 +10,7 @@ from qtpy.QtWidgets import QGridLayout from bec_widgets.utils.widget_io import WidgetIO -from bec_widgets.widgets.control.scan_control import ScanControl +from bec_widgets.widgets.control.scan_control.scan_control import ScanControl @pytest.fixture(scope="function") diff --git a/tests/unit_tests/test_bec_connector.py b/tests/unit_tests/test_bec_connector.py index 55773232b..04be46599 100644 --- a/tests/unit_tests/test_bec_connector.py +++ b/tests/unit_tests/test_bec_connector.py @@ -5,7 +5,7 @@ from qtpy.QtCore import QObject from qtpy.QtWidgets import QApplication, QWidget -from bec_widgets.utils import BECConnector +from bec_widgets.utils.bec_connector import BECConnector from bec_widgets.utils.error_popups import SafeProperty from bec_widgets.utils.error_popups import SafeSlot as Slot diff --git a/tests/unit_tests/test_color_utils.py b/tests/unit_tests/test_color_utils.py index 39c46473e..fc68acb6a 100644 --- a/tests/unit_tests/test_color_utils.py +++ b/tests/unit_tests/test_color_utils.py @@ -4,9 +4,9 @@ from qtpy.QtGui import QColor from qtpy.QtWidgets import QVBoxLayout, QWidget -from bec_widgets.utils import Colors, ConnectionConfig +from bec_widgets.utils.bec_connector import ConnectionConfig from bec_widgets.utils.bec_widget import BECWidget -from bec_widgets.utils.colors import apply_theme +from bec_widgets.utils.colors import Colors, apply_theme from bec_widgets.widgets.plots.waveform.curve import CurveConfig from tests.unit_tests.client_mocks import mocked_client from tests.unit_tests.conftest import create_widget diff --git a/tests/unit_tests/test_crosshair.py b/tests/unit_tests/test_crosshair.py index 28662a270..0012c9d46 100644 --- a/tests/unit_tests/test_crosshair.py +++ b/tests/unit_tests/test_crosshair.py @@ -4,7 +4,7 @@ from qtpy.QtCore import QPointF, Qt from qtpy.QtGui import QTransform -from bec_widgets.utils import Crosshair +from bec_widgets.utils.crosshair import Crosshair from bec_widgets.widgets.plots.image.image_item import ImageItem from bec_widgets.widgets.plots.waveform.waveform import Waveform from tests.unit_tests.client_mocks import mocked_client diff --git a/tests/unit_tests/test_device_browser.py b/tests/unit_tests/test_device_browser.py index 7c36594ee..bb458eb67 100644 --- a/tests/unit_tests/test_device_browser.py +++ b/tests/unit_tests/test_device_browser.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: # pragma: no cover from qtpy.QtWidgets import QListWidgetItem - from bec_widgets.widgets.services.device_browser.device_item import DeviceItem + from bec_widgets.widgets.services.device_browser.device_item.device_item import DeviceItem # pylint: disable=no-member diff --git a/tests/unit_tests/test_device_manager_components.py b/tests/unit_tests/test_device_manager_components.py index 771dc2df7..18ec909af 100644 --- a/tests/unit_tests/test_device_manager_components.py +++ b/tests/unit_tests/test_device_manager_components.py @@ -16,8 +16,6 @@ from bec_widgets.utils.bec_list import BECList from bec_widgets.utils.colors import get_accent_colors -from bec_widgets.widgets.control.device_manager import DeviceTable, DMConfigView, DocstringView -from bec_widgets.widgets.control.device_manager.components import docstring_to_markdown from bec_widgets.widgets.control.device_manager.components.constants import HEADERS_HELP_MD from bec_widgets.widgets.control.device_manager.components.device_config_template.device_config_template import ( DeviceConfigTemplate, @@ -34,9 +32,17 @@ ReadoutPriorityComboBox, _try_literal_eval, ) +from bec_widgets.widgets.control.device_manager.components.device_table.device_table import ( + DeviceTable, +) from bec_widgets.widgets.control.device_manager.components.device_table.device_table_row import ( DeviceTableRow, ) +from bec_widgets.widgets.control.device_manager.components.dm_config_view import DMConfigView +from bec_widgets.widgets.control.device_manager.components.dm_docstring_view import ( + DocstringView, + docstring_to_markdown, +) from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation import ( DeviceTest, LegendLabel, diff --git a/tests/unit_tests/test_device_manager_view.py b/tests/unit_tests/test_device_manager_view.py index e7326c537..f5dc33f8f 100644 --- a/tests/unit_tests/test_device_manager_view.py +++ b/tests/unit_tests/test_device_manager_view.py @@ -31,12 +31,11 @@ DeviceManagerWidget, ) from bec_widgets.utils.colors import get_accent_colors -from bec_widgets.widgets.control.device_manager.components import ( +from bec_widgets.widgets.control.device_manager.components.device_table.device_table import ( DeviceTable, - DMConfigView, - DocstringView, - OphydValidation, ) +from bec_widgets.widgets.control.device_manager.components.dm_config_view import DMConfigView +from bec_widgets.widgets.control.device_manager.components.dm_docstring_view import DocstringView from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation import ( ConfigStatus, ConnectionStatus, diff --git a/tests/unit_tests/test_ring_progress_bar.py b/tests/unit_tests/test_ring_progress_bar.py index e858e80da..8c572cb42 100644 --- a/tests/unit_tests/test_ring_progress_bar.py +++ b/tests/unit_tests/test_ring_progress_bar.py @@ -7,7 +7,7 @@ from pydantic import ValidationError from qtpy.QtGui import QColor -from bec_widgets.utils import Colors +from bec_widgets.utils.colors import Colors from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar from .client_mocks import mocked_client diff --git a/tests/unit_tests/test_scan_control.py b/tests/unit_tests/test_scan_control.py index d070e5e26..6dc9464d7 100644 --- a/tests/unit_tests/test_scan_control.py +++ b/tests/unit_tests/test_scan_control.py @@ -9,7 +9,7 @@ from bec_widgets.utils.forms_from_types.items import StrFormItem from bec_widgets.utils.widget_io import WidgetIO -from bec_widgets.widgets.control.scan_control import ScanControl +from bec_widgets.widgets.control.scan_control.scan_control import ScanControl from .client_mocks import mocked_client diff --git a/tests/unit_tests/test_scan_history_browser.py b/tests/unit_tests/test_scan_history_browser.py index 4ddf24e70..62344464b 100644 --- a/tests/unit_tests/test_scan_history_browser.py +++ b/tests/unit_tests/test_scan_history_browser.py @@ -6,9 +6,13 @@ from qtpy import QtCore from bec_widgets.utils.colors import get_accent_colors -from bec_widgets.widgets.services.scan_history_browser.components import ( +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_device_viewer import ( ScanHistoryDeviceViewer, +) +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import ( ScanHistoryMetadataViewer, +) +from bec_widgets.widgets.services.scan_history_browser.components.scan_history_view import ( ScanHistoryView, ) from bec_widgets.widgets.services.scan_history_browser.scan_history_browser import (