""" Formatting utilities for display. """ from datetime import datetime from typing import Optional, Union def format_date( value: Optional[Union[str, datetime]], length: int = 10, include_time: bool = False, ) -> str: """ Format a date/datetime for display. Args: value: Date string or datetime object length: Length to truncate to (default 10 for YYYY-MM-DD) include_time: Whether to include time portion Returns: Formatted date string """ if value is None: return "" if isinstance(value, str): # Parse ISO format string try: if "T" in value: dt = datetime.fromisoformat(value.replace("Z", "+00:00")) else: return value[:length] except ValueError: return value[:length] else: dt = value if include_time: return dt.strftime("%Y-%m-%d %H:%M") return dt.strftime("%Y-%m-%d") def format_size(size_bytes: Optional[int]) -> str: """ Format file size in human-readable form. Args: size_bytes: Size in bytes Returns: Human-readable size string (e.g., "1.5 MB") """ if size_bytes is None: return "Unknown" if size_bytes < 0: return "Unknown" if size_bytes == 0: return "0 B" units = ["B", "KB", "MB", "GB", "TB"] unit_index = 0 size = float(size_bytes) while size >= 1024 and unit_index < len(units) - 1: size /= 1024 unit_index += 1 if unit_index == 0: return f"{int(size)} {units[unit_index]}" return f"{size:.1f} {units[unit_index]}" def truncate_hash(value: str, length: int = 16, suffix: str = "...") -> str: """ Truncate a hash or long string with ellipsis. Args: value: String to truncate length: Maximum length before truncation suffix: Suffix to add when truncated Returns: Truncated string """ if not value: return "" if len(value) <= length: return value return f"{value[:length]}{suffix}" def format_duration(seconds: Optional[float]) -> str: """ Format duration in human-readable form. Args: seconds: Duration in seconds Returns: Human-readable duration string (e.g., "2m 30s") """ if seconds is None or seconds < 0: return "Unknown" if seconds < 1: return f"{int(seconds * 1000)}ms" if seconds < 60: return f"{seconds:.1f}s" minutes = int(seconds // 60) remaining_seconds = int(seconds % 60) if minutes < 60: if remaining_seconds: return f"{minutes}m {remaining_seconds}s" return f"{minutes}m" hours = minutes // 60 remaining_minutes = minutes % 60 if remaining_minutes: return f"{hours}h {remaining_minutes}m" return f"{hours}h" def format_count(count: int) -> str: """ Format a count with abbreviation for large numbers. Args: count: Number to format Returns: Formatted string (e.g., "1.2K", "3.5M") """ if count < 1000: return str(count) if count < 1000000: return f"{count / 1000:.1f}K" if count < 1000000000: return f"{count / 1000000:.1f}M" return f"{count / 1000000000:.1f}B" def format_percentage(value: float, decimals: int = 1) -> str: """ Format a percentage value. Args: value: Percentage value (0-100 or 0-1) decimals: Number of decimal places Returns: Formatted percentage string """ # Assume 0-1 if less than 1 if value <= 1: value *= 100 if decimals == 0: return f"{int(value)}%" return f"{value:.{decimals}f}%"