Commit 34675024 authored by one's avatar one
Browse files

[hytop] Move some options to the root command

parent a927fefb
...@@ -23,10 +23,10 @@ Simple examples: ...@@ -23,10 +23,10 @@ Simple examples:
```bash ```bash
# Local node, all GPUs, 5-second rolling window # Local node, all GPUs, 5-second rolling window
hytop gpu -n 1 --window 5 hytop -n 1 --window 5 gpu
# Two nodes, monitor only GPU 0 and 1 # Two nodes, monitor only GPU 0 and 1
hytop gpu -H node01,node02 --devices 0,1 -n 1 hytop -H node01,node02 -n 1 gpu --devices 0,1
# Exit with code 0 when all monitored GPUs are available # Exit with code 0 when all monitored GPUs are available
hytop gpu --devices 0,1 --wait-idle hytop gpu --devices 0,1 --wait-idle
...@@ -42,12 +42,11 @@ hytop gpu --showpower --showtemp ...@@ -42,12 +42,11 @@ hytop gpu --showpower --showtemp
Queue jobs in shared environments: Queue jobs in shared environments:
```bash ```bash
if hytop gpu -H node01,node02 --wait-idle --timeout 300; then if hytop -H node01,node02 gpu --wait-idle --timeout 300; then
echo "GPUs available, starting workload..." echo "GPUs available, starting workload..."
# YOUR COMMAND HERE (e.g., python train.py) # YOUR COMMAND HERE (e.g., python train.py)
else else
echo "Error: GPUs not available in time, aborting pipeline." echo "Error: GPUs not available in time, aborting pipeline."
exit 1
fi fi
``` ```
......
...@@ -4,10 +4,9 @@ from typing import Optional, Set ...@@ -4,10 +4,9 @@ from typing import Optional, Set
import typer import typer
from hytop import __version__
from hytop.gpu.metrics import SUPPORTED_SHOW_FLAGS, normalized_show_flags from hytop.gpu.metrics import SUPPORTED_SHOW_FLAGS, normalized_show_flags
from hytop.gpu.service import run_monitor from hytop.gpu.service import run_monitor
from hytop.gpu.validators import parse_csv_ints, parse_csv_strings, parse_positive_float from hytop.core.validators import parse_csv_ints
app = typer.Typer( app = typer.Typer(
add_completion=False, add_completion=False,
...@@ -17,21 +16,6 @@ app = typer.Typer( ...@@ -17,21 +16,6 @@ app = typer.Typer(
SHOW_FLAG_ORDER_KEY = "show_flag_order" SHOW_FLAG_ORDER_KEY = "show_flag_order"
def version_callback(value: bool) -> None:
"""Handle Typer eager version option.
Args:
value: Whether version flag was provided.
Raises:
typer.Exit: Raised to terminate command after printing version.
"""
if value:
typer.echo(__version__)
raise typer.Exit()
def remember_show_flag_callback(ctx: typer.Context, param: object, value: bool) -> bool: def remember_show_flag_callback(ctx: typer.Context, param: object, value: bool) -> bool:
"""Record --show* flags in parser encounter order.""" """Record --show* flags in parser encounter order."""
...@@ -49,29 +33,12 @@ def remember_show_flag_callback(ctx: typer.Context, param: object, value: bool) ...@@ -49,29 +33,12 @@ def remember_show_flag_callback(ctx: typer.Context, param: object, value: bool)
@app.callback(invoke_without_command=True) @app.callback(invoke_without_command=True)
def gpu( def gpu(
ctx: typer.Context, ctx: typer.Context,
hosts: str = typer.Option(
"localhost",
"--hosts",
"-H",
help="Comma-separated hosts, e.g. node01,node02. Default: localhost",
),
device_filter: str = typer.Option( device_filter: str = typer.Option(
"", "",
"--devices", "--devices",
"-d", "-d",
help="Comma-separated GPU IDs, e.g. 0,1. Default: all visible GPUs", help="Comma-separated GPU IDs, e.g. 0,1. Default: all visible GPUs",
), ),
interval: float = typer.Option(
1.0,
"--interval",
"-n",
help="Polling interval in seconds. Default: 1.0",
),
window: float = typer.Option(
5.0,
"--window",
help="Single rolling window in seconds. Default: 5.0",
),
wait_idle: bool = typer.Option( wait_idle: bool = typer.Option(
False, False,
"--wait-idle", "--wait-idle",
...@@ -112,19 +79,17 @@ def gpu( ...@@ -112,19 +79,17 @@ def gpu(
"--timeout", "--timeout",
help="Max runtime in seconds. Effective only with --wait-idle.", help="Max runtime in seconds. Effective only with --wait-idle.",
), ),
version: bool = typer.Option(
False,
"--version",
"-v",
callback=version_callback,
is_eager=True,
help="Show version and exit.",
),
) -> None: ) -> None:
"""Run GPU monitor.""" """GPU monitoring commands."""
if ctx.obj is None:
typer.echo("argument error: global options not available", err=True)
raise typer.Exit(code=2)
try: try:
host_list = parse_csv_strings(hosts, "--hosts") host_list = ctx.obj["hosts"]
interval = ctx.obj["interval"]
window_value = ctx.obj["window"]
selected_show_flags = { selected_show_flags = {
"showtemp": showtemp, "showtemp": showtemp,
"showpower": showpower, "showpower": showpower,
...@@ -146,9 +111,8 @@ def gpu( ...@@ -146,9 +111,8 @@ def gpu(
parsed_device_filter: Optional[Set[int]] = None parsed_device_filter: Optional[Set[int]] = None
if device_filter: if device_filter:
parsed_device_filter = set(parse_csv_ints(device_filter, "--devices")) parsed_device_filter = set(parse_csv_ints(device_filter, "--devices"))
window_value = parse_positive_float(str(window), "--window")
timeout_value = ( timeout_value = (
parse_positive_float(str(timeout), "--timeout") float(timeout)
if timeout is not None if timeout is not None
else None else None
) )
......
from __future__ import annotations
import typer import typer
from hytop import __version__
from hytop.cpu.cli import app as cpu_app from hytop.cpu.cli import app as cpu_app
from hytop.gpu.cli import app as gpu_app from hytop.gpu.cli import app as gpu_app
from hytop.core.validators import parse_csv_strings, parse_positive_float
app = typer.Typer(help="hytop toolkit command line") app = typer.Typer(
help="hytop toolkit command line",
context_settings={"help_option_names": ["-h", "--help"]},
)
app.add_typer(cpu_app, name="cpu") app.add_typer(cpu_app, name="cpu")
app.add_typer(gpu_app, name="gpu") app.add_typer(gpu_app, name="gpu")
def version_callback(value: bool) -> None:
"""Handle Typer eager version option."""
if value:
typer.echo(__version__)
raise typer.Exit()
@app.callback(invoke_without_command=True)
def root(
ctx: typer.Context,
version: bool = typer.Option(
False,
"--version",
"-v",
callback=version_callback,
is_eager=True,
help="Show version and exit.",
),
hosts: str = typer.Option(
"localhost",
"--hosts",
"-H",
help="Comma-separated hosts, e.g. node01,node02. Default: localhost",
),
interval: float = typer.Option(
1.0,
"--interval",
"-n",
help="Polling interval in seconds. Default: 1.0",
),
window: float = typer.Option(
5.0,
"--window",
help="Single rolling window in seconds. Default: 5.0",
),
) -> None:
"""Root callback that parses global options and stores them in context."""
try:
host_list = parse_csv_strings(hosts, "--hosts")
window_value = parse_positive_float(str(window), "--window")
except ValueError as exc:
typer.echo(f"argument error: {exc}", err=True)
raise typer.Exit(code=2) from exc
ctx.obj = {
"hosts": host_list,
"interval": interval,
"window": window_value,
}
def main() -> None: def main() -> None:
app() app()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment