118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import typing
|
|
|
|
if typing.TYPE_CHECKING:
|
|
from rich.console import Console
|
|
|
|
|
|
class Print:
|
|
"""Class to handle print primitives"""
|
|
|
|
@classmethod
|
|
def info(cls, console: "Console", message: str, **kwargs) -> None:
|
|
console.print(f"{message}", style="cyan", **kwargs)
|
|
|
|
@classmethod
|
|
def success(cls, console: "Console", message: str, **kwargs) -> None:
|
|
console.print(f"✓ {message}", style="bold green", **kwargs)
|
|
|
|
@classmethod
|
|
def error(cls, console: "Console", message: str | Exception, **kwargs) -> None:
|
|
console.print(f"✗ {message}", style="bold red", **kwargs)
|
|
|
|
@classmethod
|
|
def warn(cls, console: "Console", message: str, **kwargs) -> None:
|
|
"""Non-fatal warning message."""
|
|
console.print(f"! {message}", style="bold yellow", **kwargs)
|
|
|
|
@classmethod
|
|
def header(cls, console: "Console", title: str) -> None:
|
|
"""Print a section header."""
|
|
console.print(f"[bold cyan]{title}[/bold cyan]")
|
|
|
|
@classmethod
|
|
def field(cls, console: "Console", label: str, value: typing.Any, indent: int = 0) -> None:
|
|
"""Print a labeled field with optional indentation."""
|
|
spaces = " " * indent
|
|
console.print(f"{spaces}[bold]{label}:[/bold] {value}")
|
|
|
|
|
|
def print_plan_details(plan: dict[str, typing.Any], console: "Console") -> None:
|
|
"""Pretty-print plan details using a rich Console instance."""
|
|
Print.header(console, "Plan Details")
|
|
Print.field(console, "Name", plan.get("name", "-"))
|
|
Print.field(console, "Price", f"{fmt_inr(plan.get('price_inr'))} /mo")
|
|
Print.field(console, "vCPUs", fmt_cpu(plan.get("vcpu")))
|
|
Print.field(console, "Memory", fmt_gb(plan.get("memory")))
|
|
Print.field(console, "Disk", fmt_gb(plan.get("disk")))
|
|
|
|
|
|
def print_full_plan_details(plan: dict[str, typing.Any], console: "Console") -> None:
|
|
"""Print an extended set of plan fields like title, owner, prices, etc."""
|
|
Print.header(console, "Current Plan")
|
|
Print.field(console, "Title", plan.get("title", "-"))
|
|
Print.field(console, "Name", plan.get("name", "-"))
|
|
Print.field(console, "Owner", plan.get("owner", "-"))
|
|
Print.field(console, "Modified By", plan.get("modified_by", "-"))
|
|
Print.field(console, "Price INR", fmt_inr(plan.get("price_inr")))
|
|
Print.field(console, "Price USD", plan.get("price_usd", "-"))
|
|
Print.field(console, "Premium", "Yes" if plan.get("premium") else "No")
|
|
Print.field(console, "Price/Day INR", fmt_inr(plan.get("price_per_day_inr")))
|
|
Print.field(console, "Price/Day USD", plan.get("price_per_day_usd", "-"))
|
|
|
|
|
|
def show_usage(
|
|
vcpu: str | float | int,
|
|
mem_mb: str | float | int,
|
|
disk_gb: str | float | int,
|
|
free_mem_bytes: str | float | int,
|
|
console: "Console",
|
|
) -> None:
|
|
Print.header(console, "Server Usage")
|
|
Print.field(console, "vCPU", fmt_cpu(vcpu))
|
|
Print.field(console, "Memory Used", fmt_mb(mem_mb))
|
|
Print.field(console, "Disk Used", fmt_gb(disk_gb, 2))
|
|
# free_mem_bytes is bytes; show as MB
|
|
if isinstance(free_mem_bytes, (int, float)):
|
|
free_mb = free_mem_bytes / 1024 / 1024
|
|
else:
|
|
free_mb = free_mem_bytes
|
|
Print.field(console, "Free Memory (avg 10m)", fmt_mb(free_mb))
|
|
|
|
|
|
# ---------- formatting helpers ----------
|
|
def _fmt_number(value: typing.Any, decimals: int = 0) -> str:
|
|
"""Format numbers with thousand separators and optional decimals; strip trailing zeros."""
|
|
if isinstance(value, (int, float)):
|
|
# Round to desired precision to avoid long floats like 2.826424479...
|
|
rounded = round(float(value), decimals)
|
|
if decimals > 0:
|
|
return f"{rounded:,.{decimals}f}".rstrip("0").rstrip(".")
|
|
return f"{int(rounded):,}"
|
|
return str(value)
|
|
|
|
|
|
def fmt_gb(value: typing.Any, decimals: int = 0) -> str:
|
|
if value is None or value == "-":
|
|
return "-"
|
|
return f"{_fmt_number(value, decimals)} GB"
|
|
|
|
|
|
def fmt_mb(value: typing.Any, decimals: int = 2) -> str:
|
|
if value is None or value == "-":
|
|
return "-"
|
|
return f"{_fmt_number(value, decimals)} MB"
|
|
|
|
|
|
def fmt_cpu(value: typing.Any, decimals: int = 2) -> str:
|
|
if value is None or value == "-":
|
|
return "-"
|
|
return _fmt_number(value, decimals)
|
|
|
|
|
|
def fmt_inr(value: typing.Any) -> str:
|
|
if value is None or value == "-":
|
|
return "-"
|
|
return f"₹{_fmt_number(value, 0)}"
|