diff --git a/CHANGELOG.md b/CHANGELOG.md index b3db3b72..4c0b580b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ +## v2.1.0 + + - New CLI option `execution` that allows for resuming executions more easily + - Fix issue that prevented the status.json information to be written + ## v2.0.1 - Improved Slurm engine diff --git a/src/machinable/storage/component.py b/src/machinable/storage/component.py index 9f986da6..e8bd4bb1 100644 --- a/src/machinable/storage/component.py +++ b/src/machinable/storage/component.py @@ -128,17 +128,17 @@ def output(self): @property def records(self): """Returns the record interface""" - return self.get_records_writer("default") + return self.get_records("default") def has_records(self, scope="default"): """Returns True if records of given scope exist""" return bool(self.file(f"records/{scope}.p", default=False)) - def get_records_writer(self, scope=None): - """Returns a record writer + def get_records(self, scope=None): + """Returns a record collection # Arguments - scope: The name of the record writer + scope: The name of the record scope """ if scope is None: # return list of available scopes @@ -148,7 +148,9 @@ def get_records_writer(self, scope=None): return [s[:-5] for s in scopes if s.endswith(".json")] except: return [] - return RecordCollection(self.file(f"records/{scope}.p", reload=self.is_alive())) + return RecordCollection( + self.file(f"records/{scope}.p", default=[], reload=self.is_alive()) + ) @property def started_at(self): diff --git a/src/machinable/store/store.py b/src/machinable/store/store.py index c6e8082a..204dc018 100644 --- a/src/machinable/store/store.py +++ b/src/machinable/store/store.py @@ -8,6 +8,7 @@ from fs import open_fs from ..utils.dicts import serialize, update_dict +from ..utils.formatting import exception_to_str from .log import Log from .record import Record @@ -150,7 +151,7 @@ def __init__(self, config=None, component=None): self._status = dict() self._status["started_at"] = str(pendulum.now()) self._status["finished_at"] = False - self.refresh_status() + self.refresh_status(log_errors=True) if not self.config["url"].startswith("mem://"): OutputRedirection.apply( @@ -161,7 +162,7 @@ def destroy(self): """Destroys the store instance""" # write finished status (not triggered in the case of an unhandled exception) self._status["finished_at"] = str(pendulum.now()) - self.refresh_status() + self.refresh_status(log_errors=True) OutputRedirection.revert() @@ -182,16 +183,24 @@ def local_directory(self, append=""): self.config["url"].split("osfs://")[-1], self.get_path(append) ) - def refresh_status(self): + def refresh_status(self, log_errors=False): """Updates the status.json file with a heartbeat at the current time """ - if not self.config.get("components", None): - return + if not self.config.get("component", None): + return False + try: self._status["heartbeat_at"] = str(pendulum.now()) self.write("status.json", self._status, overwrite=True, _meta=True) - except: - pass + except (IOError, Exception) as ex: + if log_errors: + self.log.error( + f"Could not write status information. {exception_to_str(ex)}" + ) + + return ex + + return True def get_record_writer(self, scope): """Creates or returns an instance of a record writer diff --git a/tests/storage/storage_test.py b/tests/storage/storage_test.py index f379a668..c57c2f54 100644 --- a/tests/storage/storage_test.py +++ b/tests/storage/storage_test.py @@ -37,7 +37,7 @@ def test_storage_component_interface(): assert "test" in comp.store() assert len(comp.store()["$files"]) assert len(comp.host) == 8 - assert len(comp.get_records_writer()) == 2 + assert len(comp.get_records()) == 2 comp = ml.Storage(STORAGE_DIRECTORY).find("TTTTTT") assert comp.components.first().experiment.id == "TTTTTT" @@ -46,7 +46,7 @@ def test_storage_component_interface(): def test_storage_records_interface(): obs = ml.Storage(STORAGE_DIRECTORY).find("tttttt").components.first() records = obs.records - custom = obs.get_records_writer("validation") + custom = obs.get_records("validation") assert custom.sum("iteration") == 15 assert records.as_dataframe().size > 0