Skip to content

Commit a7eac3a

Browse files
fix: checking for double nested strings in gres and gpu settings (#251)
users ought to get an informative error message, if they request resources with `gres="'gpu:1'"` instead of `gres="gpu:1!` (or similarly for the `gpu` resource). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Enhanced error feedback for GPU and GRES argument validations, providing more specific messages to distinguish nested quotation issues from general format errors. - **Tests** - Added tests to verify error handling for nested string formats in GRES and GPU model arguments, ensuring accurate error messages are raised. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 1264de3 commit a7eac3a

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

snakemake_executor_plugin_slurm/utils.py

+28-9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ def set_gres_string(job: JobExecutorInterface) -> str:
5858
gres_re = re.compile(r"^[a-zA-Z0-9_]+(:[a-zA-Z0-9_]+)?:\d+$")
5959
# gpu model arguments can be of type "string"
6060
gpu_model_re = re.compile(r"^[a-zA-Z0-9_]+$")
61+
# any arguments should not start and end with ticks or
62+
# quotation marks:
63+
string_check = re.compile(r"^[^'\"].*[^'\"]$")
6164
# The Snakemake resources can be only be of type "int",
6265
# hence no further regex is needed.
6366

@@ -81,20 +84,36 @@ def set_gres_string(job: JobExecutorInterface) -> str:
8184
# Validate GRES format (e.g., "gpu:1", "gpu:tesla:2")
8285
gres = job.resources.gres
8386
if not gres_re.match(gres):
84-
raise WorkflowError(
85-
f"Invalid GRES format: {gres}. Expected format: "
86-
"'<name>:<number>' or '<name>:<type>:<number>' "
87-
"(e.g., 'gpu:1' or 'gpu:tesla:2')"
88-
)
87+
if not string_check.match(gres):
88+
raise WorkflowError(
89+
"GRES format should not be a nested string (start "
90+
"and end with ticks or quotation marks). "
91+
"Expected format: "
92+
"'<name>:<number>' or '<name>:<type>:<number>' "
93+
"(e.g., 'gpu:1' or 'gpu:tesla:2')"
94+
)
95+
else:
96+
raise WorkflowError(
97+
f"Invalid GRES format: {gres}. Expected format: "
98+
"'<name>:<number>' or '<name>:<type>:<number>' "
99+
"(e.g., 'gpu:1' or 'gpu:tesla:2')"
100+
)
89101
return f" --gres={job.resources.gres}"
90102

91103
if gpu_model and gpu_string:
92104
# validate GPU model format
93105
if not gpu_model_re.match(gpu_model):
94-
raise WorkflowError(
95-
f"Invalid GPU model format: {gpu_model}."
96-
" Expected format: '<name>' (e.g., 'tesla')"
97-
)
106+
if not string_check.match(gpu_model):
107+
raise WorkflowError(
108+
"GPU model format should not be a nested string (start "
109+
"and end with ticks or quotation marks). "
110+
"Expected format: '<name>' (e.g., 'tesla')"
111+
)
112+
else:
113+
raise WorkflowError(
114+
f"Invalid GPU model format: {gpu_model}."
115+
" Expected format: '<name>' (e.g., 'tesla')"
116+
)
98117
return f" --gpus={gpu_model}:{gpu_string}"
99118
elif gpu_model and not gpu_string:
100119
raise WorkflowError("GPU model is set, but no GPU number is given")

tests/tests.py

+36
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,42 @@ def test_both_gres_and_gpu_set(self, mock_job):
215215
):
216216
set_gres_string(job)
217217

218+
def test_nested_string_raise(self, mock_job):
219+
"""Test error case when gres is a nested string."""
220+
job = mock_job(gres="'gpu:1'")
221+
# Patch subprocess.Popen to simulate job submission
222+
with patch("subprocess.Popen") as mock_popen:
223+
# Configure the mock to simulate successful submission
224+
process_mock = MagicMock()
225+
process_mock.communicate.return_value = ("123", "")
226+
process_mock.returncode = 0
227+
mock_popen.return_value = process_mock
228+
229+
# Ensure the error is raised when both GRES and GPU are set
230+
with pytest.raises(
231+
WorkflowError,
232+
match="GRES format should not be a nested string",
233+
):
234+
set_gres_string(job)
235+
236+
def test_gpu_model_nested_string_raise(self, mock_job):
237+
"""Test error case when gpu_model is a nested string."""
238+
job = mock_job(gpu_model="'tesla'", gpu="2")
239+
# Patch subprocess.Popen to simulate job submission
240+
with patch("subprocess.Popen") as mock_popen:
241+
# Configure the mock to simulate successful submission
242+
process_mock = MagicMock()
243+
process_mock.communicate.return_value = ("123", "")
244+
process_mock.returncode = 0
245+
mock_popen.return_value = process_mock
246+
247+
# Ensure the error is raised when both GRES and GPU are set
248+
with pytest.raises(
249+
WorkflowError,
250+
match="GPU model format should not be a nested string",
251+
):
252+
set_gres_string(job)
253+
218254

219255
class TestSLURMResources(TestWorkflows):
220256
"""

0 commit comments

Comments
 (0)