| from __future__ import annotations |
| import time |
|
|
| class ETA: |
| def __init__(self, total: int, smoothing: float = 0.95): |
| self.total = max(1, total) |
| self.smoothing = smoothing |
| self.start = time.time() |
| self.last = self.start |
| self.avg = None |
| self.n = 0 |
|
|
| def step(self, count: int = 1): |
| now = time.time() |
| dt = (now - self.last) / max(1, count) |
| self.last = now |
| self.n += count |
| if self.avg is None: |
| self.avg = dt |
| else: |
| self.avg = self.smoothing * self.avg + (1 - self.smoothing) * dt |
|
|
| def eta_seconds(self) -> float: |
| rem = max(0, self.total - self.n) |
| return rem * (self.avg or 0.0) |
|
|
| @staticmethod |
| def fmt(seconds: float) -> str: |
| seconds = int(seconds) |
| h = seconds // 3600 |
| m = (seconds % 3600) // 60 |
| s = seconds % 60 |
| if h > 0: |
| return f"{h:d}h {m:02d}m {s:02d}s" |
| if m > 0: |
| return f"{m:d}m {s:02d}s" |
| return f"{s:d}s" |
|
|