55import os
66import time
77from pathlib import Path
8- from typing import Union
8+ from typing import Optional , Dict , Union
99
1010from pavilion import config
1111from pavilion import dir_db
@@ -128,9 +128,9 @@ def get_all_started(path: Path) -> Union[float, None]:
128128
129129
130130# This is needed by both the series object and the series info object.
131- def set_complete (path , when : float = None ) -> dict :
131+ def set_complete (path : Path , when : float = None ) -> dict :
132132 """Write a file in the series directory that indicates that the series
133- has finished."""
133+ has finished. May raise a timeout error if the file cannot be written. """
134134
135135 complete_fn = path / COMPLETE_FN
136136 status_fn = path / STATUS_FN
@@ -154,6 +154,12 @@ def set_complete(path, when: float = None) -> dict:
154154 except (OSError , ValueError ) as err :
155155 raise TestSeriesError ("Error saving completion file." , err )
156156
157+ wait (
158+ complete_fn_tmp .exists ,
159+ interval = 0.1 ,
160+ timeout = 5 ,
161+ msg = f"Timed out waiting for file { complete_fn_tmp } to be created." )
162+
157163 complete_fn_tmp .rename (complete_fn )
158164
159165 # Note that this might be a bit off from reality if something else set the
@@ -165,7 +171,7 @@ def set_complete(path, when: float = None) -> dict:
165171# Call the series complete even if it wasn't marked as such.
166172SERIES_COMPLETE_TIMEOUT = 3 * 60 * 60
167173
168- def _read_complete (series_path : Path ) -> Union [ dict , None ]:
174+ def _read_complete (series_path : Path ) -> Optional [ Dict ]:
169175 """Read the series completion file, if it exists, and return the completion data.
170176 Returns None if the completion file doesn't exist or can't be read."""
171177
@@ -179,8 +185,12 @@ def _read_complete(series_path: Path) -> Union[dict, None]:
179185
180186
181187def get_complete (pav_cfg : config .PavConfig , series_path : Path ,
182- check_tests : bool = False ) -> Union [dict , None ]:
183- """Check whether all the test sets in a series are complete.
188+ check_tests : bool = False ) -> Optional [Dict [str , float ]]:
189+ """Check whether all the test sets in a series are complete. If they are,
190+ returns a complete info dictionary containing the completion time.
191+
192+ :param pav_cfg: The Pavilion configuration object
193+ :param series_path: Path to the series data
184194 :param check_tests: Check tests for completion and set completion if all
185195 tests are complete. Will catch and ignore errors when setting completion."""
186196
@@ -215,7 +225,7 @@ def get_complete(pav_cfg: config.PavConfig, series_path: Path,
215225 # All tests exist, so now it's just a matter of waiting for all test sets
216226 # to complete (which they have if we're at this point)
217227 set_complete (series_path , latest )
218- return latest
228+ return { "complete" : latest }
219229
220230 if latest is None :
221231 try :
@@ -228,7 +238,7 @@ def get_complete(pav_cfg: config.PavConfig, series_path: Path,
228238 # been created though.
229239 if latest + SERIES_COMPLETE_TIMEOUT < time .time ():
230240 set_complete (series_path , latest )
231- return latest
241+ return { "complete" : latest }
232242
233243 return None
234244
0 commit comments