HydraDeck / hydradeck /utils.py
OpeneR
HydraDeck open-source clean snapshot
778278c
Raw
History Blame Contribute Delete
2.49 kB
from __future__ import annotations
import datetime
import sys
import threading
import time
def log(enabled: bool, msg: str) -> None:
if not enabled:
return
ts = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds")
print(f"[{ts}] {msg}")
JSON = dict[str, object]
class Heartbeat:
def __init__(self, enabled: bool, label: str, interval_s: float = 5.0) -> None:
self._enabled = enabled
self._label = label
self._interval_s = interval_s
self._stop = threading.Event()
self._t: threading.Thread | None = None
def __enter__(self) -> Heartbeat:
if not self._enabled:
return self
def run() -> None:
start = time.time()
while not self._stop.wait(self._interval_s):
elapsed = int(time.time() - start)
sys.stderr.write(f"[heartbeat] {self._label} ({elapsed}s)\n")
sys.stderr.flush()
self._t = threading.Thread(target=run, daemon=True)
self._t.start()
return self
def __exit__(self, exc_type, exc, tb) -> None:
_ = (exc_type, exc, tb)
if not self._enabled:
return
self._stop.set()
if self._t is not None:
self._t.join(timeout=1.0)
class Progress:
def __init__(
self,
enabled: bool,
total: int,
label: str = "",
stream=None,
) -> None:
self._enabled = enabled
self._total = max(int(total), 1)
self._label = label
self._stream = stream or sys.stderr
self._current = 0
self._last_len = 0
def update(self, step: str, inc: int = 1) -> None:
if not self._enabled:
return
self._current = min(self._total, self._current + max(int(inc), 0))
pct = int((self._current / self._total) * 100)
bar_len = 24
filled = int(bar_len * self._current / self._total)
bar = "#" * filled + "-" * (bar_len - filled)
msg = f"[progress] {self._label} [{bar}] {pct:3d}% {step}"
pad = " " * max(0, self._last_len - len(msg))
self._stream.write("\r" + msg + pad)
self._stream.flush()
self._last_len = len(msg)
def done(self, step: str = "done") -> None:
if not self._enabled:
return
self._current = self._total
self.update(step, inc=0)
self._stream.write("\n")
self._stream.flush()