from __future__ import annotations from datetime import datetime from typing import Any def _group_thousands(value: str) -> str: parts = [] while value: parts.append(value[-3:]) value = value[:-3] return ".".join(reversed(parts)) def number_de(value: Any, decimals: int = 1) -> str: if value is None: return "-" try: numeric = float(value) except (TypeError, ValueError): return "-" sign = "-" if numeric < 0 else "" numeric = abs(numeric) raw = f"{numeric:.{decimals}f}" integer, _, fraction = raw.partition(".") grouped = _group_thousands(integer) return f"{sign}{grouped},{fraction}" if decimals else f"{sign}{grouped}" def currency_de(value: Any, currency: str = "EUR") -> str: symbol = {"EUR": "€", "USD": "$", "GBP": "£"}.get(currency, currency) return f"{number_de(value, 2)} {symbol}" def percent_de(value: Any, decimals: int = 1) -> str: return f"{number_de(value, decimals)} %" def delta_de(value: Any, decimals: int = 1, suffix: str = "%") -> str: if value is None: return "-" numeric = float(value) prefix = "+" if numeric > 0 else "" return f"{prefix}{number_de(numeric, decimals)} {suffix}".strip() def date_de(value: Any) -> str: if not value: return "-" if isinstance(value, datetime): dt = value else: try: dt = datetime.fromisoformat(str(value).replace("Z", "+00:00")) except ValueError: return str(value) return dt.strftime("%d.%m.%Y") def clamp(value: Any, lower: float = 0, upper: float = 100) -> float: try: number = float(value) except (TypeError, ValueError): return lower return max(lower, min(upper, number))