mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-06-07 05:48:40 +02:00
fix: sanitize name space util for bec connector and ads
This commit is contained in:
@@ -16,6 +16,7 @@ from qtpy.QtWidgets import QApplication
|
|||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
||||||
from bec_widgets.utils.error_popups import ErrorPopupUtility, SafeSlot
|
from bec_widgets.utils.error_popups import ErrorPopupUtility, SafeSlot
|
||||||
|
from bec_widgets.utils.name_utils import sanitize_namespace
|
||||||
from bec_widgets.utils.widget_io import WidgetHierarchy
|
from bec_widgets.utils.widget_io import WidgetHierarchy
|
||||||
from bec_widgets.utils.yaml_dialog import load_yaml, load_yaml_gui, save_yaml, save_yaml_gui
|
from bec_widgets.utils.yaml_dialog import load_yaml, load_yaml_gui, save_yaml, save_yaml_gui
|
||||||
|
|
||||||
@@ -102,6 +103,8 @@ class BECConnector:
|
|||||||
"""
|
"""
|
||||||
# Extract object_name from kwargs to not pass it to Qt class
|
# Extract object_name from kwargs to not pass it to Qt class
|
||||||
object_name = object_name or kwargs.pop("objectName", None)
|
object_name = object_name or kwargs.pop("objectName", None)
|
||||||
|
if object_name is not None:
|
||||||
|
object_name = sanitize_namespace(object_name)
|
||||||
# Ensure the parent is always the first argument for QObject
|
# Ensure the parent is always the first argument for QObject
|
||||||
parent = kwargs.pop("parent", None)
|
parent = kwargs.pop("parent", None)
|
||||||
# This initializes the QObject or any qt related class BECConnector has to be used from this line down with QObject, otherwise hierarchy logic will not work
|
# This initializes the QObject or any qt related class BECConnector has to be used from this line down with QObject, otherwise hierarchy logic will not work
|
||||||
|
|||||||
@@ -14,3 +14,22 @@ def pascal_to_snake(name: str) -> str:
|
|||||||
s1 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
|
s1 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
|
||||||
s2 = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", s1)
|
s2 = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", s1)
|
||||||
return s2.lower()
|
return s2.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_namespace(namespace: str | None) -> str | None:
|
||||||
|
"""
|
||||||
|
Clean user-provided namespace labels for filesystem compatibility.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
namespace (str | None): Arbitrary namespace identifier supplied by the caller.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: Sanitized namespace containing only safe characters, or ``None``
|
||||||
|
when the input is empty.
|
||||||
|
"""
|
||||||
|
if not namespace:
|
||||||
|
return None
|
||||||
|
ns = namespace.strip()
|
||||||
|
if not ns:
|
||||||
|
return None
|
||||||
|
return re.sub(r"[^0-9A-Za-z._-]+", "_", ns)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from bec_widgets import BECWidget, SafeProperty, SafeSlot
|
|||||||
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 import BECDispatcher
|
||||||
from bec_widgets.utils.colors import apply_theme
|
from bec_widgets.utils.colors import apply_theme
|
||||||
|
from bec_widgets.utils.name_utils import sanitize_namespace
|
||||||
from bec_widgets.utils.toolbars.actions import (
|
from bec_widgets.utils.toolbars.actions import (
|
||||||
ExpandableMenuAction,
|
ExpandableMenuAction,
|
||||||
MaterialIconAction,
|
MaterialIconAction,
|
||||||
@@ -48,7 +49,6 @@ from bec_widgets.widgets.containers.advanced_dock_area.profile_utils import (
|
|||||||
profile_origin_display,
|
profile_origin_display,
|
||||||
read_manifest,
|
read_manifest,
|
||||||
restore_user_from_default,
|
restore_user_from_default,
|
||||||
sanitize_namespace,
|
|
||||||
set_last_profile,
|
set_last_profile,
|
||||||
set_quick_select,
|
set_quick_select,
|
||||||
user_profile_candidates,
|
user_profile_candidates,
|
||||||
@@ -277,6 +277,7 @@ class AdvancedDockArea(DockAreaWidget):
|
|||||||
title_buttons: Mapping[str, bool] | Sequence[str] | str | None = None,
|
title_buttons: Mapping[str, bool] | Sequence[str] | str | None = None,
|
||||||
show_settings_action: bool | None = None,
|
show_settings_action: bool | None = None,
|
||||||
promote_central: bool = False,
|
promote_central: bool = False,
|
||||||
|
object_name: str | None = None,
|
||||||
**widget_kwargs,
|
**widget_kwargs,
|
||||||
) -> QWidget | CDockWidget | BECWidget:
|
) -> QWidget | CDockWidget | BECWidget:
|
||||||
"""
|
"""
|
||||||
@@ -301,6 +302,7 @@ class AdvancedDockArea(DockAreaWidget):
|
|||||||
title_buttons=title_buttons,
|
title_buttons=title_buttons,
|
||||||
show_settings_action=show_settings_action,
|
show_settings_action=show_settings_action,
|
||||||
promote_central=promote_central,
|
promote_central=promote_central,
|
||||||
|
object_name=object_name,
|
||||||
**widget_kwargs,
|
**widget_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1227,6 +1227,7 @@ class DockAreaWidget(BECWidget, QWidget):
|
|||||||
promote_central: bool = False,
|
promote_central: bool = False,
|
||||||
dock_icon: QIcon | None = None,
|
dock_icon: QIcon | None = None,
|
||||||
apply_widget_icon: bool = True,
|
apply_widget_icon: bool = True,
|
||||||
|
object_name: str | None = None,
|
||||||
**widget_kwargs,
|
**widget_kwargs,
|
||||||
) -> QWidget | CDockWidget | BECWidget:
|
) -> QWidget | CDockWidget | BECWidget:
|
||||||
"""
|
"""
|
||||||
@@ -1262,6 +1263,9 @@ class DockAreaWidget(BECWidget, QWidget):
|
|||||||
the widget's ``ICON_NAME`` attribute is used when available.
|
the widget's ``ICON_NAME`` attribute is used when available.
|
||||||
apply_widget_icon(bool): When False, skip automatically resolving the icon from
|
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).
|
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:
|
Returns:
|
||||||
The widget instance by default, or the created `CDockWidget` when `return_dock` is True.
|
The widget instance by default, or the created `CDockWidget` when `return_dock` is True.
|
||||||
@@ -1273,7 +1277,9 @@ class DockAreaWidget(BECWidget, QWidget):
|
|||||||
)
|
)
|
||||||
widget = cast(
|
widget = cast(
|
||||||
BECWidget,
|
BECWidget,
|
||||||
widget_handler.create_widget(widget_type=widget, parent=self, **widget_kwargs),
|
widget_handler.create_widget(
|
||||||
|
widget_type=widget, parent=self, object_name=object_name, **widget_kwargs
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
spec = self._build_creation_spec(
|
spec = self._build_creation_spec(
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from qtpy.QtCore import QByteArray, QDateTime, QSettings, Qt
|
|||||||
from qtpy.QtGui import QPixmap
|
from qtpy.QtGui import QPixmap
|
||||||
from qtpy.QtWidgets import QApplication
|
from qtpy.QtWidgets import QApplication
|
||||||
|
|
||||||
|
from bec_widgets.utils.name_utils import sanitize_namespace
|
||||||
from bec_widgets.widgets.containers.qt_ads import CDockWidget
|
from bec_widgets.widgets.containers.qt_ads import CDockWidget
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
@@ -124,25 +125,6 @@ def _settings_profiles_root() -> str:
|
|||||||
return root
|
return root
|
||||||
|
|
||||||
|
|
||||||
def sanitize_namespace(namespace: str | None) -> str | None:
|
|
||||||
"""
|
|
||||||
Clean user-provided namespace labels for filesystem compatibility.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
namespace (str | None): Arbitrary namespace identifier supplied by the caller.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str | None: Sanitized namespace containing only safe characters, or ``None``
|
|
||||||
when the input is empty.
|
|
||||||
"""
|
|
||||||
if not namespace:
|
|
||||||
return None
|
|
||||||
ns = namespace.strip()
|
|
||||||
if not ns:
|
|
||||||
return None
|
|
||||||
return re.sub(r"[^0-9A-Za-z._-]+", "_", ns)
|
|
||||||
|
|
||||||
|
|
||||||
def _profiles_dir(segment: str, namespace: str | None) -> str:
|
def _profiles_dir(segment: str, namespace: str | None) -> str:
|
||||||
"""
|
"""
|
||||||
Build (and ensure) the directory that holds profiles for a namespace segment.
|
Build (and ensure) the directory that holds profiles for a namespace segment.
|
||||||
|
|||||||
Reference in New Issue
Block a user