Source code for exo_skryer.help_print

"""
help_print.py
=============
"""

from types import SimpleNamespace
from typing import Any, Dict, List


__all__ = [
    "format_duration",
    "print_cfg"
]

[docs] def format_duration(seconds: float) -> str: """Format a duration in seconds into a human-readable string. Parameters ---------- seconds : float Duration in seconds. Returns ------- str Formatted duration as ``"<d>d <h>h <m>m <s>s"``. """ days, rem = divmod(seconds, 24 * 3600) hours, rem = divmod(rem, 3600) minutes, seconds_final = divmod(rem, 60) return f"{int(days)}d {int(hours)}h {int(minutes)}m {seconds_final:.3f}s"
def _format_value(value: Any) -> str: if value is None: return "None" if isinstance(value, bool): return str(value).lower() if isinstance(value, SimpleNamespace): entries = [f"{k}={_format_value(v)}" for k, v in vars(value).items()] return ", ".join(entries) if entries else "{}" if isinstance(value, dict): entries = [f"{k}={_format_value(v)}" for k, v in value.items()] return ", ".join(entries) if entries else "{}" if isinstance(value, (list, tuple)): if not value: return "[]" if all(isinstance(v, SimpleNamespace) for v in value): count = len(value) plural = "entry" if count == 1 else "entries" return f"{count} {plural}" if all(not isinstance(v, (list, tuple, dict, SimpleNamespace)) for v in value) and len(value) <= 5: return "[" + ", ".join(str(v) for v in value) + "]" return f"{len(value)} items" return str(value) def _print_kv_table(title: str, data: Dict[str, Any]) -> None: """Print a simple key/value table.""" print() print("=" * 60) print(title) print("=" * 60) if not data: print("(none)") return k_width = max(len(k) for k in data.keys()) for k, v in data.items(): print(f"{k.ljust(k_width)} : {_format_value(v)}") def _print_params_table(params: List[SimpleNamespace]) -> None: """Print the params section as a compact table.""" print() print("=" * 60) print("PARAMETERS") print("=" * 60) if not params: print("(no parameters defined)") return header = ["name", "dist", "transform", "value/low", "high", "init"] rows: List[List[str]] = [] for p in params: name = str(getattr(p, "name", "")) dist = str(getattr(p, "dist", "")) transform = str(getattr(p, "transform", "")) if dist == "delta": val = getattr(p, "value", "") low_str = "" if val is None else str(val) high_str = "" else: low = getattr(p, "low", "") high = getattr(p, "high", "") low_str = "" if low is None else str(low) high_str = "" if high is None else str(high) init = getattr(p, "init", "") init_str = "" if init is None else str(init) rows.append([name, dist, transform, low_str, high_str, init_str]) # column widths cols = list(zip(header, *rows)) widths = [max(len(str(x)) for x in col) for col in cols] def fmt_row(row): return " ".join(str(x).ljust(w) for x, w in zip(row, widths)) # print print(fmt_row(header)) print(" ".join("-" * w for w in widths)) for r in rows: print(fmt_row(r)) def _print_opac_list(title: str, items: List[SimpleNamespace]) -> None: """Print an opacity category (line/cia/ray/cloud) as a small table.""" print() print("=" * 60) print(title) print("=" * 60) if not items: print("(none)") return # Collect all keys present across items all_keys = set() for it in items: all_keys.update(vars(it).keys()) # We prefer to show 'species' and 'path' first if they exist preferred = ["species", "path"] keys = [k for k in preferred if k in all_keys] + \ [k for k in sorted(all_keys) if k not in preferred] header = keys rows: List[List[str]] = [] for it in items: d = vars(it) rows.append([_format_value(d.get(k, "")) for k in keys]) # column widths cols = list(zip(header, *rows)) widths = [max(len(str(x)) for x in col) for col in cols] def fmt_row(row): return " ".join(str(x).ljust(w) for x, w in zip(row, widths)) # print print(fmt_row(header)) print(" ".join("-" * w for w in widths)) for r in rows: print(fmt_row(r))