From 0d17d1e4b304649005a2765065b45f2d7e48588d Mon Sep 17 00:00:00 2001 From: Victor Morand Date: Sat, 25 Apr 2026 16:23:22 +0200 Subject: [PATCH 1/2] fix: properly pass xp id, run id for service serialization --- src/experimaestro/scheduler/interfaces.py | 4 ++++ src/experimaestro/scheduler/services.py | 4 ++++ src/experimaestro/scheduler/state_provider.py | 7 ++++++- src/experimaestro/tests/test_remote_state.py | 4 ++++ src/experimaestro/tui/widgets/global_services.py | 10 ++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/experimaestro/scheduler/interfaces.py b/src/experimaestro/scheduler/interfaces.py index cd0e5dd4..02dc4e6f 100644 --- a/src/experimaestro/scheduler/interfaces.py +++ b/src/experimaestro/scheduler/interfaces.py @@ -1990,6 +1990,10 @@ def full_state_dict(self) -> Dict[str, Any]: "description": self.description(), "class": f"{self.__class__.__module__}.{self.__class__.__name__}", "state_dict": self.state_dict(), + "experiment_id": self.experiment_id, + "run_id": self.run_id, + "state": self.state.name if hasattr(self.state, "name") else str(self.state), + "url": getattr(self, "url", None), } def to_service(self) -> "BaseService": diff --git a/src/experimaestro/scheduler/services.py b/src/experimaestro/scheduler/services.py index 3e474528..a0ad2514 100644 --- a/src/experimaestro/scheduler/services.py +++ b/src/experimaestro/scheduler/services.py @@ -132,6 +132,10 @@ def full_state_dict(self) -> dict: "description": self.description(), "class": f"{self.__class__.__module__}.{self.__class__.__name__}", "state_dict": self.serialize_state_dict(self.state_dict()), + "experiment_id": self.experiment_id, + "run_id": self.run_id, + "state": self.state.name if hasattr(self.state, "name") else str(self.state), + "url": getattr(self, "url", None), } @staticmethod diff --git a/src/experimaestro/scheduler/state_provider.py b/src/experimaestro/scheduler/state_provider.py index a4a8784b..73afb63b 100644 --- a/src/experimaestro/scheduler/state_provider.py +++ b/src/experimaestro/scheduler/state_provider.py @@ -2025,6 +2025,10 @@ def full_state_dict(self) -> dict: "description": self._description, "class": self._service_class, "state_dict": self._state_dict_data, + "experiment_id": self.experiment_id, + "run_id": self.run_id, + "state": self.state.name if hasattr(self.state, "name") else str(self.state), + "url": self.url, } @property @@ -2040,7 +2044,7 @@ def from_full_state_dict(cls, d: Dict) -> "MockService": d: Dictionary from full_state_dict() Returns: - MockService instance (state is always MOCK, not from dict) + MockService instance """ return cls( service_id=d["service_id"], @@ -2050,6 +2054,7 @@ def from_full_state_dict(cls, d: Dict) -> "MockService": experiment_id=d.get("experiment_id"), run_id=d.get("run_id"), url=d.get("url"), + state=d.get("state"), ) def to_service(self) -> "BaseService": diff --git a/src/experimaestro/tests/test_remote_state.py b/src/experimaestro/tests/test_remote_state.py index 1af6895c..3516220a 100644 --- a/src/experimaestro/tests/test_remote_state.py +++ b/src/experimaestro/tests/test_remote_state.py @@ -273,6 +273,10 @@ def test_serialize_mock_service(self): # Preserves original service class, not MockService's class name assert result["class"] == "mymodule.MyService" assert result["state_dict"] == {"port": 8080} + assert result["experiment_id"] == "exp1" + assert result["run_id"] == "run1" + assert result["url"] == "http://localhost:8080" + assert result["state"] == "STOPPED" def test_serialize_mock_service_no_class(self): """Test serializing a MockService with service_class=None""" diff --git a/src/experimaestro/tui/widgets/global_services.py b/src/experimaestro/tui/widgets/global_services.py index 441b9df5..8e29403c 100644 --- a/src/experimaestro/tui/widgets/global_services.py +++ b/src/experimaestro/tui/widgets/global_services.py @@ -68,6 +68,12 @@ def _load_services(self) -> None: try: all_services = self.state_provider.get_services() + for s in all_services: + self.log.info( + f"DEBUG: raw_service id={getattr(s, 'id', 'N/A')} " + f"exp_id={getattr(s, 'experiment_id', 'N/A')} " + f"run_id={getattr(s, 'run_id', 'N/A')}" + ) running_services = [ s for s in all_services @@ -157,6 +163,10 @@ def _on_services_loaded(self, running_services: list) -> None: state_icon = state_icons.get(state_name, "?") service_key = f"{exp_id}:{run_id}:{service_id}" + self.log.info( + f"DEBUG: service_key='{service_key}' (exp_id='{exp_id}', " + f"run_id='{run_id}', service_id='{service_id}')" + ) table.add_row( exp_display, description or service_id, From 8d0e401bd158756d1c10ab29bb1fcff68c630373 Mon Sep 17 00:00:00 2001 From: Victor Morand Date: Sat, 25 Apr 2026 19:59:48 +0200 Subject: [PATCH 2/2] fix: enable disable kwarg for xpm tqdm --- src/experimaestro/notifications.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/experimaestro/notifications.py b/src/experimaestro/notifications.py index 25d64d46..798bbf1b 100644 --- a/src/experimaestro/notifications.py +++ b/src/experimaestro/notifications.py @@ -191,7 +191,8 @@ def __init__(self, iterable=None, file=None, *args, **kwargs): _file = file or sys.stderr self.is_tty = hasattr(_file, "isatty") or _file.isatty() - super().__init__(iterable, disable=False, file=file, *args, **kwargs) + kwargs.setdefault("disable", False) + super().__init__(iterable, file=file, *args, **kwargs) progress(0.0, level=self.pos, desc=kwargs.get("desc", None), console=False) def update(self, n=1):