@@ -68,6 +68,54 @@ def seeded_dir():
6868 mm .MEDIA_DIR , mu .MEDIA_DIR , tu .MEDIA_DIR , ss .MEDIA_DIR = orig_media
6969
7070
71+ @pytest .fixture (scope = "module" )
72+ def seeded_dir_with_unfinished ():
73+ """Fixture with two finished runs and one still-running run."""
74+ with tempfile .TemporaryDirectory (ignore_cleanup_errors = True ) as tmpdir :
75+ import trackio .media .media as mm
76+ import trackio .media .utils as mu
77+ import trackio .sqlite_storage as ss
78+ import trackio .utils as tu
79+
80+ orig_trackio = ss .TRACKIO_DIR
81+ orig_media = [mm .MEDIA_DIR , mu .MEDIA_DIR , tu .MEDIA_DIR , ss .MEDIA_DIR ]
82+ ss .TRACKIO_DIR = Path (tmpdir )
83+ mm .MEDIA_DIR = mu .MEDIA_DIR = tu .MEDIA_DIR = ss .MEDIA_DIR = (
84+ Path (tmpdir ) / "media"
85+ )
86+
87+ context_vars .current_run .set (None )
88+ context_vars .current_project .set (None )
89+ context_vars .current_server .set (None )
90+ context_vars .current_space_id .set (None )
91+
92+ proj = "filter_test"
93+
94+ trackio .init (project = proj , name = "done-run" , config = {"lr" : 0.01 })
95+ for step in range (5 ):
96+ trackio .log ({"val/loss" : 1.0 - step * 0.1 }, step = step )
97+ trackio .finish ()
98+
99+ trackio .init (project = proj , name = "also-done" , config = {"lr" : 0.1 })
100+ for step in range (5 ):
101+ trackio .log ({"val/loss" : 2.0 - step * 0.1 }, step = step )
102+ trackio .finish ()
103+
104+ trackio .init (project = proj , name = "still-running" , config = {"lr" : 1.0 })
105+ for step in range (5 ):
106+ trackio .log ({"val/loss" : 5.0 + step * 0.5 }, step = step )
107+
108+ context_vars .current_run .set (None )
109+ context_vars .current_project .set (None )
110+ context_vars .current_server .set (None )
111+ context_vars .current_space_id .set (None )
112+
113+ yield (tmpdir , proj )
114+
115+ ss .TRACKIO_DIR = orig_trackio
116+ mm .MEDIA_DIR , mu .MEDIA_DIR , tu .MEDIA_DIR , ss .MEDIA_DIR = orig_media
117+
118+
71119def _cli (args , env_dir ):
72120 env = os .environ .copy ()
73121 env ["TRACKIO_DIR" ] = env_dir
@@ -108,6 +156,29 @@ def test_best(seeded_dir):
108156 assert json .loads (r2 .stdout )["best_run" ] == "run-lr0.01"
109157
110158
159+ def test_best_excludes_unfinished_by_default (seeded_dir_with_unfinished ):
160+ tmpdir , proj = seeded_dir_with_unfinished
161+ r = _cli (["best" , "--project" , proj , "--metric" , "val/loss" , "--json" ], tmpdir )
162+ assert r .returncode == 0
163+ data = json .loads (r .stdout )
164+ run_names = [e ["run" ] for e in data ["ranking" ]]
165+ assert "still-running" not in run_names
166+ assert len (run_names ) == 2
167+
168+
169+ def test_best_include_all (seeded_dir_with_unfinished ):
170+ tmpdir , proj = seeded_dir_with_unfinished
171+ r = _cli (
172+ ["best" , "--project" , proj , "--metric" , "val/loss" , "--include-all" , "--json" ],
173+ tmpdir ,
174+ )
175+ assert r .returncode == 0
176+ data = json .loads (r .stdout )
177+ run_names = [e ["run" ] for e in data ["ranking" ]]
178+ assert "still-running" in run_names
179+ assert len (run_names ) == 3
180+
181+
111182def test_compare (seeded_dir ):
112183 r = _cli (
113184 ["compare" , "--project" , PROJECT , "--metrics" , "val/loss,accuracy" , "--json" ],
@@ -136,6 +207,37 @@ def test_compare(seeded_dir):
136207 assert len (json .loads (r2 .stdout )["runs" ]) == 2
137208
138209
210+ def test_compare_excludes_unfinished_by_default (seeded_dir_with_unfinished ):
211+ tmpdir , proj = seeded_dir_with_unfinished
212+ r = _cli (["compare" , "--project" , proj , "--metrics" , "val/loss" , "--json" ], tmpdir )
213+ assert r .returncode == 0
214+ data = json .loads (r .stdout )
215+ run_names = [e ["run" ] for e in data ["runs" ]]
216+ assert "still-running" not in run_names
217+ assert len (run_names ) == 2
218+
219+
220+ def test_compare_include_all (seeded_dir_with_unfinished ):
221+ tmpdir , proj = seeded_dir_with_unfinished
222+ r = _cli (
223+ [
224+ "compare" ,
225+ "--project" ,
226+ proj ,
227+ "--metrics" ,
228+ "val/loss" ,
229+ "--include-all" ,
230+ "--json" ,
231+ ],
232+ tmpdir ,
233+ )
234+ assert r .returncode == 0
235+ data = json .loads (r .stdout )
236+ run_names = [e ["run" ] for e in data ["runs" ]]
237+ assert "still-running" in run_names
238+ assert len (run_names ) == 3
239+
240+
139241def test_summary (seeded_dir ):
140242 r = _cli (
141243 ["summary" , "--project" , PROJECT , "--metric" , "val/loss" , "--json" ], seeded_dir
@@ -155,6 +257,20 @@ def test_summary(seeded_dir):
155257 } <= run_entry .keys ()
156258
157259
260+ def test_list_runs_json_includes_status (seeded_dir ):
261+ r = _cli (["list" , "runs" , "--project" , PROJECT , "--json" ], seeded_dir )
262+ assert r .returncode == 0
263+ data = json .loads (r .stdout )
264+ assert "runs" in data
265+ for entry in data ["runs" ]:
266+ assert "name" in entry
267+ assert "status" in entry
268+ statuses = {e ["name" ]: e ["status" ] for e in data ["runs" ]}
269+ assert statuses .get ("run-lr0.01" ) == "finished"
270+ assert statuses .get ("run-lr0.1" ) == "finished"
271+ assert statuses .get ("run-lr1.0" ) == "finished"
272+
273+
158274def test_best_error_cases (seeded_dir ):
159275 assert (
160276 _cli (
0 commit comments