import sys import threading import time class ProgressIndicator: def __init__(self, message: str = "Working", show: bool = True): self.message = message self.show = show self.running = False self.thread = None def __enter__(self): if self.show: self.start() return self def __exit__(self, exc_type, exc_val, exc_tb): if self.show: self.stop() def start(self): self.running = True self.thread = threading.Thread(target=self._animate, daemon=True) self.thread.start() def stop(self): if self.running: self.running = False if self.thread: self.thread.join(timeout=1.0) sys.stdout.write("\r" + " " * (len(self.message) + 10) + "\r") sys.stdout.flush() def _animate(self): spinner = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] idx = 0 while self.running: sys.stdout.write(f"\r{spinner[idx]} {self.message}...") sys.stdout.flush() idx = (idx + 1) % len(spinner) time.sleep(0.1) class ProgressBar: def __init__(self, total: int, description: str = "Progress", width: int = 40): self.total = total self.description = description self.width = width self.current = 0 def update(self, amount: int = 1): self.current += amount self._display() def _display(self): if self.total == 0: percent = 100 else: percent = int((self.current / self.total) * 100) filled = int((self.current / self.total) * self.width) if self.total > 0 else self.width bar = "█" * filled + "░" * (self.width - filled) sys.stdout.write(f"\r{self.description}: |{bar}| {percent}% ({self.current}/{self.total})") sys.stdout.flush() if self.current >= self.total: sys.stdout.write("\n") def finish(self): self.current = self.total self._display()