mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-05-09 16:22:08 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70098dfee2 | |||
| a8c595f2a8 | |||
| 27a5899c8b | |||
| 02a5763a0f | |||
| 152aadfffd | |||
| ac6af06ef6 |
+12
-10
@@ -1,19 +1,21 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
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"):
|
if sys.platform.startswith("linux"):
|
||||||
qt_platform = os.environ.get("QT_QPA_PLATFORM", "")
|
qt_platform = os.environ.get("QT_QPA_PLATFORM", "")
|
||||||
if qt_platform != "offscreen":
|
if qt_platform != "offscreen":
|
||||||
os.environ["QT_QPA_PLATFORM"] = "xcb"
|
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"]
|
__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}")
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
from .config_choice_dialog import ConfigChoiceDialog
|
|
||||||
from .device_form_dialog import DeviceFormDialog
|
|
||||||
|
|||||||
+4
-2
@@ -8,14 +8,16 @@ from ophyd_devices.interfaces.device_config_templates.ophyd_templates import OPH
|
|||||||
from qtpy import QtCore, QtWidgets
|
from qtpy import QtCore, QtWidgets
|
||||||
|
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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 (
|
from bec_widgets.widgets.control.device_manager.components.device_config_template.device_config_template import (
|
||||||
DeviceConfigTemplate,
|
DeviceConfigTemplate,
|
||||||
)
|
)
|
||||||
from bec_widgets.widgets.control.device_manager.components.device_config_template.template_items import (
|
from bec_widgets.widgets.control.device_manager.components.device_config_template.template_items import (
|
||||||
validate_name,
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
format_error_to_md,
|
format_error_to_md,
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ from qtpy import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
from bec_widgets.utils.colors import get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
get_validation_icons,
|
get_validation_icons,
|
||||||
|
|||||||
+27
-13
@@ -13,6 +13,7 @@ from bec_lib.file_utils import DeviceConfigWriter
|
|||||||
from bec_lib.logger import bec_logger
|
from bec_lib.logger import bec_logger
|
||||||
from bec_lib.messages import ConfigAction, ScanStatusMessage
|
from bec_lib.messages import ConfigAction, ScanStatusMessage
|
||||||
from bec_lib.plugin_helper import plugin_package_name, plugin_repo_path
|
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 bec_qthemes import apply_theme, material_icon
|
||||||
from qtpy.QtCore import QMetaObject, Qt, QThreadPool, Signal
|
from qtpy.QtCore import QMetaObject, Qt, QThreadPool, Signal
|
||||||
from qtpy.QtGui import QColor
|
from qtpy.QtGui import QColor
|
||||||
@@ -26,26 +27,18 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
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.colors import get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
||||||
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
||||||
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
|
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
|
||||||
from bec_widgets.widgets.containers.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,
|
|
||||||
DocstringView,
|
|
||||||
OphydValidation,
|
|
||||||
)
|
|
||||||
from bec_widgets.widgets.control.device_manager.components._util import SharedSelectionSignal
|
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,
|
||||||
|
)
|
||||||
|
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 (
|
from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation_utils import (
|
||||||
ConfigStatus,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
@@ -61,8 +54,29 @@ from bec_widgets.widgets.utility.spinner.spinner import SpinnerWidget
|
|||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_lib.client import BECClient
|
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
|
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(
|
_yes_no_question = partial(
|
||||||
QMessageBox.question,
|
QMessageBox.question,
|
||||||
buttons=QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
buttons=QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
"""Module for Device Manager View."""
|
"""Module for Device Manager View."""
|
||||||
|
|
||||||
|
from bec_lib.utils.import_utils import lazy_import_from
|
||||||
from qtpy.QtCore import QRect
|
from qtpy.QtCore import QRect
|
||||||
from qtpy.QtWidgets import QWidget
|
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.applications.views.view import ViewBase, ViewTourSteps
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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):
|
class DeviceManagerView(ViewBase):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -6,15 +6,18 @@ import os
|
|||||||
|
|
||||||
from bec_lib.bec_yaml_loader import yaml_load
|
from bec_lib.bec_yaml_loader import yaml_load
|
||||||
from bec_lib.logger import bec_logger
|
from bec_lib.logger import bec_logger
|
||||||
|
from bec_lib.utils.import_utils import lazy_import_from
|
||||||
from bec_qthemes import material_icon
|
from bec_qthemes import material_icon
|
||||||
from qtpy import QtCore, QtWidgets
|
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.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3172,190 +3172,6 @@ class LogPanel(RPCBase):
|
|||||||
class Minesweeper(RPCBase): ...
|
class Minesweeper(RPCBase): ...
|
||||||
|
|
||||||
|
|
||||||
class MonacoDock(RPCBase):
|
|
||||||
"""MonacoDock is a dock widget that contains Monaco editor instances."""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def new(
|
|
||||||
self,
|
|
||||||
widget: "QWidget | str",
|
|
||||||
*,
|
|
||||||
closable: "bool" = True,
|
|
||||||
floatable: "bool" = True,
|
|
||||||
movable: "bool" = True,
|
|
||||||
start_floating: "bool" = False,
|
|
||||||
floating_state: "Mapping[str, object] | None" = None,
|
|
||||||
where: "Literal['left', 'right', 'top', 'bottom'] | None" = None,
|
|
||||||
on_close: "Callable[[CDockWidget, QWidget], None] | None" = None,
|
|
||||||
tab_with: "CDockWidget | QWidget | str | None" = None,
|
|
||||||
relative_to: "CDockWidget | QWidget | str | None" = None,
|
|
||||||
return_dock: "bool" = False,
|
|
||||||
show_title_bar: "bool | None" = None,
|
|
||||||
title_buttons: "Mapping[str, bool] | Sequence[str] | str | None" = None,
|
|
||||||
show_settings_action: "bool | None" = False,
|
|
||||||
promote_central: "bool" = False,
|
|
||||||
dock_icon: "QIcon | None" = None,
|
|
||||||
apply_widget_icon: "bool" = True,
|
|
||||||
object_name: "str | None" = None,
|
|
||||||
**widget_kwargs,
|
|
||||||
) -> "QWidget | CDockWidget | BECWidget":
|
|
||||||
"""
|
|
||||||
Create a new widget (or reuse an instance) and add it as a dock.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
widget(QWidget | str): Instance or registered widget type string.
|
|
||||||
closable(bool): Whether the dock is closable.
|
|
||||||
floatable(bool): Whether the dock is floatable.
|
|
||||||
movable(bool): Whether the dock is movable.
|
|
||||||
start_floating(bool): Whether to start the dock floating.
|
|
||||||
floating_state(Mapping | None): Optional floating geometry metadata to apply when floating.
|
|
||||||
where(Literal["left", "right", "top", "bottom"] | None): Dock placement hint relative to the dock area (ignored when
|
|
||||||
``relative_to`` is provided without an explicit value).
|
|
||||||
on_close(Callable[[CDockWidget, QWidget], None] | None): Optional custom close handler accepting (dock, widget).
|
|
||||||
tab_with(CDockWidget | QWidget | str | None): Existing dock (or widget/name) to tab the new dock alongside.
|
|
||||||
relative_to(CDockWidget | QWidget | str | None): Existing dock (or widget/name) used as the positional anchor.
|
|
||||||
When supplied and ``where`` is ``None``, the new dock inherits the
|
|
||||||
anchor's current dock area.
|
|
||||||
return_dock(bool): When True, return the created dock instead of the widget.
|
|
||||||
show_title_bar(bool | None): Explicitly show or hide the dock area's title bar.
|
|
||||||
title_buttons(Mapping[str, bool] | Sequence[str] | str | None): Mapping or iterable describing which title bar buttons should
|
|
||||||
remain visible. Provide a mapping of button names (``"float"``,
|
|
||||||
``"close"``, ``"menu"``, ``"auto_hide"``, ``"minimize"``) to booleans,
|
|
||||||
or a sequence of button names to hide.
|
|
||||||
show_settings_action(bool | None): Control whether a dock settings/property action should
|
|
||||||
be installed. Defaults to ``False`` for the basic dock area; subclasses
|
|
||||||
such as `BECDockArea` override the default to ``True``.
|
|
||||||
promote_central(bool): When True, promote the created dock to be the dock manager's
|
|
||||||
central widget (useful for editor stacks or other root content).
|
|
||||||
dock_icon(QIcon | None): Optional icon applied to the dock via ``CDockWidget.setIcon``.
|
|
||||||
Provide a `QIcon` (e.g. from ``material_icon``). When ``None`` (default),
|
|
||||||
the widget's ``ICON_NAME`` attribute is used when available.
|
|
||||||
apply_widget_icon(bool): When False, skip automatically resolving the icon from
|
|
||||||
the widget's ``ICON_NAME`` (useful for callers who want no icon and do not pass one explicitly).
|
|
||||||
object_name(str | None): Optional object name to assign to the created widget.
|
|
||||||
**widget_kwargs: Additional keyword arguments passed to the widget constructor
|
|
||||||
when creating by type name.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The widget instance by default, or the created `CDockWidget` when `return_dock` is True.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def dock_map(self) -> "dict[str, CDockWidget]":
|
|
||||||
"""
|
|
||||||
Return the dock widgets map as dictionary with names as keys.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def dock_list(self) -> "list[CDockWidget]":
|
|
||||||
"""
|
|
||||||
Return the list of dock widgets.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def widget_map(self, bec_widgets_only: "bool" = True) -> "dict[str, QWidget]":
|
|
||||||
"""
|
|
||||||
Return a dictionary mapping widget names to their corresponding widgets.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bec_widgets_only(bool): If True, only include widgets that are BECConnector instances.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def widget_list(self, bec_widgets_only: "bool" = True) -> "list[QWidget]":
|
|
||||||
"""
|
|
||||||
Return a list of widgets contained in the dock area.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
bec_widgets_only(bool): If True, only include widgets that are BECConnector instances.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def attach_all(self):
|
|
||||||
"""
|
|
||||||
Re-attach floating docks back into the dock manager.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def delete_all(self):
|
|
||||||
"""
|
|
||||||
Delete all docks and their associated widgets.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def delete(self, object_name: "str") -> "bool":
|
|
||||||
"""
|
|
||||||
Remove a widget from the dock area by its object name.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
object_name: The object name of the widget to remove.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if the widget was found and removed, False otherwise.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If no widget with the given object name is found.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
>>> dock_area.delete("my_widget")
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def set_layout_ratios(
|
|
||||||
self,
|
|
||||||
*,
|
|
||||||
horizontal: "Sequence[float] | Mapping[int | str, float] | None" = None,
|
|
||||||
vertical: "Sequence[float] | Mapping[int | str, float] | None" = None,
|
|
||||||
splitter_overrides: "Mapping[int | str | Sequence[int], Sequence[float] | Mapping[int | str, float]] | None" = None,
|
|
||||||
) -> "None":
|
|
||||||
"""
|
|
||||||
Adjust splitter ratios in the dock layout.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
horizontal: Weights applied to every horizontal splitter encountered.
|
|
||||||
vertical: Weights applied to every vertical splitter encountered.
|
|
||||||
splitter_overrides: Optional overrides targeting specific splitters identified
|
|
||||||
by their index path (e.g. ``{0: [1, 2], (1, 0): [3, 5]}``). Paths are zero-based
|
|
||||||
indices following the splitter hierarchy, starting from the root splitter.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
To build three columns with custom per-column ratios::
|
|
||||||
|
|
||||||
area.set_layout_ratios(
|
|
||||||
horizontal=[1, 2, 1], # column widths
|
|
||||||
splitter_overrides={
|
|
||||||
0: [1, 2], # column 0 (two rows)
|
|
||||||
1: [3, 2, 1], # column 1 (three rows)
|
|
||||||
2: [1], # column 2 (single row)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def describe_layout(self) -> "list[dict[str, Any]]":
|
|
||||||
"""
|
|
||||||
Return metadata describing splitter paths, orientations, and contained docks.
|
|
||||||
|
|
||||||
Useful for determining the keys to use in `set_layout_ratios(splitter_overrides=...)`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def print_layout_structure(self) -> "None":
|
|
||||||
"""
|
|
||||||
Pretty-print the current splitter paths to stdout.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@rpc_call
|
|
||||||
def set_central_dock(self, dock: "CDockWidget | QWidget | str") -> "None":
|
|
||||||
"""
|
|
||||||
Promote an existing dock to be the dock manager's central widget.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
dock(CDockWidget | QWidget | str): Dock reference to promote.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MonacoWidget(RPCBase):
|
class MonacoWidget(RPCBase):
|
||||||
"""A simple Monaco editor widget"""
|
"""A simple Monaco editor widget"""
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from bec_widgets.cli.client_utils import IGNORE_WIDGETS
|
from typing import TYPE_CHECKING
|
||||||
from bec_widgets.utils.bec_plugin_helper import get_all_plugin_widgets
|
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_lib.utils.import_utils import lazy_import_from
|
||||||
from bec_widgets.utils.plugin_utils import get_custom_classes
|
|
||||||
|
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:
|
class RPCWidgetHandler:
|
||||||
@@ -13,7 +23,7 @@ class RPCWidgetHandler:
|
|||||||
self._widget_classes = None
|
self._widget_classes = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def widget_classes(self) -> dict[str, type[BECWidget]]:
|
def widget_classes(self) -> dict[str, type["BECWidget"]]:
|
||||||
"""
|
"""
|
||||||
Get the available widget classes.
|
Get the available widget classes.
|
||||||
|
|
||||||
@@ -31,12 +41,24 @@ class RPCWidgetHandler:
|
|||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
self._widget_classes = (
|
ignored = set(IGNORE_WIDGETS)
|
||||||
get_custom_classes("bec_widgets", packages=("widgets", "applications"))
|
widget_classes = {
|
||||||
+ get_all_plugin_widgets()
|
reference.name: lazy_import_from(reference.module, (reference.name,))
|
||||||
).as_dict(IGNORE_WIDGETS)
|
for reference in get_all_plugin_widget_references(use_cache=False)
|
||||||
|
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"), use_cache=False
|
||||||
|
)
|
||||||
|
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.
|
Create a widget from an RPC message.
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
import importlib.metadata
|
import importlib.metadata
|
||||||
import inspect
|
import inspect
|
||||||
|
import logging
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import traceback
|
import traceback
|
||||||
from importlib import util as importlib_util
|
from importlib import util as importlib_util
|
||||||
@@ -9,11 +11,65 @@ from importlib.machinery import FileFinder, ModuleSpec, SourceFileLoader
|
|||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
from bec_lib.logger import bec_logger
|
from bec_widgets.utils.plugin_utils import (
|
||||||
|
BECClassContainer,
|
||||||
|
BECClassInfo,
|
||||||
|
BECClassReference,
|
||||||
|
_ast_node_name,
|
||||||
|
_class_has_rpc_markers,
|
||||||
|
_discover_class_references_from_roots,
|
||||||
|
_find_package_roots,
|
||||||
|
)
|
||||||
|
|
||||||
from bec_widgets.utils.plugin_utils import BECClassContainer, BECClassInfo
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
_PLUGIN_WIDGET_REFERENCE_CACHE: dict[tuple[tuple[str, str], ...], tuple[BECClassReference, ...]] = (
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _plugin_entry_point_snapshot() -> tuple[tuple[str, str], ...]:
|
||||||
|
return tuple(
|
||||||
|
sorted(
|
||||||
|
(entry_point.name, entry_point.module)
|
||||||
|
for entry_point in importlib.metadata.entry_points(group="bec.widgets.user_widgets") # type: ignore
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_plugin_widget_references() -> tuple[BECClassReference, ...]:
|
||||||
|
references: list[BECClassReference] = []
|
||||||
|
seen_names: set[str] = set()
|
||||||
|
for entry_point in importlib.metadata.entry_points(group="bec.widgets.user_widgets"): # type: ignore
|
||||||
|
try:
|
||||||
|
package_roots = _find_package_roots(entry_point.module)
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
continue
|
||||||
|
for reference in _discover_class_references_from_roots(
|
||||||
|
entry_point.module,
|
||||||
|
package_roots,
|
||||||
|
file_name_filter=lambda file_name: file_name.endswith(".py")
|
||||||
|
and not file_name.startswith("__"),
|
||||||
|
candidate_filter=_plugin_class_is_candidate,
|
||||||
|
):
|
||||||
|
if reference.name in seen_names:
|
||||||
|
continue
|
||||||
|
references.append(reference)
|
||||||
|
seen_names.add(reference.name)
|
||||||
|
return tuple(references)
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_plugin_widget_references(*, use_cache: bool = True) -> list[BECClassReference]:
|
||||||
|
snapshot = _plugin_entry_point_snapshot()
|
||||||
|
if not use_cache or snapshot not in _PLUGIN_WIDGET_REFERENCE_CACHE:
|
||||||
|
_PLUGIN_WIDGET_REFERENCE_CACHE[snapshot] = _build_plugin_widget_references()
|
||||||
|
return list(_PLUGIN_WIDGET_REFERENCE_CACHE[snapshot])
|
||||||
|
|
||||||
|
|
||||||
def _submodule_specs(module: ModuleType) -> tuple[ModuleSpec | None, ...]:
|
def _submodule_specs(module: ModuleType) -> tuple[ModuleSpec | None, ...]:
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ from bec_widgets.widgets.utility.spinner.spinner import SpinnerWidget
|
|||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_widgets.utils.busy_loader import BusyLoaderOverlay
|
from bec_widgets.utils.busy_loader import BusyLoaderOverlay
|
||||||
from bec_widgets.widgets.containers.dock import BECDock
|
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING, Iterable
|
from functools import lru_cache
|
||||||
|
from importlib import util as importlib_util
|
||||||
from bec_lib.plugin_helper import _get_available_plugins
|
from typing import TYPE_CHECKING, Callable, Iterable
|
||||||
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
|
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
|
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.
|
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
|
The plugins are provided through python plugins and specified in the respective pyproject.toml file using
|
||||||
@@ -35,9 +36,10 @@ def get_plugin_widgets() -> dict[str, BECConnector]:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, BECConnector]: A dictionary of widget names and their respective classes.
|
dict[str, BECConnector]: A dictionary of widget names and their respective classes.
|
||||||
"""
|
"""
|
||||||
|
from bec_lib.plugin_helper import _get_available_plugins
|
||||||
|
|
||||||
modules = _get_available_plugins("bec.widgets.user_widgets")
|
modules = _get_available_plugins("bec.widgets.user_widgets")
|
||||||
loaded_plugins = {}
|
loaded_plugins = {}
|
||||||
print(modules)
|
|
||||||
for module in modules:
|
for module in modules:
|
||||||
mods = inspect.getmembers(module, predicate=_filter_plugins)
|
mods = inspect.getmembers(module, predicate=_filter_plugins)
|
||||||
for name, mod_cls in mods:
|
for name, mod_cls in mods:
|
||||||
@@ -48,6 +50,8 @@ def get_plugin_widgets() -> dict[str, BECConnector]:
|
|||||||
|
|
||||||
|
|
||||||
def _filter_plugins(obj):
|
def _filter_plugins(obj):
|
||||||
|
from bec_widgets.utils.bec_connector import BECConnector
|
||||||
|
|
||||||
return inspect.isclass(obj) and issubclass(obj, BECConnector)
|
return inspect.isclass(obj) and issubclass(obj, BECConnector)
|
||||||
|
|
||||||
|
|
||||||
@@ -66,6 +70,8 @@ def get_plugin_auto_updates() -> dict[str, type[AutoUpdates]]:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, AutoUpdates]: A dictionary of widget names and their respective classes.
|
dict[str, AutoUpdates]: A dictionary of widget names and their respective classes.
|
||||||
"""
|
"""
|
||||||
|
from bec_lib.plugin_helper import _get_available_plugins
|
||||||
|
|
||||||
modules = _get_available_plugins("bec.widgets.auto_updates")
|
modules = _get_available_plugins("bec.widgets.auto_updates")
|
||||||
loaded_plugins = {}
|
loaded_plugins = {}
|
||||||
for module in modules:
|
for module in modules:
|
||||||
@@ -90,14 +96,20 @@ class BECClassInfo:
|
|||||||
name: str
|
name: str
|
||||||
module: str
|
module: str
|
||||||
file: str
|
file: str
|
||||||
obj: type[BECWidget]
|
obj: type["BECWidget"]
|
||||||
is_connector: bool = False
|
is_connector: bool = False
|
||||||
is_widget: bool = False
|
is_widget: bool = False
|
||||||
is_plugin: bool = False
|
is_plugin: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BECClassReference:
|
||||||
|
name: str
|
||||||
|
module: str
|
||||||
|
|
||||||
|
|
||||||
class BECClassContainer:
|
class BECClassContainer:
|
||||||
def __init__(self, initial: Iterable[BECClassInfo] = []):
|
def __init__(self, initial: Iterable[BECClassInfo] = ()):
|
||||||
self._collection: list[BECClassInfo] = list(initial)
|
self._collection: list[BECClassInfo] = list(initial)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -109,12 +121,13 @@ class BECClassContainer:
|
|||||||
def __add__(self, other: BECClassContainer):
|
def __add__(self, other: BECClassContainer):
|
||||||
return BECClassContainer((*self, *(c for c in other if c.name not in self.names)))
|
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.
|
"""get a dict of {name: Type} for all the entries in the collection.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ignores(list[str]): a list of class names to exclude from the dictionary."""
|
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):
|
def add_class(self, class_info: BECClassInfo):
|
||||||
"""
|
"""
|
||||||
@@ -166,48 +179,276 @@ class BECClassContainer:
|
|||||||
return [info.obj for info in self.collection]
|
return [info.obj for info in self.collection]
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=64)
|
||||||
|
def _find_package_roots(module_name: str) -> tuple[str, ...]:
|
||||||
|
spec = importlib_util.find_spec(module_name)
|
||||||
|
if spec is None:
|
||||||
|
raise ModuleNotFoundError(module_name)
|
||||||
|
|
||||||
|
package_roots = tuple(spec.submodule_search_locations or ())
|
||||||
|
if package_roots:
|
||||||
|
return package_roots
|
||||||
|
if spec.origin:
|
||||||
|
return (os.path.dirname(spec.origin),)
|
||||||
|
raise ModuleNotFoundError(module_name)
|
||||||
|
|
||||||
|
|
||||||
|
def _discover_class_references_from_roots(
|
||||||
|
module_prefix: str,
|
||||||
|
package_roots: Iterable[str],
|
||||||
|
*,
|
||||||
|
file_name_filter: Callable[[str], bool],
|
||||||
|
candidate_filter: Callable[[ast.ClassDef], bool],
|
||||||
|
) -> tuple[BECClassReference, ...]:
|
||||||
|
references: list[BECClassReference] = []
|
||||||
|
seen_names: set[str] = set()
|
||||||
|
|
||||||
|
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_filter(file_name):
|
||||||
|
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)
|
||||||
|
rel_path = os.path.relpath(path, package_root).removesuffix(".py")
|
||||||
|
module_name = ".".join([module_prefix, *rel_path.split(os.sep)])
|
||||||
|
for node in module.body:
|
||||||
|
if not isinstance(node, ast.ClassDef) or not candidate_filter(node):
|
||||||
|
continue
|
||||||
|
if node.name in seen_names:
|
||||||
|
continue
|
||||||
|
references.append(BECClassReference(name=node.name, module=module_name))
|
||||||
|
seen_names.add(node.name)
|
||||||
|
|
||||||
|
return tuple(references)
|
||||||
|
|
||||||
|
|
||||||
|
def _iter_candidate_modules(repo_name: str, package: str) -> Iterable[tuple[str, str, list[str]]]:
|
||||||
|
try:
|
||||||
|
package_roots = _find_package_roots(f"{repo_name}.{package}")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
return ()
|
||||||
|
|
||||||
|
modules: list[tuple[str, str, list[str]]] = []
|
||||||
|
for directory in package_roots:
|
||||||
|
for root, _, files in sorted(os.walk(directory)):
|
||||||
|
for file_name in sorted(files):
|
||||||
|
if (
|
||||||
|
not file_name.endswith(".py")
|
||||||
|
or file_name.startswith("__")
|
||||||
|
or file_name.startswith("register_")
|
||||||
|
or file_name.endswith("_plugin.py")
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
path = os.path.join(root, file_name)
|
||||||
|
rel_dir = os.path.dirname(os.path.relpath(path, directory))
|
||||||
|
module_name = (
|
||||||
|
file_name.removesuffix(".py")
|
||||||
|
if rel_dir in ("", ".")
|
||||||
|
else ".".join(rel_dir.split(os.sep) + [file_name.removesuffix(".py")])
|
||||||
|
)
|
||||||
|
class_names = _candidate_top_level_class_names(path)
|
||||||
|
if class_names:
|
||||||
|
modules.append((f"{repo_name}.{package}.{module_name}", path, class_names))
|
||||||
|
return tuple(modules)
|
||||||
|
|
||||||
|
|
||||||
def _collect_classes_from_package(repo_name: str, package: str) -> BECClassContainer:
|
def _collect_classes_from_package(repo_name: str, package: str) -> BECClassContainer:
|
||||||
"""Collect classes from a package subtree (for example ``widgets`` or ``applications``)."""
|
"""Collect classes from a package subtree (for example ``widgets`` or ``applications``)."""
|
||||||
collection = BECClassContainer()
|
collection = BECClassContainer()
|
||||||
try:
|
for module_name, path, _ in _iter_candidate_modules(repo_name, package):
|
||||||
anchor_module = importlib.import_module(f"{repo_name}.{package}")
|
from qtpy.QtWidgets import QWidget
|
||||||
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
|
|
||||||
raise
|
|
||||||
|
|
||||||
directory = os.path.dirname(anchor_module.__file__)
|
from bec_widgets.utils.bec_connector import BECConnector
|
||||||
for root, _, files in sorted(os.walk(directory)):
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
for file in files:
|
|
||||||
if not file.endswith(".py") or file.startswith("__"):
|
module = importlib.import_module(module_name)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ != module.__name__:
|
||||||
continue
|
continue
|
||||||
|
class_info = BECClassInfo(name=name, module=module.__name__, file=path, obj=obj)
|
||||||
path = os.path.join(root, file)
|
if issubclass(obj, BECConnector):
|
||||||
rel_dir = os.path.dirname(os.path.relpath(path, directory))
|
class_info.is_connector = True
|
||||||
if rel_dir in ("", "."):
|
if issubclass(obj, QWidget) or issubclass(obj, BECWidget):
|
||||||
module_name = file.split(".")[0]
|
class_info.is_widget = True
|
||||||
else:
|
if hasattr(obj, "PLUGIN") and obj.PLUGIN:
|
||||||
module_name = ".".join(rel_dir.split(os.sep) + [file.split(".")[0]])
|
class_info.is_plugin = True
|
||||||
|
collection.add_class(class_info)
|
||||||
module = importlib.import_module(f"{repo_name}.{package}.{module_name}")
|
|
||||||
|
|
||||||
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)
|
|
||||||
return collection
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
def _build_ast_inheritance_map(
|
||||||
|
repo_name: str, packages: tuple[str, ...]
|
||||||
|
) -> dict[str, tuple[str, set[str]]]:
|
||||||
|
"""
|
||||||
|
Walk all candidate modules in the given packages and return a map of:
|
||||||
|
class_name -> (module_name, {direct_base_names})
|
||||||
|
|
||||||
|
This is used for the transitive-closure widget discovery so that subclasses
|
||||||
|
of discovered widget bases are themselves discoverable without needing to
|
||||||
|
repeat ``PLUGIN = True`` on every intermediate or leaf class.
|
||||||
|
"""
|
||||||
|
mapping: dict[str, tuple[str, set[str]]] = {}
|
||||||
|
for package in packages:
|
||||||
|
try:
|
||||||
|
package_roots = _find_package_roots(f"{repo_name}.{package}")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
continue
|
||||||
|
for directory in package_roots:
|
||||||
|
for root, _, files in sorted(os.walk(directory)):
|
||||||
|
for file_name in sorted(files):
|
||||||
|
if (
|
||||||
|
not file_name.endswith(".py")
|
||||||
|
or file_name.startswith("__")
|
||||||
|
or file_name.startswith("register_")
|
||||||
|
or file_name.endswith("_plugin.py")
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
path = os.path.join(root, file_name)
|
||||||
|
rel_dir = os.path.dirname(os.path.relpath(path, directory))
|
||||||
|
module_name = (
|
||||||
|
file_name.removesuffix(".py")
|
||||||
|
if rel_dir in ("", ".")
|
||||||
|
else ".".join(rel_dir.split(os.sep) + [file_name.removesuffix(".py")])
|
||||||
|
)
|
||||||
|
full_module = f"{repo_name}.{package}.{module_name}"
|
||||||
|
with open(path, encoding="utf-8") as fh:
|
||||||
|
tree = ast.parse(fh.read(), filename=path)
|
||||||
|
for node in tree.body:
|
||||||
|
if not isinstance(node, ast.ClassDef):
|
||||||
|
continue
|
||||||
|
base_names = {_ast_node_name(b) for b in node.bases} - {None}
|
||||||
|
mapping[node.name] = (full_module, base_names) # type: ignore[arg-type]
|
||||||
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=32)
|
||||||
|
def _cached_custom_class_references(
|
||||||
|
repo_name: str, packages: tuple[str, ...]
|
||||||
|
) -> tuple[BECClassReference, ...]:
|
||||||
|
"""Discover widget/connector class references using a transitive-closure AST scan.
|
||||||
|
|
||||||
|
The first pass identifies classes that directly inherit from
|
||||||
|
``_DISCOVERY_BASE_NAMES`` or carry explicit RPC markers (``PLUGIN``,
|
||||||
|
``USER_ACCESS``, ``RPC_CONTENT_CLASS``). Subsequent passes treat every
|
||||||
|
newly found class name as an additional base name, so subclasses of
|
||||||
|
subclasses are discovered automatically — without requiring each
|
||||||
|
intermediate class to repeat ``PLUGIN = True``.
|
||||||
|
"""
|
||||||
|
inheritance_map = _build_ast_inheritance_map(repo_name, packages)
|
||||||
|
|
||||||
|
# Seed with _class_has_rpc_markers — we need the AST nodes for that check.
|
||||||
|
# Re-parse only to identify initial RPC-marker classes; inheritance_map
|
||||||
|
# already has everything else we need.
|
||||||
|
rpc_marker_names: set[str] = set()
|
||||||
|
for package in packages:
|
||||||
|
try:
|
||||||
|
package_roots = _find_package_roots(f"{repo_name}.{package}")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
continue
|
||||||
|
for directory in package_roots:
|
||||||
|
for root, _, files in sorted(os.walk(directory)):
|
||||||
|
for file_name in sorted(files):
|
||||||
|
if (
|
||||||
|
not file_name.endswith(".py")
|
||||||
|
or file_name.startswith("__")
|
||||||
|
or file_name.startswith("register_")
|
||||||
|
or file_name.endswith("_plugin.py")
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
path = os.path.join(root, file_name)
|
||||||
|
with open(path, encoding="utf-8") as fh:
|
||||||
|
tree = ast.parse(fh.read(), filename=path)
|
||||||
|
for node in tree.body:
|
||||||
|
if isinstance(node, ast.ClassDef) and _class_has_rpc_markers(node):
|
||||||
|
rpc_marker_names.add(node.name)
|
||||||
|
|
||||||
|
# Transitive closure: start with known base names + RPC-marker classes,
|
||||||
|
# then repeatedly add classes whose direct bases are already known.
|
||||||
|
known: set[str] = set(_DISCOVERY_BASE_NAMES) | rpc_marker_names
|
||||||
|
changed = True
|
||||||
|
while changed:
|
||||||
|
changed = False
|
||||||
|
for class_name, (_, bases) in inheritance_map.items():
|
||||||
|
if class_name not in known and bases & known:
|
||||||
|
known.add(class_name)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Build the final list of references, preserving first-seen order and
|
||||||
|
# keeping only classes that are in the inheritance map (i.e. have a module).
|
||||||
|
references: list[BECClassReference] = []
|
||||||
|
seen_names: set[str] = set()
|
||||||
|
for class_name, (module_name, bases) in inheritance_map.items():
|
||||||
|
if class_name not in known:
|
||||||
|
continue
|
||||||
|
if class_name in seen_names:
|
||||||
|
continue
|
||||||
|
# Only emit if the class is actually a candidate (not just a raw base)
|
||||||
|
if class_name in _DISCOVERY_BASE_NAMES:
|
||||||
|
continue
|
||||||
|
references.append(BECClassReference(name=class_name, module=module_name))
|
||||||
|
seen_names.add(class_name)
|
||||||
|
return tuple(references)
|
||||||
|
|
||||||
|
|
||||||
|
def get_custom_class_references(
|
||||||
|
repo_name: str, packages: tuple[str, ...] | None = None, *, use_cache: bool = True
|
||||||
|
) -> list[BECClassReference]:
|
||||||
|
selected_packages = packages or ("widgets",)
|
||||||
|
if use_cache:
|
||||||
|
return list(_cached_custom_class_references(repo_name, tuple(selected_packages)))
|
||||||
|
_cached_custom_class_references.cache_clear()
|
||||||
|
return list(_cached_custom_class_references(repo_name, tuple(selected_packages)))
|
||||||
|
|
||||||
|
|
||||||
def get_custom_classes(
|
def get_custom_classes(
|
||||||
repo_name: str, packages: tuple[str, ...] | None = None
|
repo_name: str, packages: tuple[str, ...] | None = None
|
||||||
) -> BECClassContainer:
|
) -> BECClassContainer:
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ from qtpy.QtWidgets import QWidget
|
|||||||
from redis.exceptions import RedisError
|
from redis.exceptions import RedisError
|
||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
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_connector import BECConnector
|
||||||
|
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
||||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||||
from bec_widgets.utils.error_popups import ErrorPopupUtility
|
from bec_widgets.utils.error_popups import ErrorPopupUtility
|
||||||
from bec_widgets.utils.screen_utils import apply_window_geometry
|
from bec_widgets.utils.screen_utils import apply_window_geometry
|
||||||
@@ -25,7 +25,6 @@ from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
|
|||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_lib import messages
|
from bec_lib import messages
|
||||||
from qtpy.QtCore import QObject
|
|
||||||
else:
|
else:
|
||||||
messages = lazy_import("bec_lib.messages")
|
messages = lazy_import("bec_lib.messages")
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from qtpy.QtWidgets import (
|
|||||||
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_widgets.utils import BECConnector
|
from bec_widgets.utils.bec_connector import BECConnector
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
@@ -418,7 +418,7 @@ class WidgetHierarchy:
|
|||||||
only_bec_widgets(bool, optional): Whether to print only widgets that are instances of BECWidget.
|
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.
|
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
|
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||||
|
|
||||||
for node in WidgetHierarchy.iter_widget_tree(
|
for node in WidgetHierarchy.iter_widget_tree(
|
||||||
@@ -468,7 +468,7 @@ class WidgetHierarchy:
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QApplication
|
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
|
from bec_widgets.widgets.plots.plot_base import PlotBase
|
||||||
|
|
||||||
# 1) Gather ALL QWidget-based BECConnector objects
|
# 1) Gather ALL QWidget-based BECConnector objects
|
||||||
@@ -534,7 +534,7 @@ class WidgetHierarchy:
|
|||||||
Returns:
|
Returns:
|
||||||
The nearest ancestor that is a BECConnector, or None if not found.
|
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
|
# Guard against deleted/invalid Qt wrappers
|
||||||
if not shb.isValid(widget):
|
if not shb.isValid(widget):
|
||||||
@@ -636,7 +636,7 @@ class WidgetHierarchy:
|
|||||||
Return all BECConnector instances whose closest BECConnector ancestor is the given widget,
|
Return all BECConnector instances whose closest BECConnector ancestor is the given widget,
|
||||||
including the widget itself if it is a BECConnector.
|
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] = []
|
connectors: list[BECConnector] = []
|
||||||
if isinstance(widget, BECConnector):
|
if isinstance(widget, BECConnector):
|
||||||
@@ -664,7 +664,7 @@ class WidgetHierarchy:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
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
|
is_bec_target = False
|
||||||
if isinstance(ancestor_class, str):
|
if isinstance(ancestor_class, str):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import bec_widgets.widgets.containers.qt_ads as QtAds
|
|||||||
from bec_widgets import BECWidget, SafeProperty, SafeSlot
|
from bec_widgets import BECWidget, SafeProperty, SafeSlot
|
||||||
from bec_widgets.applications.views.view import ViewTourSteps
|
from bec_widgets.applications.views.view import ViewTourSteps
|
||||||
from bec_widgets.cli.rpc.rpc_widget_handler import widget_handler
|
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.colors import apply_theme
|
||||||
from bec_widgets.utils.rpc_decorator import rpc_timeout
|
from bec_widgets.utils.rpc_decorator import rpc_timeout
|
||||||
from bec_widgets.utils.toolbars.actions import (
|
from bec_widgets.utils.toolbars.actions import (
|
||||||
@@ -68,7 +68,7 @@ from bec_widgets.widgets.containers.dock_area.toolbar_components.workspace_actio
|
|||||||
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindowNoRPC
|
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindowNoRPC
|
||||||
from bec_widgets.widgets.containers.qt_ads import CDockWidget
|
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.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.bec_console.bec_console import BecConsole, BECShell
|
from bec_widgets.widgets.editors.bec_console.bec_console import BecConsole, BECShell
|
||||||
from bec_widgets.widgets.plots.heatmap.heatmap import Heatmap
|
from bec_widgets.widgets.plots.heatmap.heatmap import Heatmap
|
||||||
from bec_widgets.widgets.plots.image.image import Image
|
from bec_widgets.widgets.plots.image.image import Image
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ from qtpy.QtCore import QObject, QTimer
|
|||||||
from qtpy.QtWidgets import QApplication, QFrame, QMainWindow, QScrollArea, QWidget
|
from qtpy.QtWidgets import QApplication, QFrame, QMainWindow, QScrollArea, QWidget
|
||||||
|
|
||||||
from bec_widgets import SafeProperty, SafeSlot
|
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.colors import apply_theme
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ from qtpy.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
import bec_widgets
|
import bec_widgets
|
||||||
from bec_widgets.utils import UILoader
|
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import apply_theme
|
from bec_widgets.utils.colors import apply_theme
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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.hover_widget import HoverWidget
|
||||||
from bec_widgets.widgets.containers.main_window.addons.notification_center.notification_banner import (
|
from bec_widgets.widgets.containers.main_window.addons.notification_center.notification_banner import (
|
||||||
BECNotificationBroker,
|
BECNotificationBroker,
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
from PySide6QtAds import *
|
from PySide6QtAds import *
|
||||||
|
|
||||||
|
CDockManager.setConfigFlag(CDockManager.eConfigFlag.FocusHighlighting, True)
|
||||||
|
CDockManager.setConfigFlag(CDockManager.eConfigFlag.RetainTabSizeWhenCloseButtonHidden, True)
|
||||||
|
|||||||
+1
-1
@@ -11,9 +11,9 @@ from qtpy.QtCore import Qt, Signal
|
|||||||
from qtpy.QtGui import QDoubleValidator
|
from qtpy.QtGui import QDoubleValidator
|
||||||
from qtpy.QtWidgets import QDoubleSpinBox
|
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.colors import apply_theme, get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
|
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
|
||||||
DeviceUpdateUIComponents,
|
DeviceUpdateUIComponents,
|
||||||
PositionerBoxBase,
|
PositionerBoxBase,
|
||||||
|
|||||||
+1
-1
@@ -12,9 +12,9 @@ from qtpy.QtCore import Signal
|
|||||||
from qtpy.QtGui import QDoubleValidator
|
from qtpy.QtGui import QDoubleValidator
|
||||||
from qtpy.QtWidgets import QDoubleSpinBox
|
from qtpy.QtWidgets import QDoubleSpinBox
|
||||||
|
|
||||||
from bec_widgets.utils import UILoader
|
|
||||||
from bec_widgets.utils.colors import apply_theme
|
from bec_widgets.utils.colors import apply_theme
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
|
from bec_widgets.widgets.control.device_control.positioner_box.positioner_box_base import (
|
||||||
DeviceUpdateUIComponents,
|
DeviceUpdateUIComponents,
|
||||||
PositionerBoxBase,
|
PositionerBoxBase,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from bec_lib.device import Signal as BECSignal
|
|||||||
from bec_lib.logger import bec_logger
|
from bec_lib.logger import bec_logger
|
||||||
from pydantic import field_validator
|
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.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.filter_io import FilterIO
|
from bec_widgets.utils.filter_io import FilterIO
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from bec_lib.device import Signal
|
|||||||
from bec_lib.logger import bec_logger
|
from bec_lib.logger import bec_logger
|
||||||
from qtpy.QtCore import Property
|
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.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.filter_io import FilterIO
|
from bec_widgets.utils.filter_io import FilterIO
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
from .components import DeviceTable, DMConfigView, DocstringView, OphydValidation
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
from .available_device_resources import AvailableDeviceResources
|
|
||||||
|
|
||||||
__all__ = ["AvailableDeviceResources"]
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from bec_widgets.utils.fuzzy_search import is_match
|
|||||||
from bec_widgets.widgets.control.device_manager.components.device_table.device_table_row import (
|
from bec_widgets.widgets.control.device_manager.components.device_table.device_table_row import (
|
||||||
DeviceTableRow,
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
get_validation_icons,
|
get_validation_icons,
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from bec_lib.atlas_models import Device as DeviceModel
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
+5
-3
@@ -22,15 +22,17 @@ from bec_widgets.utils.bec_list import BECList
|
|||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
from bec_widgets.utils.colors import get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
DeviceTestModel,
|
DeviceTestModel,
|
||||||
ValidationButton,
|
|
||||||
ValidationListItem,
|
|
||||||
format_error_to_md,
|
format_error_to_md,
|
||||||
get_validation_icons,
|
get_validation_icons,
|
||||||
)
|
)
|
||||||
|
from bec_widgets.widgets.control.device_manager.components.ophyd_validation.validation_list_item import (
|
||||||
|
ValidationButton,
|
||||||
|
ValidationListItem,
|
||||||
|
)
|
||||||
|
|
||||||
READY_TO_TEST = False
|
READY_TO_TEST = False
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ from qtpy import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
from bec_widgets.utils.colors import get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
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,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
DeviceTestModel,
|
DeviceTestModel,
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
from .scan_control import ScanControl
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
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.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import apply_theme, get_accent_colors
|
from bec_widgets.utils.colors import apply_theme, get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ from bec_lib.logger import bec_logger
|
|||||||
from qtpy.QtCore import Signal
|
from qtpy.QtCore import Signal
|
||||||
from qtpy.QtWidgets import QPushButton, QSizePolicy, QTreeWidgetItem, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QPushButton, QSizePolicy, QTreeWidgetItem, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.utils import UILoader
|
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
from bec_widgets.utils.colors import get_accent_colors
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|||||||
@@ -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.inprocess import QtInProcessKernelManager
|
||||||
from qtconsole.manager import QtKernelManager
|
from qtconsole.manager import QtKernelManager
|
||||||
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
||||||
from qtpy.QtCore import Qt
|
from qtpy.QtCore import Qt
|
||||||
from qtpy.QtWidgets import QApplication, QMainWindow
|
from qtpy.QtWidgets import QApplication, QMainWindow
|
||||||
|
|
||||||
|
BECIPythonClient = lazy_import_from("bec_ipython_client.main", ("BECIPythonClient",))
|
||||||
|
|
||||||
|
|
||||||
class BECJupyterConsole(RichJupyterWidget): # pragma: no cover:
|
class BECJupyterConsole(RichJupyterWidget): # pragma: no cover:
|
||||||
def __init__(self, inprocess: bool = False):
|
def __init__(self, inprocess: bool = False):
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from bec_lib.logger import bec_logger
|
|||||||
from qtpy.QtCore import QSize, Qt
|
from qtpy.QtCore import QSize, Qt
|
||||||
from qtpy.QtWidgets import QDialog, QDialogButtonBox, QPushButton, QVBoxLayout
|
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
|
logger = bec_logger.logger
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ from scipy.interpolate import (
|
|||||||
from scipy.spatial import cKDTree
|
from scipy.spatial import cKDTree
|
||||||
from toolz import partition
|
from toolz import partition
|
||||||
|
|
||||||
from bec_widgets.utils import Colors
|
|
||||||
from bec_widgets.utils.bec_connector import 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.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import os
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout
|
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.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
from bec_widgets.utils.settings_dialog import SettingWidget
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
|
|
||||||
|
|
||||||
class HeatmapSettings(SettingWidget):
|
class HeatmapSettings(SettingWidget):
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from pydantic import BaseModel, Field, field_validator
|
|||||||
from qtpy.QtCore import QTimer
|
from qtpy.QtCore import QTimer
|
||||||
from qtpy.QtWidgets import QWidget
|
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.colors import Colors, apply_theme
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.widgets.plots.image.image_base import ImageBase
|
from bec_widgets.widgets.plots.image.image_base import ImageBase
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationError
|
|||||||
from qtpy.QtCore import QPointF, Signal, SignalInstance
|
from qtpy.QtCore import QPointF, Signal, SignalInstance
|
||||||
from qtpy.QtWidgets import QDialog, QVBoxLayout
|
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.container_utils import WidgetContainerUtils
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.side_panel import SidePanel
|
from bec_widgets.utils.side_panel import SidePanel
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ from pydantic import Field, ValidationError, field_validator
|
|||||||
from qtpy.QtCore import Signal
|
from qtpy.QtCore import Signal
|
||||||
from qtpy.QtGui import QTransform
|
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 (
|
from bec_widgets.widgets.plots.image.image_processor import (
|
||||||
ImageProcessor,
|
ImageProcessor,
|
||||||
ImageStats,
|
ImageStats,
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ from qtpy.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets import BECWidget
|
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.actions import WidgetAction
|
||||||
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
||||||
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar
|
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ from qtpy.QtCore import Signal
|
|||||||
from qtpy.QtGui import QColor
|
from qtpy.QtGui import QColor
|
||||||
from qtpy.QtWidgets import QHBoxLayout, QMainWindow, QWidget
|
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 apply_theme
|
from bec_widgets.utils.colors import Colors, apply_theme
|
||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction
|
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import os
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout, QWidget
|
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.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
from bec_widgets.utils.settings_dialog import SettingWidget
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ from pydantic import Field, ValidationError, field_validator
|
|||||||
from qtpy.QtCore import Signal
|
from qtpy.QtCore import Signal
|
||||||
from qtpy.QtWidgets import QWidget
|
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.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.side_panel import SidePanel
|
from bec_widgets.utils.side_panel import SidePanel
|
||||||
from bec_widgets.widgets.control.device_input.device_combobox.device_combobox import DeviceComboBox
|
from bec_widgets.widgets.control.device_input.device_combobox.device_combobox import DeviceComboBox
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import os
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.utils import UILoader
|
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
from bec_widgets.utils.settings_dialog import SettingWidget
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ from bec_lib import bec_logger
|
|||||||
from qtpy.QtCore import QPoint, QPointF, Qt, Signal
|
from qtpy.QtCore import QPoint, QPointF, Qt, Signal
|
||||||
from qtpy.QtWidgets import QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget
|
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.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.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.fps_counter import FPSCounter
|
from bec_widgets.utils.fps_counter import FPSCounter
|
||||||
from bec_widgets.utils.plot_indicator_items import BECArrowItem, BECTickItem
|
from bec_widgets.utils.plot_indicator_items import BECArrowItem, BECTickItem
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from qtpy import QtCore
|
|||||||
from qtpy.QtCore import QObject, Signal
|
from qtpy.QtCore import QObject, Signal
|
||||||
|
|
||||||
from bec_widgets import SafeProperty
|
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
|
from bec_widgets.utils.colors import Colors
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ from bec_lib import bec_logger
|
|||||||
from pydantic import BaseModel, Field, ValidationError, field_validator
|
from pydantic import BaseModel, Field, ValidationError, field_validator
|
||||||
from qtpy import QtCore
|
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
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterWaveform
|
from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterWaveform
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ from pydantic import Field, ValidationError, field_validator
|
|||||||
from qtpy.QtCore import QTimer, Signal
|
from qtpy.QtCore import QTimer, Signal
|
||||||
from qtpy.QtWidgets import QHBoxLayout, QMainWindow, QWidget
|
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.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction
|
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import os
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout
|
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.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
from bec_widgets.utils.settings_dialog import SettingWidget
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
|
|
||||||
|
|
||||||
class ScatterCurveSettings(SettingWidget):
|
class ScatterCurveSettings(SettingWidget):
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import os
|
|||||||
|
|
||||||
from qtpy.QtWidgets import QFrame, QScrollArea, QVBoxLayout, QWidget
|
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.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
from bec_widgets.utils.settings_dialog import SettingWidget
|
||||||
|
from bec_widgets.utils.ui_loader import UILoader
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
from bec_widgets.utils.widget_io import WidgetIO
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ from bec_lib import bec_logger
|
|||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from qtpy import QtCore
|
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
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||||
|
|||||||
@@ -50,9 +50,10 @@ from qtpy.QtWidgets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets import SafeSlot
|
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.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import Colors
|
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.actions import WidgetAction
|
||||||
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
||||||
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar
|
from bec_widgets.utils.toolbars.toolbar import MaterialIconAction, ModularToolBar
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
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.bec_signal_proxy import BECSignalProxy
|
||||||
from bec_widgets.utils.colors import Colors, apply_theme
|
from bec_widgets.utils.colors import Colors, apply_theme
|
||||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ from bec_lib.logger import bec_logger
|
|||||||
from qtpy.QtCore import QPointF, QSize, Qt
|
from qtpy.QtCore import QPointF, QSize, Qt
|
||||||
from qtpy.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QWidget
|
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.bec_widget import BECWidget
|
||||||
|
from bec_widgets.utils.colors import Colors
|
||||||
from bec_widgets.utils.error_popups import SafeProperty
|
from bec_widgets.utils.error_popups import SafeProperty
|
||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
from bec_widgets.utils.toolbars.actions import MaterialIconAction
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bec_widgets.utils import UILoader
|
|
||||||
from bec_widgets.utils.error_popups import SafeSlot
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingWidget
|
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.progress.ring_progress_bar.ring import Ring
|
||||||
from bec_widgets.widgets.utility.visual.colormap_widget.colormap_widget import BECColorMapWidget
|
from bec_widgets.widgets.utility.visual.colormap_widget.colormap_widget import BECColorMapWidget
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ from bec_widgets.utils.bec_widget import BECWidget
|
|||||||
from bec_widgets.utils.error_popups import SafeSlot
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
from bec_widgets.utils.list_of_expandable_frames import ListOfExpandableFrames
|
from bec_widgets.utils.list_of_expandable_frames import ListOfExpandableFrames
|
||||||
from bec_widgets.utils.ui_loader import UILoader
|
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 (
|
from bec_widgets.widgets.services.device_browser.device_item.device_config_dialog import (
|
||||||
DirectUpdateDeviceConfigDialog,
|
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
|
from bec_widgets.widgets.services.device_browser.util import map_device_type_to_icon
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
from .device_item import DeviceItem
|
|
||||||
|
|||||||
@@ -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"]
|
|
||||||
|
|||||||
@@ -330,8 +330,10 @@ class ScanHistoryView(BECWidget, QtWidgets.QTreeWidget):
|
|||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
# pylint: disable=import-outside-toplevel
|
# 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,
|
ScanHistoryDeviceViewer,
|
||||||
|
)
|
||||||
|
from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import (
|
||||||
ScanHistoryMetadataViewer,
|
ScanHistoryMetadataViewer,
|
||||||
)
|
)
|
||||||
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
from qtpy import QtCore, QtWidgets
|
from qtpy import QtCore, QtWidgets
|
||||||
|
|
||||||
from bec_widgets.utils.bec_widget import BECWidget, ConnectionConfig
|
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,
|
ScanHistoryDeviceViewer,
|
||||||
|
)
|
||||||
|
from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import (
|
||||||
ScanHistoryMetadataViewer,
|
ScanHistoryMetadataViewer,
|
||||||
|
)
|
||||||
|
from bec_widgets.widgets.services.scan_history_browser.components.scan_history_view import (
|
||||||
ScanHistoryView,
|
ScanHistoryView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ from qtpy import QtCore, QtGui
|
|||||||
from qtpy.QtCore import Property, Signal, Slot
|
from qtpy.QtCore import Property, Signal, Slot
|
||||||
from qtpy.QtWidgets import QSizePolicy, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QSizePolicy, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.utils import Colors
|
from bec_widgets.utils.colors import Colors
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
|
||||||
|
|
||||||
|
|
||||||
class RoundedColorMapButton(ColorMapButton):
|
class RoundedColorMapButton(ColorMapButton):
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from qtpy.QtWidgets import (
|
|||||||
QWidget,
|
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_highlighter import WidgetHighlighter
|
||||||
from bec_widgets.utils.widget_io import WidgetHierarchy
|
from bec_widgets.utils.widget_io import WidgetHierarchy
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import random
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from bec_widgets.cli.client_utils import BECGuiClient
|
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=unused-argument
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
|
|||||||
@@ -89,13 +89,6 @@ def test_available_widgets(qtbot, connected_client_gui_obj):
|
|||||||
# Skip private attributes
|
# Skip private attributes
|
||||||
if object_name.startswith("_"):
|
if object_name.startswith("_"):
|
||||||
continue
|
continue
|
||||||
# Skip BECShell as ttyd is not installed
|
|
||||||
if object_name == "BECShell":
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Skip BecConsole as ttyd is not installed
|
|
||||||
if object_name == "BecConsole":
|
|
||||||
continue
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
######### Add widget ########
|
######### Add widget ########
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ except ImportError:
|
|||||||
from qtpy.QtWidgets import QGridLayout
|
from qtpy.QtWidgets import QGridLayout
|
||||||
|
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
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")
|
@pytest.fixture(scope="function")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import pytest
|
|||||||
from qtpy.QtCore import QObject
|
from qtpy.QtCore import QObject
|
||||||
from qtpy.QtWidgets import QApplication, QWidget
|
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 SafeProperty
|
||||||
from bec_widgets.utils.error_popups import SafeSlot as Slot
|
from bec_widgets.utils.error_popups import SafeSlot as Slot
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ from pydantic import ValidationError
|
|||||||
from qtpy.QtGui import QColor
|
from qtpy.QtGui import QColor
|
||||||
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
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.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 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
|
from .client_mocks import mocked_client
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
def test_color_validation_CSS():
|
def test_color_validation_CSS():
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import pytest
|
|||||||
from qtpy.QtCore import QPointF, Qt
|
from qtpy.QtCore import QPointF, Qt
|
||||||
from qtpy.QtGui import QTransform
|
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.image.image_item import ImageItem
|
||||||
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
|
|
||||||
|
from .client_mocks import mocked_client
|
||||||
from .conftest import create_widget
|
from .conftest import create_widget
|
||||||
|
|
||||||
# pylint: disable = redefined-outer-name
|
# pylint: disable = redefined-outer-name
|
||||||
@@ -214,7 +214,7 @@ def test_crosshair_clicked_signal(qtbot, plot_widget_with_crosshair):
|
|||||||
pos_in_widget = graphics_view.mapFromScene(pos_in_scene)
|
pos_in_widget = graphics_view.mapFromScene(pos_in_scene)
|
||||||
|
|
||||||
# Simulate mouse click
|
# Simulate mouse click
|
||||||
qtbot.mouseClick(graphics_view.viewport(), Qt.LeftButton, pos=pos_in_widget)
|
qtbot.mouseClick(graphics_view.viewport(), Qt.MouseButton.LeftButton, pos=pos_in_widget)
|
||||||
|
|
||||||
x, y = emitted_positions[0]
|
x, y = emitted_positions[0]
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ from bec_widgets.widgets.plots.waveform.settings.curve_settings.curve_tree impor
|
|||||||
ScanIndexValidator,
|
ScanIndexValidator,
|
||||||
)
|
)
|
||||||
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||||
from tests.unit_tests.client_mocks import dap_plugin_message, mocked_client, mocked_client_with_dap
|
|
||||||
from tests.unit_tests.conftest import create_widget
|
from .client_mocks import dap_plugin_message, mocked_client, mocked_client_with_dap
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# CurveSetting
|
# CurveSetting
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from .client_mocks import mocked_client
|
|||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from qtpy.QtWidgets import QListWidgetItem
|
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
|
# pylint: disable=no-member
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ from qtpy import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from bec_widgets.utils.bec_list import BECList
|
from bec_widgets.utils.bec_list import BECList
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
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.constants import HEADERS_HELP_MD
|
||||||
from bec_widgets.widgets.control.device_manager.components.device_config_template.device_config_template import (
|
from bec_widgets.widgets.control.device_manager.components.device_config_template.device_config_template import (
|
||||||
DeviceConfigTemplate,
|
DeviceConfigTemplate,
|
||||||
@@ -34,9 +32,17 @@ from bec_widgets.widgets.control.device_manager.components.device_config_templat
|
|||||||
ReadoutPriorityComboBox,
|
ReadoutPriorityComboBox,
|
||||||
_try_literal_eval,
|
_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 (
|
from bec_widgets.widgets.control.device_manager.components.device_table.device_table_row import (
|
||||||
DeviceTableRow,
|
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 (
|
from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation import (
|
||||||
DeviceTest,
|
DeviceTest,
|
||||||
LegendLabel,
|
LegendLabel,
|
||||||
|
|||||||
@@ -31,12 +31,11 @@ from bec_widgets.applications.views.device_manager_view.device_manager_view impo
|
|||||||
DeviceManagerWidget,
|
DeviceManagerWidget,
|
||||||
)
|
)
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
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,
|
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 (
|
from bec_widgets.widgets.control.device_manager.components.ophyd_validation.ophyd_validation import (
|
||||||
ConfigStatus,
|
ConfigStatus,
|
||||||
ConnectionStatus,
|
ConnectionStatus,
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ from bec_widgets.widgets.plots.heatmap.heatmap import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# pytest: disable=unused-import
|
# pytest: disable=unused-import
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
from .client_mocks import create_dummy_scan_item, mocked_client
|
||||||
|
|
||||||
from .client_mocks import create_dummy_scan_item
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ from qtpy.QtCore import QPointF, Qt
|
|||||||
from bec_widgets.widgets.plots.image.image import Image
|
from bec_widgets.widgets.plots.image.image import Image
|
||||||
from bec_widgets.widgets.plots.image.setting_widgets.image_roi_tree import ROIPropertyTree
|
from bec_widgets.widgets.plots.image.setting_widgets.image_roi_tree import ROIPropertyTree
|
||||||
from bec_widgets.widgets.plots.roi.image_roi import CircularROI, RectangularROI
|
from bec_widgets.widgets.plots.roi.image_roi import CircularROI, RectangularROI
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
from tests.unit_tests.conftest import create_widget
|
from .client_mocks import mocked_client
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -44,7 +45,7 @@ def test_initialization(roi_tree, image_widget):
|
|||||||
assert roi_tree.plot == image_widget.plot_item
|
assert roi_tree.plot == image_widget.plot_item
|
||||||
assert roi_tree.controller == image_widget.roi_controller
|
assert roi_tree.controller == image_widget.roi_controller
|
||||||
assert isinstance(roi_tree.roi_items, dict)
|
assert isinstance(roi_tree.roi_items, dict)
|
||||||
assert len(roi_tree.tree.findItems("", Qt.MatchContains)) == 0 # Empty tree initially
|
assert len(roi_tree.tree.findItems("", Qt.MatchFlag.MatchContains)) == 0 # Empty tree initially
|
||||||
|
|
||||||
# Check toolbar actions
|
# Check toolbar actions
|
||||||
assert roi_tree.toolbar.components.get_action("roi_rectangle")
|
assert roi_tree.toolbar.components.get_action("roi_rectangle")
|
||||||
@@ -66,12 +67,16 @@ def test_controller_connection(roi_tree, image_widget):
|
|||||||
|
|
||||||
# Verify that ROI was added to the tree
|
# Verify that ROI was added to the tree
|
||||||
assert roi in roi_tree.roi_items
|
assert roi in roi_tree.roi_items
|
||||||
assert len(roi_tree.tree.findItems("test_roi", Qt.MatchExactly, roi_tree.COL_ROI)) == 1
|
assert (
|
||||||
|
len(roi_tree.tree.findItems("test_roi", Qt.MatchFlag.MatchExactly, roi_tree.COL_ROI)) == 1
|
||||||
|
)
|
||||||
|
|
||||||
# Remove ROI via controller and check that it's removed from the tree
|
# Remove ROI via controller and check that it's removed from the tree
|
||||||
image_widget.remove_roi(0)
|
image_widget.remove_roi(0)
|
||||||
assert roi not in roi_tree.roi_items
|
assert roi not in roi_tree.roi_items
|
||||||
assert len(roi_tree.tree.findItems("test_roi", Qt.MatchExactly, roi_tree.COL_ROI)) == 0
|
assert (
|
||||||
|
len(roi_tree.tree.findItems("test_roi", Qt.MatchFlag.MatchExactly, roi_tree.COL_ROI)) == 0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_expand_collapse_tree(roi_tree, image_widget):
|
def test_expand_collapse_tree(roi_tree, image_widget):
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ from bec_widgets.widgets.plots.roi.image_roi import (
|
|||||||
RectangularROI,
|
RectangularROI,
|
||||||
ROIController,
|
ROIController,
|
||||||
)
|
)
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
from tests.unit_tests.conftest import create_widget
|
from .client_mocks import mocked_client
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=["rect", "circle", "ellipse"])
|
@pytest.fixture(params=["rect", "circle", "ellipse"])
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ from bec_lib.endpoints import MessageEndpoints
|
|||||||
from qtpy.QtCore import QPointF
|
from qtpy.QtCore import QPointF
|
||||||
|
|
||||||
from bec_widgets.widgets.plots.image.image import Image
|
from bec_widgets.widgets.plots.image.image import Image
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
from tests.unit_tests.conftest import create_widget
|
from .client_mocks import mocked_client
|
||||||
|
from .conftest import create_widget
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# Image widget base functionality tests
|
# Image widget base functionality tests
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from qtpy.QtTest import QSignalSpy
|
from qtpy.QtTest import QSignalSpy
|
||||||
|
|
||||||
from bec_widgets.widgets.plots.motor_map.motor_map import MotorMap
|
from bec_widgets.widgets.plots.motor_map.motor_map import MotorMap
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
|
|
||||||
|
from .client_mocks import mocked_client
|
||||||
from .conftest import create_widget
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from bec_widgets.widgets.plots.multi_waveform.multi_waveform import MultiWaveform
|
from bec_widgets.widgets.plots.multi_waveform.multi_waveform import MultiWaveform
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
|
|
||||||
|
from .client_mocks import mocked_client
|
||||||
from .conftest import create_widget
|
from .conftest import create_widget
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from bec_widgets.utils.plugin_utils import get_custom_classes
|
import sys
|
||||||
|
|
||||||
|
from bec_widgets.utils.plugin_utils import get_custom_class_references, get_custom_classes
|
||||||
|
|
||||||
|
|
||||||
def test_client_generator_classes():
|
def test_client_generator_classes():
|
||||||
@@ -10,3 +12,13 @@ def test_client_generator_classes():
|
|||||||
assert "Waveform" in connector_cls_names
|
assert "Waveform" in connector_cls_names
|
||||||
assert "MotorMap" in plugins
|
assert "MotorMap" in plugins
|
||||||
assert "NonExisting" not in plugins
|
assert "NonExisting" not in plugins
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_custom_class_references_avoids_importing_widget_modules():
|
||||||
|
target_module = "bec_widgets.widgets.plots.image.image"
|
||||||
|
sys.modules.pop(target_module, None)
|
||||||
|
|
||||||
|
references = get_custom_class_references("bec_widgets", use_cache=False)
|
||||||
|
|
||||||
|
assert "Image" in [reference.name for reference in references]
|
||||||
|
assert target_module not in sys.modules
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from qtpy.QtCore import QEvent, QPoint, QPointF, Qt
|
|||||||
from qtpy.QtGui import QColor, QMouseEvent
|
from qtpy.QtGui import QColor, QMouseEvent
|
||||||
from qtpy.QtWidgets import QApplication
|
from qtpy.QtWidgets import QApplication
|
||||||
|
|
||||||
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 (
|
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import (
|
||||||
RingProgressBar,
|
RingProgressBar,
|
||||||
RingProgressContainerWidget,
|
RingProgressContainerWidget,
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import pytest
|
|||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
|
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
|
||||||
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_settings_cards import RingSettings
|
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_settings_cards import RingSettings
|
||||||
from tests.unit_tests.client_mocks import mocked_client
|
|
||||||
|
from .client_mocks import mocked_client
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import sys
|
||||||
|
from types import ModuleType
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_widget_handler import RPCWidgetHandler
|
from bec_widgets.cli.rpc.rpc_widget_handler import RPCWidgetHandler
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.plugin_utils import BECClassReference
|
||||||
from bec_widgets.utils.plugin_utils import BECClassContainer, BECClassInfo
|
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_widget_handler():
|
def test_rpc_widget_handler():
|
||||||
@@ -12,19 +13,38 @@ def test_rpc_widget_handler():
|
|||||||
assert "BECDockArea" in handler.widget_classes
|
assert "BECDockArea" in handler.widget_classes
|
||||||
|
|
||||||
|
|
||||||
class _TestPluginWidget(BECWidget): ...
|
def test_duplicate_plugins_not_allowed(monkeypatch):
|
||||||
|
builtin_module = ModuleType("builtin_test_widgets")
|
||||||
|
plugin_module = ModuleType("plugin_test_widgets")
|
||||||
|
|
||||||
|
SharedWidgetBuiltin = type("SharedWidget", (), {})
|
||||||
|
SharedWidgetBuiltin.__module__ = builtin_module.__name__
|
||||||
|
setattr(builtin_module, "SharedWidget", SharedWidgetBuiltin)
|
||||||
|
|
||||||
@patch(
|
SharedWidgetPlugin = type("SharedWidget", (), {})
|
||||||
"bec_widgets.cli.rpc.rpc_widget_handler.get_all_plugin_widgets",
|
SharedWidgetPlugin.__module__ = plugin_module.__name__
|
||||||
return_value=BECClassContainer(
|
setattr(plugin_module, "SharedWidget", SharedWidgetPlugin)
|
||||||
[
|
|
||||||
BECClassInfo(name="DeviceComboBox", obj=_TestPluginWidget, module="", file=""),
|
NewPluginWidget = type("NewPluginWidget", (), {})
|
||||||
BECClassInfo(name="NewPluginWidget", obj=_TestPluginWidget, module="", file=""),
|
NewPluginWidget.__module__ = plugin_module.__name__
|
||||||
]
|
setattr(plugin_module, "NewPluginWidget", NewPluginWidget)
|
||||||
),
|
|
||||||
)
|
monkeypatch.setitem(sys.modules, builtin_module.__name__, builtin_module)
|
||||||
def test_duplicate_plugins_not_allowed(_):
|
monkeypatch.setitem(sys.modules, plugin_module.__name__, plugin_module)
|
||||||
handler = RPCWidgetHandler()
|
|
||||||
assert handler.widget_classes["DeviceComboBox"] is not _TestPluginWidget
|
with (
|
||||||
assert handler.widget_classes["NewPluginWidget"] is _TestPluginWidget
|
patch(
|
||||||
|
"bec_widgets.cli.rpc.rpc_widget_handler.get_all_plugin_widget_references",
|
||||||
|
return_value=[
|
||||||
|
BECClassReference(name="SharedWidget", module=plugin_module.__name__),
|
||||||
|
BECClassReference(name="NewPluginWidget", module=plugin_module.__name__),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"bec_widgets.cli.rpc.rpc_widget_handler.get_custom_class_references",
|
||||||
|
return_value=[BECClassReference(name="SharedWidget", module=builtin_module.__name__)],
|
||||||
|
),
|
||||||
|
):
|
||||||
|
handler = RPCWidgetHandler()
|
||||||
|
assert handler.widget_classes["SharedWidget"].__module__ == builtin_module.__name__
|
||||||
|
assert handler.widget_classes["NewPluginWidget"].__module__ == plugin_module.__name__
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from qtpy.QtCore import QModelIndex, Qt
|
|||||||
|
|
||||||
from bec_widgets.utils.forms_from_types.items import StrFormItem
|
from bec_widgets.utils.forms_from_types.items import StrFormItem
|
||||||
from bec_widgets.utils.widget_io import WidgetIO
|
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
|
from .client_mocks import mocked_client
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,13 @@ from pytestqt import qtbot
|
|||||||
from qtpy import QtCore
|
from qtpy import QtCore
|
||||||
|
|
||||||
from bec_widgets.utils.colors import get_accent_colors
|
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,
|
ScanHistoryDeviceViewer,
|
||||||
|
)
|
||||||
|
from bec_widgets.widgets.services.scan_history_browser.components.scan_history_metadata_viewer import (
|
||||||
ScanHistoryMetadataViewer,
|
ScanHistoryMetadataViewer,
|
||||||
|
)
|
||||||
|
from bec_widgets.widgets.services.scan_history_browser.components.scan_history_view import (
|
||||||
ScanHistoryView,
|
ScanHistoryView,
|
||||||
)
|
)
|
||||||
from bec_widgets.widgets.services.scan_history_browser.scan_history_browser import (
|
from bec_widgets.widgets.services.scan_history_browser.scan_history_browser import (
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterW
|
|||||||
from bec_widgets.widgets.plots.scatter_waveform.settings.scatter_curve_setting import (
|
from bec_widgets.widgets.plots.scatter_waveform.settings.scatter_curve_setting import (
|
||||||
ScatterCurveSettings,
|
ScatterCurveSettings,
|
||||||
)
|
)
|
||||||
from tests.unit_tests.client_mocks import create_dummy_scan_item, mocked_client
|
|
||||||
|
|
||||||
|
from .client_mocks import create_dummy_scan_item, mocked_client
|
||||||
from .conftest import create_widget
|
from .conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
|||||||
from bec_widgets.widgets.services.scan_history_browser.scan_history_browser import (
|
from bec_widgets.widgets.services.scan_history_browser.scan_history_browser import (
|
||||||
ScanHistoryBrowser,
|
ScanHistoryBrowser,
|
||||||
)
|
)
|
||||||
from tests.unit_tests.client_mocks import (
|
|
||||||
|
from .client_mocks import (
|
||||||
DummyData,
|
DummyData,
|
||||||
create_dummy_scan_item,
|
create_dummy_scan_item,
|
||||||
dap_plugin_message,
|
dap_plugin_message,
|
||||||
@@ -26,7 +27,6 @@ from tests.unit_tests.client_mocks import (
|
|||||||
mocked_client,
|
mocked_client,
|
||||||
mocked_client_with_dap,
|
mocked_client_with_dap,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .conftest import create_widget
|
from .conftest import create_widget
|
||||||
|
|
||||||
# pylint: disable=unexpected-keyword-arg
|
# pylint: disable=unexpected-keyword-arg
|
||||||
|
|||||||
Reference in New Issue
Block a user