Skip to content

Commit bafc67e

Browse files
committed
fix: issues from rebase
1 parent fd01f74 commit bafc67e

9 files changed

Lines changed: 488 additions & 160 deletions

File tree

bec_lib/bec_lib/config_helper.py

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@
2929
from bec_lib.endpoints import MessageEndpoints
3030
from bec_lib.file_utils import DeviceConfigWriter
3131
from bec_lib.logger import bec_logger
32-
from bec_lib.messages import ConfigAction
32+
from bec_lib.messages import ConfigAction, sanitize_one_way_encodable
3333
from bec_lib.utils.import_utils import lazy_import_from
3434
from bec_lib.utils.json_extended import ExtendedEncoder
3535

3636
if TYPE_CHECKING: # pragma: no cover
3737
from bec_lib.devicemanager import DeviceManagerBase
38-
from bec_lib.messages import DeviceConfigMessage, RequestResponseMessage, ServiceResponseMessage
38+
from bec_lib.messages import (
39+
DeviceConfigMessage,
40+
RequestResponseMessage,
41+
ServiceResponseMessage,
42+
)
3943
from bec_lib.redis_connector import RedisConnector
4044

4145
else:
@@ -74,7 +78,11 @@ def __init__(self, device_manager: DeviceManagerBase) -> None:
7478
self._config_helper = device_manager.config_helper
7579

7680
def update_session_with_file(
77-
self, file_path: str, save_recovery: bool = True, force: bool = False, validate: bool = True
81+
self,
82+
file_path: str,
83+
save_recovery: bool = True,
84+
force: bool = False,
85+
validate: bool = True,
7886
) -> None:
7987
"""Update the current session with a yaml file from disk.
8088
@@ -96,15 +104,19 @@ def save_current_session(self, file_path: str):
96104
"""
97105
self._config_helper.save_current_session(file_path)
98106

99-
def reset_config(self, wait_for_response: bool = True, timeout_s: float | None = None) -> None:
107+
def reset_config(
108+
self, wait_for_response: bool = True, timeout_s: float | None = None
109+
) -> None:
100110
"""
101111
Send a request to reset config to default
102112
Args:
103113
wait_for_response (bool): whether to wait for the response, default True
104114
timeout_s (float, optional): how long to wait for a response. Ignored if not waiting. Defaults to best effort calculated value based on message length.
105115
Returns: None
106116
"""
107-
self._config_helper.reset_config(wait_for_response=wait_for_response, timeout_s=timeout_s)
117+
self._config_helper.reset_config(
118+
wait_for_response=wait_for_response, timeout_s=timeout_s
119+
)
108120

