Skip to content

Commit

Permalink
Allow tracking of component-specific execution data (#460)
Browse files Browse the repository at this point in the history
  • Loading branch information
frthjf committed Jun 21, 2023
1 parent 81fd098 commit b2c7a11
Show file tree
Hide file tree
Showing 31 changed files with 946 additions and 613 deletions.
2 changes: 1 addition & 1 deletion docs/examples/slurm-and-mpi-execution/mpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Config:
def __call__(self):
for executable in self.pending_executables:
script_file = self.save_file(
f"mpi-{executable.id}.sh",
[executable, "mpi.sh"],
executable.dispatch_code(),
)
st = os.stat(script_file)
Expand Down
20 changes: 12 additions & 8 deletions docs/examples/slurm-and-mpi-execution/slurm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,28 @@
class Slurm(Execution):
def __call__(self):
script = "#!/usr/bin/env bash\n"
for component in self.pending_executables:
resources = component.resources()
for executable in self.pending_executables:
resources = executable.resources()
if "--job-name" not in resources:
resources["--job-name"] = f"{component.id}"
resources["--job-name"] = f"{executable.id}"
if "--output" not in resources:
resources["--output"] = component.local_directory("output.log")
resources["--output"] = self.local_directory(
executable.id, "output.log"
)
if "--open-mode" not in resources:
resources["--open-mode"] = "append"

sbatch_arguments = []
for k, v in resources.items():
if not k.startswith("--"):
continue
line = "#SBATCH " + k
if v not in [None, True]:
line += f"={v}"
sbatch_arguments.append(line)
script += "\n".join(sbatch_arguments) + "\n"

script += component.dispatch_code()
script += executable.dispatch_code()

# submit to slurm
process = subprocess.Popen(
Expand All @@ -50,13 +54,13 @@ def __call__(self):
except ValueError:
job_id = False
print(
f"{output} for component {component.id} ({component.local_directory()})"
f"{output} for component {executable.id} ({executable.local_directory()})"
)

# save job information
self.save_file(
filepath="slurm.json",
data={
[executable, "slurm.json"],
{
"job_id": job_id,
"cmd": sbatch_arguments,
"script": script,
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/slurm-and-mpi-execution/test_mpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ def test_mpi_execution(tmp_path):
component = MpiExample()
with Execution.get("mpi"):
component.launch()
assert component.is_finished()
assert component.execution.is_finished()
assert component.load_file("test.txt") == "hello"
2 changes: 1 addition & 1 deletion docs/examples/slurm-and-mpi-execution/test_slurm.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_slurm_execution(tmp_path):
component.launch()

for _ in range(60):
if component.is_finished():
if component.execution.is_finished():
assert "Hello world from Slurm" in component.output()
assert (
component.load_file("test_run.json")["success"] is True
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Downloading 'mnist' ...
If the execution is successful, the component is marked as finished.

```python
>>> mnist.is_finished()
>>> mnist.execution.is_finished()
True
```

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class EstimatePi(Component):
)

def summary(self):
if self.is_finished():
if self.execution.is_finished():
print(
f"After {self.config.samples} samples, "
f"PI is approximately {self.load_file('result.json')['pi']}."
Expand Down
253 changes: 131 additions & 122 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ flatten-dict = "^0.4"
jsonlines = "^3.1"
pydantic = "^1.10.8"
arrow = "^1.2"
importlib-metadata = {version = "^6.6", python = "<3.8"}
importlib-metadata = {version = "^6.7", python = "<3.8"}
omegaconf = "^2.3.0"
dill = "^0.3.6"
typing-extensions = {version = "^4.5.0", python = "<3.11"}
Expand All @@ -40,7 +40,7 @@ pyupgrade = "^3.3"
black = "^23.3.0"
pytest = "^7.3"
pre-commit = "^2.21.0"
editorconfig-checker = "^2.7.1"
editorconfig-checker = "^2.7.2"
pytest-cov = "^4.1.0"

[tool.poetry.extras]
Expand Down
2 changes: 1 addition & 1 deletion src/machinable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
def get(
module: Union[str, Element, None] = None,
version: VersionType = None,
predicate: Optional[str] = get_settings().default_predicate,
predicate: Optional[str] = "$",
**kwargs,
) -> Interface:
return Interface.get(module, version, predicate, **kwargs)
Expand Down
15 changes: 7 additions & 8 deletions src/machinable/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from json import dumps
from pprint import pprint

from machinable.settings import get_settings
from machinable.types import VersionType

long = int
Expand Down Expand Up @@ -1384,7 +1383,7 @@ def filter_by_predicate(
self,
module: str,
version: VersionType = None,
predicate: str = get_settings().default_predicate,
predicate: str = "$",
**kwargs,
):
from machinable import Element
Expand All @@ -1407,7 +1406,7 @@ def singleton(
self,
module: str,
version: VersionType = None,
predicate: str = get_settings().default_predicate,
predicate: str = "$",
**kwargs,
) -> Union[Any, "Component"]:
from machinable import Element
Expand Down Expand Up @@ -1445,6 +1444,11 @@ def launch(self) -> "ComponentCollection":

return self


class ExecutionCollection(ElementCollection):
def __str__(self):
return f"Executions <{len(self.items)}>"

def status(self, status="started"):
"""Filters the collection by a status attribute
Expand All @@ -1455,8 +1459,3 @@ def status(self, status="started"):
return self.filter(lambda item: getattr(item, "is_" + status)())
except AttributeError as _ex:
raise ValueError(f"Invalid status field: {status}") from _ex


class ExecutionCollection(ElementCollection):
def __str__(self):
return f"Executions <{len(self.items)}>"
Loading

0 comments on commit b2c7a11

Please sign in to comment.