|
import logging |
|
import sys |
|
from typing import Dict, Any, List, Optional |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
class LogFormatter: |
|
"""Utility class for consistent log formatting across the application""" |
|
|
|
@staticmethod |
|
def section(title: str) -> str: |
|
"""Create a section header""" |
|
return f"\n{'='*20} {title.upper()} {'='*20}" |
|
|
|
@staticmethod |
|
def subsection(title: str) -> str: |
|
"""Create a subsection header""" |
|
return f"\n{'β'*20} {title} {'β'*20}" |
|
|
|
@staticmethod |
|
def tree(items: Dict[str, Any], title: str = None) -> List[str]: |
|
"""Create a tree view of dictionary data""" |
|
lines = [] |
|
if title: |
|
lines.append(f"π {title}:") |
|
|
|
|
|
max_key_length = max(len(str(k)) for k in items.keys()) |
|
|
|
|
|
for i, (key, value) in enumerate(items.items()): |
|
prefix = "βββ" if i == len(items) - 1 else "βββ" |
|
if isinstance(value, (int, float)): |
|
value = f"{value:,}" |
|
lines.append(f"{prefix} {str(key):<{max_key_length}}: {value}") |
|
|
|
return lines |
|
|
|
@staticmethod |
|
def stats(stats: Dict[str, int], title: str = None) -> List[str]: |
|
"""Format statistics with icons""" |
|
lines = [] |
|
if title: |
|
lines.append(f"π {title}:") |
|
|
|
|
|
max_key_length = max(len(str(k)) for k in stats.keys()) |
|
|
|
|
|
icons = { |
|
"total": "π", |
|
"success": "β
", |
|
"error": "β", |
|
"pending": "β³", |
|
"processing": "βοΈ", |
|
"finished": "β¨", |
|
"evaluating": "π", |
|
"downloads": "β¬οΈ", |
|
"files": "π", |
|
"cached": "πΎ", |
|
"size": "π", |
|
"time": "β±οΈ", |
|
"rate": "π" |
|
} |
|
|
|
|
|
for i, (key, value) in enumerate(stats.items()): |
|
prefix = "βββ" if i == len(stats) - 1 else "βββ" |
|
icon = icons.get(key.lower().split('_')[0], "β’") |
|
if isinstance(value, (int, float)): |
|
value = f"{value:,}" |
|
lines.append(f"{prefix} {icon} {str(key):<{max_key_length}}: {value}") |
|
|
|
return lines |
|
|
|
@staticmethod |
|
def progress_bar(current: int, total: int, width: int = 20) -> str: |
|
"""Create a progress bar""" |
|
percentage = (current * 100) // total |
|
filled = "β" * (percentage * width // 100) |
|
empty = "β" * (width - len(filled)) |
|
return f"{filled}{empty} {percentage:3d}%" |
|
|
|
@staticmethod |
|
def error(message: str, error: Optional[Exception] = None) -> str: |
|
"""Format error message""" |
|
error_msg = f"\nβ Error: {message}" |
|
if error: |
|
error_msg += f"\n βββ Details: {str(error)}" |
|
return error_msg |
|
|
|
@staticmethod |
|
def success(message: str) -> str: |
|
"""Format success message""" |
|
return f"β
{message}" |
|
|
|
@staticmethod |
|
def warning(message: str) -> str: |
|
"""Format warning message""" |
|
return f"β οΈ {message}" |
|
|
|
@staticmethod |
|
def info(message: str) -> str: |
|
"""Format info message""" |
|
return f"βΉοΈ {message}" |