Coverage for src / lstautorta / shared_observation.py: 30%
54 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 11:56 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 11:56 +0000
1import json
2import logging
3import os
4import tempfile
5import time
6from typing import NamedTuple
8DEFAULT_SHARED_OBS_PATH = "/fefs/onsite/pipeline/rta/data/current_obs.json"
11class SharedObsInfo(NamedTuple):
12 obs_id: int | None
13 time_start_camera: float | None
14 RA: float | None
15 DEC: float | None
16 source_RA: float | None
17 source_DEC: float | None
18 updated_ts: float | None
21def write_shared_obs(path: str, obs_info) -> None:
22 payload = {
23 "obs_id": obs_info.obs_id,
24 "time_start_camera": obs_info.time_start_camera,
25 "ra": obs_info.RA,
26 "dec": obs_info.DEC,
27 "source_ra": obs_info.source_RA,
28 "source_dec": obs_info.source_DEC,
29 "updated_ts": time.time(),
30 }
31 parent_dir = os.path.dirname(path)
32 os.makedirs(parent_dir, exist_ok=True)
33 fd, tmp_path = tempfile.mkstemp(dir=parent_dir, prefix=".current_obs_", suffix=".json")
34 try:
35 with os.fdopen(fd, "w") as f:
36 json.dump(payload, f)
37 f.flush()
38 os.fsync(f.fileno())
39 os.replace(tmp_path, path)
40 finally:
41 if os.path.exists(tmp_path):
42 os.unlink(tmp_path)
45def _parse_shared_obs(data: dict) -> SharedObsInfo | None:
46 if not isinstance(data, dict):
47 return None
48 obs_id = data.get("obs_id")
49 return SharedObsInfo(
50 obs_id=obs_id,
51 time_start_camera=data.get("time_start_camera"),
52 RA=data.get("ra"),
53 DEC=data.get("dec"),
54 source_RA=data.get("source_ra"),
55 source_DEC=data.get("source_dec"),
56 updated_ts=data.get("updated_ts"),
57 )
60def read_shared_obs(path: str) -> SharedObsInfo | None:
61 if not os.path.exists(path):
62 return None
63 try:
64 with open(path) as f:
65 data = json.load(f)
66 except json.JSONDecodeError:
67 return None
68 except OSError as e:
69 logging.exception("Failed to read shared observation file %s: %s", path, e)
70 return None
71 return _parse_shared_obs(data)
74def wait_for_shared_obs(
75 path: str,
76 poll_s: int = 5,
77 timeout_s: int = 12 * 3600,
78) -> SharedObsInfo:
79 start_time = time.time()
81 while True:
82 obs_info = read_shared_obs(path)
83 if obs_info is not None and obs_info.obs_id is not None:
84 return obs_info
86 if time.time() - start_time > timeout_s:
87 raise TimeoutError(f"No shared observation available in {path} after {timeout_s} seconds")
89 time.sleep(poll_s)