From 3dfed232efb8baff14ebe62b6b14e62e0a4acd36 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Fri, 12 Jun 2026 15:14:48 +0200 Subject: [PATCH] fix(pydantic): adoption to new ScanArgument refactor from bec --- bec_widgets/cli/client.py | 2 +- .../pydantic_model_info_adapter.py | 4 ++++ tests/unit_tests/test_generated_form_form.py | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py index b08bef18..539158c9 100644 --- a/bec_widgets/cli/client.py +++ b/bec_widgets/cli/client.py @@ -738,7 +738,7 @@ class BeamlineStateManager(RPCBase): @rpc_call def state_summary(self) -> "dict[str, dict[str, str]]": """ - Return the displayed beamline states with their current status and label. + Return all beamline states (including filtered ones) with their current status and label. Returns: dict: Mapping of state name to a dictionary with ``status`` and ``label`` keys. diff --git a/bec_widgets/utils/forms_from_types/pydantic_model_info_adapter.py b/bec_widgets/utils/forms_from_types/pydantic_model_info_adapter.py index 90485e35..f998abe9 100644 --- a/bec_widgets/utils/forms_from_types/pydantic_model_info_adapter.py +++ b/bec_widgets/utils/forms_from_types/pydantic_model_info_adapter.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Mapping from typing import Any +from bec_lib.scan_args import ScanArgument from pydantic import BaseModel from pydantic_core import PydanticUndefined @@ -17,6 +18,9 @@ def pydantic_model_input_configs(model: type[BaseModel]) -> list[dict[str, Any]] for name, info in model.model_fields.items(): metadata: dict[str, Any] = {} for entry in info.metadata: + if isinstance(entry, ScanArgument): + metadata.update(entry.model_dump(exclude_none=True)) + continue for key in NUMERIC_BOUND_KEYS: value = getattr(entry, key, None) if value is not None: diff --git a/tests/unit_tests/test_generated_form_form.py b/tests/unit_tests/test_generated_form_form.py index d639ac6c..5017d243 100644 --- a/tests/unit_tests/test_generated_form_form.py +++ b/tests/unit_tests/test_generated_form_form.py @@ -214,6 +214,28 @@ def test_pydantic_widget_form_plain_field_has_generated_label_and_no_tooltip(qtb assert form.field_widget("sample_name").toolTip() == "" +def test_pydantic_model_input_configs_reads_bl_states_annotated_scan_arguments(): + """Contract test: ScanArgument metadata attached via ``Annotated`` in bec_lib's beamline + state configs must reach the generated-form configuration.""" + from bec_lib import bl_states + + from bec_widgets.utils.forms_from_types.pydantic_model_info_adapter import ( + pydantic_model_input_configs, + ) + + items = { + item["name"]: item + for item in pydantic_model_input_configs(bl_states.DeviceWithinLimitsState.CONFIG_CLASS) + } + + assert items["name"]["display_name"] == "State name" + assert items["name"]["tooltip"] + assert items["device"]["display_name"] == "Device" + assert items["low_limit"]["reference_units"] == "device" + assert items["high_limit"]["reference_units"] == "device" + assert items["tolerance"]["reference_units"] == "device" + + def test_pydantic_widget_form_uses_scan_argument_metadata(qtbot, mocked_client): form = PydanticWidgetForm(GeneratedScanArgumentSchema, client=mocked_client) qtbot.addWidget(form)