forked from mdekauwe/CABLE_benchmarking
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Log status of fluxsite and comparison runs
This change introduces a State object as a minimal way of having state persist between separate processes. This is necessary for correctly showing the status of fluxsite and comparison runs as these tasks are run inside child processes which do not share the same data structures in the parent process.
- Loading branch information
1 parent
bb20f5e
commit 4f4e54d
Showing
7 changed files
with
141 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from pathlib import Path | ||
|
||
from benchcab.internal import STATE_PREFIX | ||
|
||
|
||
class StateAttributeError(Exception): | ||
"""Exception class for signalling state attribute errors.""" | ||
|
||
|
||
class State: | ||
"""Stores state which persists on the file system.""" | ||
|
||
def __init__(self, state_dir: Path) -> None: | ||
"""Instantiate a State object. | ||
Parameters | ||
---------- | ||
state_dir: Path | ||
Path to the directory in which state is stored. If the specified | ||
directory does not exist, create the directory. | ||
""" | ||
self.state_dir = state_dir | ||
self.state_dir.mkdir(parents=True, exist_ok=True) | ||
|
||
def reset(self): | ||
"""Clear all state attributes.""" | ||
for path in self.state_dir.glob(f"{STATE_PREFIX}*"): | ||
path.unlink() | ||
|
||
def set(self, attr: str): | ||
"""Set state attribute.""" | ||
(self.state_dir / (STATE_PREFIX + attr)).touch() | ||
|
||
def is_set(self, attr: str): | ||
"""Return True if the state attribute has been set, False otherwise.""" | ||
return (self.state_dir / (STATE_PREFIX + attr)).exists() | ||
|
||
def get(self) -> str: | ||
"""Get the state of the most recent state attribute.""" | ||
attrs = list(self.state_dir.glob(f"{STATE_PREFIX}*")) | ||
|
||
def get_mtime(path: Path): | ||
return path.stat().st_mtime | ||
|
||
attrs.sort(key=get_mtime) | ||
try: | ||
return attrs.pop().name.removeprefix(STATE_PREFIX) | ||
except IndexError as exc: | ||
msg = "No attributes have been set." | ||
raise StateAttributeError(msg) from exc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import time | ||
from pathlib import Path | ||
|
||
import pytest | ||
from benchcab.utils.state import State, StateAttributeError | ||
|
||
|
||
@pytest.fixture() | ||
def state(): | ||
"""Return a State object.""" | ||
return State(state_dir=Path("my_state")) | ||
|
||
|
||
def test_state_is_set(state): | ||
"""Success case: test state is set.""" | ||
state.set("foo") | ||
assert state.is_set("foo") | ||
|
||
|
||
def test_state_reset(state): | ||
"""Success case: test state is reset.""" | ||
state.set("foo") | ||
state.reset() | ||
assert not state.is_set("foo") | ||
|
||
|
||
def test_state_get(state): | ||
"""Success case: test get() returns the most recent state attribute.""" | ||
state.set("foo") | ||
# This is done so that time stamps can be resolved between state attributes | ||
time.sleep(0.01) | ||
state.set("bar") | ||
assert state.get() == "bar" | ||
|
||
|
||
def test_state_get_raises_exception(state): | ||
"""Failure case: test get() raises an exception when no attributes are set.""" | ||
with pytest.raises(StateAttributeError): | ||
state.get() |