Skip to content

Commit 842bd54

Browse files
committed
provide start, stop time in CLI output
1 parent 17d3917 commit 842bd54

2 files changed

Lines changed: 94 additions & 38 deletions

File tree

trackio/cli.py

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -934,24 +934,48 @@ def main():
934934
print(format_list(projects, "Projects"))
935935
elif args.list_type == "runs":
936936
if remote:
937-
run_records = remote.predict(
937+
remote_records = remote.predict(
938938
args.project, api_name="/get_runs_for_project"
939939
)
940-
runs = [r["name"] if isinstance(r, dict) else r for r in run_records]
941-
else:
942-
_require_project(args.project)
943-
runs = SQLiteStorage.get_runs(args.project)
944-
if args.json:
940+
runs = [r["name"] if isinstance(r, dict) else r for r in remote_records]
945941
statuses = SQLiteStorage.get_run_statuses(args.project)
946-
run_records = [{"name": r, "status": statuses.get(r)} for r in runs]
947-
print(format_json({"project": args.project, "runs": run_records}))
942+
if args.json:
943+
out = [{"name": r, "status": statuses.get(r)} for r in runs]
944+
print(format_json({"project": args.project, "runs": out}))
945+
else:
946+
annotated = [
947+
f"{r} [{statuses[r]}]" if r in statuses and statuses[r] else r
948+
for r in runs
949+
]
950+
print(format_list(annotated, f"Runs in '{args.project}'"))
948951
else:
952+
_require_project(args.project)
953+
records = SQLiteStorage.get_run_records(args.project)
949954
statuses = SQLiteStorage.get_run_statuses(args.project)
950-
annotated = [
951-
f"{r} [{statuses[r]}]" if r in statuses and statuses[r] else r
952-
for r in runs
953-
]
954-
print(format_list(annotated, f"Runs in '{args.project}'"))
955+
names = [r["name"] for r in records]
956+
has_dupes = len(names) != len(set(names))
957+
if args.json:
958+
out = [
959+
{
960+
"id": r["id"],
961+
"name": r["name"],
962+
"status": statuses.get(r["name"]),
963+
"started_at": r["created_at"],
964+
"finished_at": r["finished_at"],
965+
}
966+
for r in records
967+
]
968+
print(format_json({"project": args.project, "runs": out}))
969+
else:
970+
annotated = []
971+
for r in records:
972+
label = r["name"]
973+
if has_dupes:
974+
label += f" ({r['id'][:8]})"
975+
if statuses.get(r["name"]):
976+
label += f" [{statuses[r['name']]}]"
977+
annotated.append(label)
978+
print(format_list(annotated, f"Runs in '{args.project}'"))
955979
elif args.list_type == "metrics":
956980
if remote:
957981
metrics = remote.predict(
@@ -1400,9 +1424,26 @@ def main():
14001424
for r in results:
14011425
r["config"] = _public_config(configs.get(r["run"]) or {})
14021426

1427+
statuses_map = SQLiteStorage.get_run_statuses(args.project)
1428+
all_records = SQLiteStorage.get_run_records(args.project)
1429+
if status_filter is not None:
1430+
all_records = [rec for rec in all_records if statuses_map.get(rec["name"]) == status_filter]
1431+
records_by_name: dict[str, list[dict]] = {}
1432+
for rec in all_records:
1433+
records_by_name.setdefault(rec["name"], []).append(rec)
1434+
for r in results:
1435+
pool = records_by_name.get(r["run"], [])
1436+
matched = pool.pop(0) if pool else {}
1437+
r["id"] = matched.get("id")
1438+
r["started_at"] = matched.get("created_at")
1439+
r["finished_at"] = matched.get("finished_at")
1440+
14031441
results.sort(key=lambda x: x["value"], reverse=not minimize)
14041442
best = results[0]
14051443

1444+
run_names = [r["run"] for r in results]
1445+
has_dupes = len(run_names) != len(set(run_names))
1446+
14061447
if args.json:
14071448
print(
14081449
format_json(
@@ -1419,41 +1460,43 @@ def main():
14191460
)
14201461
)
14211462
else:
1422-
print(format_best(args.project, args.metric, minimize, args.mode, results))
1463+
display = [
1464+
{**r, "run": f"{r['run']} ({r['id'][:8]})" if has_dupes and r.get("id") else r["run"]}
1465+
for r in results
1466+
]
1467+
print(format_best(args.project, args.metric, minimize, args.mode, display))
14231468
elif args.command == "compare":
14241469
_require_project(args.project)
14251470

1426-
run_names = None
1427-
if args.runs:
1428-
run_names = [r.strip() for r in args.runs.split(",")]
1429-
14301471
status_filter = None if args.include_all else "finished"
1431-
if run_names:
1432-
all_runs = run_names
1433-
else:
1434-
all_runs = SQLiteStorage.get_runs(args.project)
1435-
if status_filter is not None:
1436-
statuses_for_filter = SQLiteStorage.get_run_statuses(args.project)
1437-
all_runs = [
1438-
r for r in all_runs if statuses_for_filter.get(r) == status_filter
1439-
]
1472+
statuses = SQLiteStorage.get_run_statuses(args.project)
1473+
1474+
all_records = SQLiteStorage.get_run_records(args.project)
1475+
if args.runs:
1476+
names_filter = {r.strip() for r in args.runs.split(",")}
1477+
all_records = [r for r in all_records if r["name"] in names_filter]
1478+
elif status_filter is not None:
1479+
all_records = [r for r in all_records if statuses.get(r["name"]) == status_filter]
14401480

14411481
metric_names = None
14421482
if args.metrics:
14431483
metric_names = [m.strip() for m in args.metrics.split(",")]
14441484

14451485
if not metric_names:
14461486
metric_set = set()
1447-
for run in all_runs:
1487+
for rec in all_records:
14481488
metric_set.update(
1449-
SQLiteStorage.get_all_metrics_for_run(args.project, run)
1489+
SQLiteStorage.get_all_metrics_for_run(args.project, rec["name"])
14501490
)
14511491
metric_names = sorted(metric_set)
14521492

14531493
configs = SQLiteStorage.get_all_run_configs(args.project)
1454-
statuses = SQLiteStorage.get_run_statuses(args.project)
1494+
run_names = [r["name"] for r in all_records]
1495+
has_dupes = len(run_names) != len(set(run_names))
1496+
14551497
comparison = []
1456-
for run in all_runs:
1498+
for rec in all_records:
1499+
run = rec["name"]
14571500
run_metrics = {}
14581501
for metric in metric_names:
14591502
values = SQLiteStorage.get_final_metric_for_runs(
@@ -1467,8 +1510,11 @@ def main():
14671510
run_metrics[metric] = values[0]["value"]
14681511
comparison.append(
14691512
{
1513+
"id": rec["id"],
14701514
"run": run,
14711515
"status": statuses.get(run),
1516+
"started_at": rec["created_at"],
1517+
"finished_at": rec["finished_at"],
14721518
"config": _public_config(configs.get(run, {})),
14731519
"metrics": run_metrics,
14741520
}
@@ -1485,7 +1531,11 @@ def main():
14851531
)
14861532
)
14871533
else:
1488-
print(format_compare(args.project, metric_names, comparison))
1534+
display = [
1535+
{**e, "run": f"{e['run']} ({e['id'][:8]})" if has_dupes and e.get("id") else e["run"]}
1536+
for e in comparison
1537+
]
1538+
print(format_compare(args.project, metric_names, display))
14891539
elif args.command == "summary":
14901540
_require_project(args.project)
14911541

trackio/sqlite_storage.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,11 @@ def get_run_records(project: str) -> list[dict[str, str | None]]:
607607
if SQLiteStorage._supports_run_ids(conn):
608608
cursor.execute(
609609
"""
610-
SELECT run_id, run_name, MIN(timestamp) as created_at
611-
FROM metrics
612-
GROUP BY run_id, run_name
610+
SELECT m.run_id, m.run_name, MIN(m.timestamp) as created_at,
611+
c.finished_at
612+
FROM metrics m
613+
LEFT JOIN configs c ON c.run_id = m.run_id
614+
GROUP BY m.run_id, m.run_name
613615
ORDER BY created_at ASC
614616
"""
615617
)
@@ -618,15 +620,18 @@ def get_run_records(project: str) -> list[dict[str, str | None]]:
618620
"id": row["run_id"],
619621
"name": row["run_name"],
620622
"created_at": row["created_at"],
623+
"finished_at": row["finished_at"],
621624
}
622625
for row in cursor.fetchall()
623626
]
624627

625628
cursor.execute(
626629
"""
627-
SELECT run_name, MIN(timestamp) as created_at
628-
FROM metrics
629-
GROUP BY run_name
630+
SELECT m.run_name, MIN(m.timestamp) as created_at,
631+
c.finished_at
632+
FROM metrics m
633+
LEFT JOIN configs c ON c.run_name = m.run_name
634+
GROUP BY m.run_name
630635
ORDER BY created_at ASC
631636
"""
632637
)
@@ -635,6 +640,7 @@ def get_run_records(project: str) -> list[dict[str, str | None]]:
635640
"id": row["run_name"],
636641
"name": row["run_name"],
637642
"created_at": row["created_at"],
643+
"finished_at": row["finished_at"],
638644
}
639645
for row in cursor.fetchall()
640646
]

0 commit comments

Comments
 (0)