Skip to content

Commit c65100b

Browse files
authored
Add pysqa command which raises an exception (#465)
* Add pysqa command which raises an exception * fix type hints * fix tests * another test * more fixes * add shell option
1 parent b41acba commit c65100b

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

executorlib/standalone/cache/queue.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
2-
from typing import List, Optional
2+
import subprocess
3+
from typing import List, Optional, Union
34

45
from pysqa import QueueAdapter
56

@@ -29,7 +30,11 @@ def execute_with_pysqa(
2930
"""
3031
if resource_dict is None:
3132
resource_dict = {"cwd": "."}
32-
qa = QueueAdapter(directory=config_directory, queue_type=backend)
33+
qa = QueueAdapter(
34+
directory=config_directory,
35+
queue_type=backend,
36+
execute_command=_pysqa_execute_command,
37+
)
3338
submit_kwargs = {
3439
"command": " ".join(command),
3540
"dependency_list": [str(qid) for qid in task_dependent_lst],
@@ -47,3 +52,39 @@ def execute_with_pysqa(
4752
del resource_dict[k]
4853
submit_kwargs.update(resource_dict)
4954
return qa.submit_job(**submit_kwargs)
55+
56+
57+
def _pysqa_execute_command(
58+
commands: str,
59+
working_directory: Optional[str] = None,
60+
split_output: bool = True,
61+
shell: bool = False,
62+
error_filename: str = "pysqa.err",
63+
) -> Union[str, List[str]]:
64+
"""
65+
A wrapper around the subprocess.check_output function. Modified from pysqa to raise an exception if the subprocess
66+
fails to submit the job to the queue.
67+
68+
Args:
69+
commands (str): The command(s) to be executed on the command line
70+
working_directory (str, optional): The directory where the command is executed. Defaults to None.
71+
split_output (bool, optional): Boolean flag to split newlines in the output. Defaults to True.
72+
shell (bool, optional): Additional switch to convert commands to a single string. Defaults to False.
73+
error_filename (str, optional): In case the execution fails, the output is written to this file. Defaults to "pysqa.err".
74+
75+
Returns:
76+
Union[str, List[str]]: Output of the shell command either as a string or as a list of strings
77+
"""
78+
if shell and isinstance(commands, list):
79+
commands = " ".join(commands)
80+
out = subprocess.check_output(
81+
commands,
82+
cwd=working_directory,
83+
stderr=subprocess.STDOUT,
84+
universal_newlines=True,
85+
shell=not isinstance(commands, list),
86+
)
87+
if out is not None and split_output:
88+
return out.split("\n")
89+
else:
90+
return out

tests/test_pysqa_subprocess.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import unittest
2+
3+
try:
4+
from executorlib.standalone.cache.queue import _pysqa_execute_command
5+
6+
skip_pysqa_test = False
7+
except ImportError:
8+
skip_pysqa_test = True
9+
10+
11+
@unittest.skipIf(
12+
skip_pysqa_test, "pysqa is not installed, so the pysqa tests are skipped."
13+
)
14+
class TestPysqaExecuteCommand(unittest.TestCase):
15+
def test_pysqa_execute_command_list(self):
16+
out = _pysqa_execute_command(
17+
commands=["echo", "test"],
18+
working_directory=None,
19+
split_output=True,
20+
shell=True,
21+
error_filename="pysqa.err",
22+
)
23+
self.assertEqual(len(out), 2)
24+
self.assertEqual("test", out[0])
25+
26+
def test_pysqa_execute_command_string(self):
27+
out = _pysqa_execute_command(
28+
commands="echo test",
29+
working_directory=None,
30+
split_output=False,
31+
shell=False,
32+
error_filename="pysqa.err",
33+
)
34+
self.assertEqual(len(out), 5)
35+
self.assertEqual("test\n", out)
36+
37+
def test_pysqa_execute_command_fail(self):
38+
with self.assertRaises(FileNotFoundError):
39+
_pysqa_execute_command(
40+
commands=["no/executable/available"],
41+
working_directory=None,
42+
split_output=True,
43+
shell=False,
44+
error_filename="pysqa.err",
45+
)

0 commit comments

Comments
 (0)