Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/aiida_shell/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def launch_shell_job( # noqa: PLR0913
metadata: dict[str, t.Any] | None = None,
submit: bool = False,
resolve_command: bool = True,
monitors: dict[str, Data] | None = None,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be Dict, no?

Suggested change
monitors: dict[str, Data] | None = None,
monitors: dict[str, Dict] | None = None,

) -> tuple[dict[str, Data], ProcessNode]:
"""Launch a :class:`aiida_shell.ShellJob` job for the given command.

Expand All @@ -52,6 +53,8 @@ def launch_shell_job( # noqa: PLR0913
:param resolve_command: Whether to resolve the command to the absolute path of the executable. If set to ``True``,
the ``which`` command is executed on the target computer to attempt and determine the absolute path. Otherwise,
the command is set as the ``filepath_executable`` attribute of the created ``AbstractCode`` instance.
:param monitors: Optional dictionary of ``Data`` nodes to be used as monitors for the job (see AiiDA
documentation on how to define monitors).
:raises TypeError: If the value specified for ``metadata.options.computer`` is not a ``Computer``.
:raises ValueError: If ``resolve_command=True`` and the absolute path of the command on the computer could not be
determined.
Expand All @@ -69,6 +72,7 @@ def launch_shell_job( # noqa: PLR0913
parser=parser,
metadata=metadata,
resolve_command=resolve_command,
monitors=monitors,
)

if submit:
Expand All @@ -91,6 +95,7 @@ def prepare_shell_job_inputs( # noqa: PLR0913
parser: ParserFunctionType | str | None = None,
metadata: dict[str, t.Any] | None = None,
resolve_command: bool = True,
monitors: dict[str, Data] | None = None,
) -> dict[str, t.Any]:
"""Prepare inputs for the ShellJob based on the provided parameters.

Expand All @@ -110,6 +115,8 @@ def prepare_shell_job_inputs( # noqa: PLR0913
:param resolve_command: Whether to resolve the command to the absolute path of the executable. If set to ``True``,
the ``which`` command is executed on the target computer to attempt and determine the absolute path. Otherwise,
the command is set as the ``filepath_executable`` attribute of the created ``AbstractCode`` instance.
:param monitors: Optional dictionary of ``Data`` nodes to be used as monitors for the job (see AiiDA
documentation on how to define monitors).
:raises TypeError: If the value specified for ``metadata.options.computer`` is not a ``Computer``.
:raises ValueError: If ``resolve_command=True`` and the absolute path of the command on the computer could not be
determined.
Expand Down Expand Up @@ -148,6 +155,8 @@ def prepare_shell_job_inputs( # noqa: PLR0913
'parser': parser,
'metadata': metadata or {},
}
if monitors:
inputs['monitors'] = monitors

return inputs

Expand Down
2 changes: 1 addition & 1 deletion src/aiida_shell/parsers/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def parse_default_outputs(self, dirpath: pathlib.Path) -> ExitCode:
except FileNotFoundError:
stderr = ''
else:
stderr = node_stderr.get_content() # type: ignore[assignment]
stderr = node_stderr.get_content(mode='r')
self.out(ShellJob.FILENAME_STDERR, node_stderr)

filename_stdout = self.node.get_option('output_filename') or ShellJob.FILENAME_STDOUT
Expand Down
6 changes: 5 additions & 1 deletion tests/calculations/test_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,11 @@ def test_output_filename(generate_calc_job, generate_code, file_regression):
def test_filename_stdin(generate_calc_job, generate_code, file_regression):
"""Test the ``metadata.options.filename_stdin`` input."""
inputs = {
'code': generate_code('cat'),
# even if 'cat' would be more natural, we use `diff` to avoid issues
# in this specific test, because the exact path of the `cat` binary
# may differ across systems (Linux vs. MacOS), while `diff` seems
# to be (by default) more consistent (in /usr/bin).
'code': generate_code('diff'),
'arguments': List(['{filename}']),
'nodes': {'filename': SinglefileData.from_string('content')},
'metadata': {'options': {'filename_stdin': 'filename'}},
Expand Down
2 changes: 1 addition & 1 deletion tests/calculations/test_shell/test_filename_stdin.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ exec > _scheduler-stdout.txt
exec 2> _scheduler-stderr.txt


'/usr/bin/cat' < 'filename' > 'stdout' 2> 'stderr'
'/usr/bin/diff' < 'filename' > 'stdout' 2> 'stderr'

echo $? > status
5 changes: 4 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

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

def factory(command='/bin/true', computer_label='localhost', label=None, entry_point_name='core.shell'):
def factory(command=default_command, computer_label='localhost', label=None, entry_point_name='core.shell'):
"""Return a :class:`aiida_shell.data.code.ShellCode` instance, either already existing or created."""
label = label or str(uuid.uuid4())
computer = generate_computer(computer_label)
Expand Down
7 changes: 5 additions & 2 deletions tests/test_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from aiida_shell.calculations.shell import ShellJob
from aiida_shell.launch import launch_shell_job, prepare_computer

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


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

assert node.is_finished_ok
Expand Down Expand Up @@ -273,7 +276,7 @@ def job_function():
@pytest.mark.parametrize(
'resolve_command, executable',
(
(True, '/usr/bin/date'),
(True, DATE_COMMAND),
(False, 'date'),
),
)
Expand Down