Skip to content

Commit 2cf6a45

Browse files
committed
Adding support for AiiDA monitors
Now launch_shell_job allows to optionally set monitors which are simply passed to the underlying builder. Also, I am slighly adapting tests to ensure they can also run on a default MacOS machine (where default paths for common bash commands are a bit different, as well as the behaviour of some commands, such as the available flags of the `date` command...)
1 parent 64249d9 commit 2cf6a45

File tree

5 files changed

+24
-5
lines changed

5 files changed

+24
-5
lines changed

src/aiida_shell/launch.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def launch_shell_job( # noqa: PLR0913
3232
metadata: dict[str, t.Any] | None = None,
3333
submit: bool = False,
3434
resolve_command: bool = True,
35+
monitors: dict[str, Data] | None = None,
3536
) -> tuple[dict[str, Data], ProcessNode]:
3637
"""Launch a :class:`aiida_shell.ShellJob` job for the given command.
3738
@@ -52,6 +53,8 @@ def launch_shell_job( # noqa: PLR0913
5253
:param resolve_command: Whether to resolve the command to the absolute path of the executable. If set to ``True``,
5354
the ``which`` command is executed on the target computer to attempt and determine the absolute path. Otherwise,
5455
the command is set as the ``filepath_executable`` attribute of the created ``AbstractCode`` instance.
56+
:param monitors: Optional dictionary of ``Data`` nodes to be used as monitors for the job (see AiiDA
57+
documentation on how to define monitors).
5558
:raises TypeError: If the value specified for ``metadata.options.computer`` is not a ``Computer``.
5659
:raises ValueError: If ``resolve_command=True`` and the absolute path of the command on the computer could not be
5760
determined.
@@ -69,6 +72,7 @@ def launch_shell_job( # noqa: PLR0913
6972
parser=parser,
7073
metadata=metadata,
7174
resolve_command=resolve_command,
75+
monitors=monitors,
7276
)
7377

7478
if submit:
@@ -91,6 +95,7 @@ def prepare_shell_job_inputs( # noqa: PLR0913
9195
parser: ParserFunctionType | str | None = None,
9296
metadata: dict[str, t.Any] | None = None,
9397
resolve_command: bool = True,
98+
monitors: dict[str, Data] | None = None,
9499
) -> dict[str, t.Any]:
95100
"""Prepare inputs for the ShellJob based on the provided parameters.
96101
@@ -110,6 +115,8 @@ def prepare_shell_job_inputs( # noqa: PLR0913
110115
:param resolve_command: Whether to resolve the command to the absolute path of the executable. If set to ``True``,
111116
the ``which`` command is executed on the target computer to attempt and determine the absolute path. Otherwise,
112117
the command is set as the ``filepath_executable`` attribute of the created ``AbstractCode`` instance.
118+
:param monitors: Optional dictionary of ``Data`` nodes to be used as monitors for the job (see AiiDA
119+
documentation on how to define monitors).
113120
:raises TypeError: If the value specified for ``metadata.options.computer`` is not a ``Computer``.
114121
:raises ValueError: If ``resolve_command=True`` and the absolute path of the command on the computer could not be
115122
determined.
@@ -148,6 +155,8 @@ def prepare_shell_job_inputs( # noqa: PLR0913
148155
'parser': parser,
149156
'metadata': metadata or {},
150157
}
158+
if monitors:
159+
inputs['monitors'] = monitors
151160

152161
return inputs
153162

tests/calculations/test_shell.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,11 @@ def test_output_filename(generate_calc_job, generate_code, file_regression):
286286
def test_filename_stdin(generate_calc_job, generate_code, file_regression):
287287
"""Test the ``metadata.options.filename_stdin`` input."""
288288
inputs = {
289-
'code': generate_code('cat'),
289+
# even if 'cat' would be more natural, we use `diff` to avoid issues
290+
# in this specific test, because the exact path of the `cat` binary
291+
# may differ across systems (Linux vs. MacOS), while `diff` seems
292+
# to be (by default) more consistent (in /usr/bin).
293+
'code': generate_code('diff'),
290294
'arguments': List(['{filename}']),
291295
'nodes': {'filename': SinglefileData.from_string('content')},
292296
'metadata': {'options': {'filename_stdin': 'filename'}},

tests/calculations/test_shell/test_filename_stdin.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ exec > _scheduler-stdout.txt
33
exec 2> _scheduler-stderr.txt
44

55

6-
'/usr/bin/cat' < 'filename' > 'stdout' 2> 'stderr'
6+
'/usr/bin/diff' < 'filename' > 'stdout' 2> 'stderr'
77

88
echo $? > status

tests/conftest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33

44
import collections
5+
import shutil
56
import pathlib
67
import tempfile
78
import typing as t
@@ -170,8 +171,10 @@ def factory(label='localhost', hostname='localhost', scheduler_type='core.direct
170171
@pytest.fixture
171172
def generate_code(generate_computer):
172173
"""Return a :class:`aiida_shell.data.code.ShellCode` instance, either already existing or created."""
174+
default_command = shutil.which('true') # /bin/true on Linux, /usr/bin/true on macOS
175+
assert default_command is not None, 'The `true` command must be available on the system for the tests to run.'
173176

174-
def factory(command='/bin/true', computer_label='localhost', label=None, entry_point_name='core.shell'):
177+
def factory(command=default_command, computer_label='localhost', label=None, entry_point_name='core.shell'):
175178
"""Return a :class:`aiida_shell.data.code.ShellCode` instance, either already existing or created."""
176179
label = label or str(uuid.uuid4())
177180
computer = generate_computer(computer_label)

tests/test_launch.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
from aiida_shell.calculations.shell import ShellJob
1111
from aiida_shell.launch import launch_shell_job, prepare_computer
1212

13+
DATE_COMMAND = shutil.which('date')
14+
assert DATE_COMMAND is not None, 'The `date` command must be available in order to run the tests.'
15+
1316

1417
class ShellWorkChain(WorkChain):
1518
"""Implementation of :class:`aiida.engine.processes.workchains.workchain.WorkChain` that submits a ``ShellJob``."""
@@ -86,7 +89,7 @@ def test_arguments():
8689
shellfunction runs just before midnight and the comparison ``datetime`` call runs in the next day causing the test
8790
to fail, but that seems extremely unlikely.
8891
"""
89-
arguments = ['--iso-8601']
92+
arguments = ['-I'] # equivalent to --iso-8601, but supported also on MacOS
9093
results, node = launch_shell_job('date', arguments=arguments)
9194

9295
assert node.is_finished_ok
@@ -273,7 +276,7 @@ def job_function():
273276
@pytest.mark.parametrize(
274277
'resolve_command, executable',
275278
(
276-
(True, '/usr/bin/date'),
279+
(True, DATE_COMMAND),
277280
(False, 'date'),
278281
),
279282
)

0 commit comments

Comments
 (0)