Skip to content

Commit 19eb47c

Browse files
committed
Add CLI tool with run command (#67)
1 parent 787630c commit 19eb47c

7 files changed

Lines changed: 96 additions & 11 deletions

File tree

ngraph/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
import ngraph.transform
1+
from __future__ import annotations
2+
from . import cli, transform
3+
4+
__all__ = ["cli", "transform"]

ngraph/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from __future__ import annotations
2+
3+
from .cli import main
4+
5+
if __name__ == "__main__":
6+
main()

ngraph/cli.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from __future__ import annotations
2+
3+
import argparse
4+
import json
5+
from pathlib import Path
6+
from typing import Any, Dict, List, Optional
7+
8+
from ngraph.scenario import Scenario
9+
10+
11+
def _run_scenario(path: Path, output: Optional[Path]) -> None:
12+
"""Run a scenario file and store results as JSON."""
13+
yaml_text = path.read_text()
14+
scenario = Scenario.from_yaml(yaml_text)
15+
scenario.run()
16+
17+
results_dict: Dict[str, Dict[str, Any]] = scenario.results.to_dict()
18+
json_str = json.dumps(results_dict, indent=2, default=str)
19+
if output:
20+
output.write_text(json_str)
21+
else:
22+
print(json_str)
23+
24+
25+
def main(argv: Optional[List[str]] = None) -> None:
26+
"""Entry point for the ``ngraph`` command."""
27+
parser = argparse.ArgumentParser(prog="ngraph")
28+
subparsers = parser.add_subparsers(dest="command", required=True)
29+
30+
run_parser = subparsers.add_parser("run", help="Run a scenario")
31+
run_parser.add_argument("scenario", type=Path, help="Path to scenario YAML")
32+
run_parser.add_argument(
33+
"--results",
34+
"-r",
35+
type=Path,
36+
default=None,
37+
help="Write JSON results to this file instead of stdout",
38+
)
39+
40+
args = parser.parse_args(argv)
41+
42+
if args.command == "run":
43+
_run_scenario(args.scenario, args.results)
44+
45+
46+
if __name__ == "__main__":
47+
main()

ngraph/results.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ def get_all(self, key: str) -> Dict[str, Any]:
5454
if key in data:
5555
result[step_name] = data[key]
5656
return result
57+
58+
def to_dict(self) -> Dict[str, Dict[str, Any]]:
59+
"""Return a dictionary representation of all stored results."""
60+
return {step: data.copy() for step, data in self._store.items()}

notebooks/bb_fabric.ipynb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 6,
5+
"execution_count": 11,
66
"id": "a92a8d34",
77
"metadata": {},
88
"outputs": [],
@@ -19,7 +19,7 @@
1919
},
2020
{
2121
"cell_type": "code",
22-
"execution_count": null,
22+
"execution_count": 12,
2323
"id": "ad94e880",
2424
"metadata": {},
2525
"outputs": [
@@ -101,7 +101,7 @@
101101
},
102102
{
103103
"cell_type": "code",
104-
"execution_count": 8,
104+
"execution_count": 13,
105105
"id": "6c491ddc",
106106
"metadata": {},
107107
"outputs": [
@@ -111,7 +111,7 @@
111111
"Node(name='bb_fabric/t1/t1-4', disabled=True, risk_groups=set(), attrs={'type': 'node'})"
112112
]
113113
},
114-
"execution_count": 8,
114+
"execution_count": 13,
115115
"metadata": {},
116116
"output_type": "execute_result"
117117
}
@@ -122,7 +122,7 @@
122122
},
123123
{
124124
"cell_type": "code",
125-
"execution_count": 9,
125+
"execution_count": 14,
126126
"id": "df3eb867",
127127
"metadata": {},
128128
"outputs": [],
@@ -132,19 +132,19 @@
132132
},
133133
{
134134
"cell_type": "code",
135-
"execution_count": 10,
135+
"execution_count": 15,
136136
"id": "35a81770",
137137
"metadata": {},
138138
"outputs": [
139139
{
140140
"name": "stdout",
141141
"output_type": "stream",
142142
"text": [
143-
"- root | Nodes=21, Links=130, Cost=0.0, Power=0.0\n",
144-
" - bb_fabric | Nodes=20, Links=130, Cost=0.0, Power=0.0\n",
143+
"- root | Nodes=21, Links=132, Cost=0.0, Power=0.0\n",
144+
" - bb_fabric | Nodes=20, Links=132, Cost=0.0, Power=0.0\n",
145145
" - t2 | Nodes=4, Links=128, Cost=0.0, Power=0.0\n",
146-
" - t1 | Nodes=16, Links=130, Cost=0.0, Power=0.0\n",
147-
" - remote | Nodes=1, Links=2, Cost=0.0, Power=0.0\n"
146+
" - t1 | Nodes=16, Links=132, Cost=0.0, Power=0.0\n",
147+
" - remote | Nodes=1, Links=4, Cost=0.0, Power=0.0\n"
148148
]
149149
}
150150
],

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ dev = [
3333
"black",
3434
"isort",
3535
]
36+
[project.scripts]
37+
ngraph = "ngraph.cli:main"
38+
3639

3740
# ---------------------------------------------------------------------
3841
# Pytest flags

tests/test_cli.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import json
2+
from pathlib import Path
3+
4+
from ngraph import cli
5+
6+
7+
def test_cli_run_file(tmp_path: Path) -> None:
8+
scenario = Path("tests/scenarios/scenario_1.yaml")
9+
out_file = tmp_path / "res.json"
10+
cli.main(["run", str(scenario), "--results", str(out_file)])
11+
assert out_file.is_file()
12+
data = json.loads(out_file.read_text())
13+
assert "build_graph" in data
14+
assert "graph" in data["build_graph"]
15+
16+
17+
def test_cli_run_stdout(capsys) -> None:
18+
scenario = Path("tests/scenarios/scenario_1.yaml")
19+
cli.main(["run", str(scenario)])
20+
captured = capsys.readouterr()
21+
data = json.loads(captured.out)
22+
assert "build_graph" in data

0 commit comments

Comments
 (0)