Add fluksio status, and ask for a run's parameters at a terminal
Two halves of the same gap: the CLI could start work but not show you any. `fluksio status` draws the home screen's top half in a terminal — health and what is wrong with it, every flow with its state and node count, and the recent runs and failures under them. `--watch` keeps it there. Rich does the drawing; it was already installed under fastapi's own CLI, and is named now because a command depends on it. `fluksio run` with no parameters at a terminal asks for them, one line per declared input with its declared value in brackets — so Enter through the lot is what running the defaults looks like, and an artifact input takes the `@run:` spelling the engine now resolves. A scripted run is untouched: passing any parameter, or piping the command, skips the questions, as does --defaults. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019V5bsYGNxcgPs4xXmTPx69
This commit is contained in:
@@ -255,3 +255,53 @@ def test_ctrl_c_while_waiting_cancels_the_run(monkeypatch) -> None:
|
||||
args = _parser().parse_args(["run", "train", "--local", "--no-sync"])
|
||||
assert cli.cmd_run(args, []) == 130
|
||||
assert cancelled == ["run-1"]
|
||||
|
||||
|
||||
def test_an_artifact_input_may_be_named_rather_than_pasted() -> None:
|
||||
"""The engine resolves either spelling; the CLI just stops mangling them."""
|
||||
import json
|
||||
|
||||
from fluksio.sdk.cli import _coerce
|
||||
|
||||
assert _coerce("@run:123-abc.dataset", "artifact") == "@run:123-abc.dataset"
|
||||
digest = "sha256:" + "a1" * 32
|
||||
assert _coerce(digest, "artifact") == digest
|
||||
# A reference a script already holds still arrives as the object it is.
|
||||
reference = {"digest": digest, "size": 3}
|
||||
assert _coerce(json.dumps(reference), "artifact") == reference
|
||||
|
||||
|
||||
def test_the_run_prompt_keeps_declared_values_for_anything_left_blank() -> None:
|
||||
"""Enter through the lot is what running with the defaults looks like."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from fluksio.sdk.cli import _ask_params
|
||||
|
||||
definition = {
|
||||
"inputs": [
|
||||
{"spec": {"name": "lr", "dtype": "float"}, "initial": 0.05},
|
||||
{"spec": {"name": "epochs", "dtype": "int"}, "initial": 10},
|
||||
]
|
||||
}
|
||||
|
||||
with patch("builtins.input", side_effect=["", ""]):
|
||||
# Nothing sent: an input the caller leaves out keeps what it declares,
|
||||
# which is the same contract the browser's dialog has.
|
||||
assert _ask_params(definition) == {}
|
||||
|
||||
with patch("builtins.input", side_effect=["0.01", "50"]):
|
||||
assert _ask_params(definition) == {"lr": 0.01, "epochs": 50}
|
||||
|
||||
|
||||
def test_the_run_prompt_names_an_answer_of_the_wrong_type() -> None:
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from fluksio.sdk import SyncError
|
||||
from fluksio.sdk.cli import _ask_params
|
||||
|
||||
definition = {"inputs": [{"spec": {"name": "lr", "dtype": "float"}}]}
|
||||
with patch("builtins.input", side_effect=["fast"]):
|
||||
with pytest.raises(SyncError, match="lr"):
|
||||
_ask_params(definition)
|
||||
|
||||
Reference in New Issue
Block a user