|
import sys
|
|
import time
|
|
import threading
|
|
|
|
|
|
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()
|