109121
def load_demo_config(self, force: bool = False) -> None:
110122
"""
@@ -139,7 +151,11 @@ def __init__(
139151
self._device_manager = device_manager
140152

141153
def update_session_with_file(
142-
self, file_path: str, save_recovery: bool = True, force: bool = False, validate: bool = True
154+
self,
155+
file_path: str,
156+
save_recovery: bool = True,
157+
force: bool = False,
158+
validate: bool = True,
143159
) -> None:
144160
"""Update the current session with a yaml file from disk.
145161
@@ -167,7 +183,9 @@ def update_session_with_file(
167183

168184
if not os.path.exists(self._base_path_recovery):
169185
self._writer_mixin.create_directory(self._base_path_recovery)
170-
fname = os.path.join(self._base_path_recovery, f"recovery_config_{time_stamp}.yaml")
186+
fname = os.path.join(
187+
self._base_path_recovery, f"recovery_config_{time_stamp}.yaml"
188+
)
171189
success = self._save_config_to_file(fname, raise_on_error=False)
172190
if success:
173191
print(f"A recovery config was written to {fname}.")
@@ -259,7 +277,9 @@ def _get_config_conflicts(self, new_config: dict, validate: bool = True) -> dict
259277
for sub_element in all_config_keys:
260278
sub_value = value.get(sub_element, None)
261279
current_sub_value = (
262-
current_value.get(sub_element, None) if current_value else None
280+
current_value.get(sub_element, None)
281+
if current_value
282+
else None
263283
)
264284
if sub_value != current_sub_value:
265285
nested_conflicts[sub_element] = {
@@ -414,12 +434,16 @@ def _resolve_single_conflict(
414434

415435
if choice.lower() == "a":
416436
# Accept new value
417-
self._apply_config_value(config, device_name, element, sub_element, new_value)
437+
self._apply_config_value(
438+
config, device_name, element, sub_element, new_value
439+
)
418440
console.print(" [green]→ Accepted new value[/green]")
419441
elif choice.lower() == "k":
420442
# Keep current value - do nothing to config since we're loading from file
421443
# We need to update config dict to keep current value
422-
self._apply_config_value(config, device_name, element, sub_element, current_value)
444+
self._apply_config_value(
445+
config, device_name, element, sub_element, current_value
446+
)
423447
console.print(" [yellow]→ Kept current value[/yellow]")
424448
elif choice.lower() == "m":
425449
# Manual merge - prompt for custom value
@@ -434,7 +458,9 @@ def _resolve_single_conflict(
434458
except (ValueError, SyntaxError):
435459
# If evaluation fails, treat as string
436460
custom_value = custom_input
437-
self._apply_config_value(config, device_name, element, sub_element, custom_value)
461+
self._apply_config_value(
462+
config, device_name, element, sub_element, custom_value
463+
)
438464
console.print(f" [blue]→ Applied custom value: {custom_value}[/blue]")
439465

440466
def _format_value_for_display(self, value) -> str:
@@ -458,7 +484,12 @@ def _format_value_for_display(self, value) -> str:
458484
return str(value)
459485

460486
def _apply_config_value(
461-
self, config: dict, device_name: str, element: str, sub_element: str | None, value
487+
self,
488+
config: dict,
489+
device_name: str,
490+
element: str,
491+
sub_element: str | None,
492+
value,
462493
) -> None:
463494
"""
464495
Apply a resolved value to the config dict.
@@ -501,7 +532,11 @@ def _apply_all_current_values(self, config: dict, conflicts: dict) -> None:
501532
# This is a nested conflict (like deviceConfig)
502533
for sub_element, sub_conflict in conflict_data.items():
503534
self._apply_config_value(
504-
config, device_name, element, sub_element, sub_conflict["current"]
535+
config,
536+
device_name,
537+
element,
538+
sub_element,
539+
sub_conflict["current"],
505540
)
506541

507542
def _is_nested_conflict(self, conflict_data: dict) -> bool:
@@ -515,7 +550,8 @@ def _is_nested_conflict(self, conflict_data: dict) -> bool:
515550
bool: True if nested conflict, False otherwise.
516551
"""
517552
return isinstance(conflict_data, dict) and all(
518-
isinstance(v, dict) and "new" in v and "current" in v for v in conflict_data.values()
553+
isinstance(v, dict) and "new" in v and "current" in v
554+
for v in conflict_data.values()
519555
)
520556

521557
def _save_config_to_file(self, file_path: str, raise_on_error: bool = True) -> bool:
@@ -617,14 +653,22 @@ def send_config_request(
617653
request_id = str(uuid.uuid4())
618654
self._connector.send(
619655
MessageEndpoints.device_config_request(),
620-
DeviceConfigMessage(action=action, config=config, metadata={"RID": request_id}),
656+
DeviceConfigMessage(
657+
action=action,
658+
config=sanitize_one_way_encodable(config),
659+
metadata={"RID": request_id},
660+
),
621661
)
622662

623663
if wait_for_response:
624-
timeout = timeout_s if timeout_s is not None else self.suggested_timeout_s(config)
664+
timeout = (
665+
timeout_s if timeout_s is not None else self.suggested_timeout_s(config)
666+
)
625667
logger.info(f"Waiting for reply with timeout {timeout} s")
626668
reply = self.wait_for_config_reply(
627-
request_id, timeout=timeout, send_cancel_on_interrupt=(action != "cancel")
669+
request_id,
670+
timeout=timeout,
671+
send_cancel_on_interrupt=(action != "cancel"),
628672
)
629673
if action == "cancel":
630674
raise DeviceConfigError(
@@ -633,7 +677,9 @@ def send_config_request(
633677
self.handle_update_reply(reply, request_id, timeout)
634678
return request_id
635679

636-
def reset_config(self, wait_for_response: bool = True, timeout_s: float | None = None) -> None:
680+
def reset_config(
681+
self, wait_for_response: bool = True, timeout_s: float | None = None
682+
) -> None:
637683
"""
638684
Send a request to reset config to default
639685
Args:
@@ -657,7 +703,9 @@ def reset_config(self, wait_for_response: bool = True, timeout_s: float | None =
657703
def suggested_timeout_s(config: dict):
658704
return min(300, len(config) * 30) + 2
659705

660-
def handle_update_reply(self, reply: RequestResponseMessage, RID: str, timeout: float):
706+
def handle_update_reply(
707+
self, reply: RequestResponseMessage, RID: str, timeout: float
708+
):
661709
if not reply.content["accepted"] and not reply.metadata.get("updated_config"):
662710
raise DeviceConfigError(
663711
f"Failed to update the config: {reply.content['message']}. No devices were updated."
@@ -695,7 +743,9 @@ def wait_for_service_response(self, RID: str, timeout: float = 60) -> None:
695743
start_time = time.monotonic()
696744
while True:
697745
elapsed_time = time.monotonic() - start_time
698-
service_messages = self._connector.lrange(MessageEndpoints.service_response(RID), 0, -1)
746+
service_messages = self._connector.lrange(
747+
MessageEndpoints.service_response(RID), 0, -1
748+
)
699749
if not service_messages:
700750
time.sleep(0.005)
701751
else:
@@ -738,11 +788,15 @@ def wait_for_config_reply(
738788
start = time.monotonic()
739789
while True:
740790
elapsed_time = time.monotonic() - start
741-
msg = self._connector.get(MessageEndpoints.device_config_request_response(RID))
791+
msg = self._connector.get(
792+
MessageEndpoints.device_config_request_response(RID)
793+
)
742794
if msg is None:
743795
time.sleep(0.01)
744796
if elapsed_time > timeout:
745-
raise DeviceConfigError("Timeout reached whilst waiting for config reply.")
797+
raise DeviceConfigError(
798+
"Timeout reached whilst waiting for config reply."
799+
)
746800
continue
747801
return msg
748802
except KeyboardInterrupt:
@@ -759,6 +813,8 @@ def load_demo_config(self, force: bool = False) -> None:
759813
force (bool, optional): Force update even if there are conflicts. Defaults to False.
760814
Returns: None
761815
"""
762-
dir_path = os.path.abspath(os.path.join(os.path.dirname(bec_lib.__file__), "./configs/"))
816+
dir_path = os.path.abspath(
817+
os.path.join(os.path.dirname(bec_lib.__file__), "./configs/")
818+
)
763819
fpath = os.path.join(dir_path, "demo_config.yaml")
764820
self.update_session_with_file(fpath, force=force)

0 commit comments

Comments
 (0)