snakemake-executor-plugin-slurm 1.6.1__py3-none-any.whl → 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of snakemake-executor-plugin-slurm might be problematic. Click here for more details.
- snakemake_executor_plugin_slurm/__init__.py +44 -17
- snakemake_executor_plugin_slurm/submit_string.py +35 -17
- {snakemake_executor_plugin_slurm-1.6.1.dist-info → snakemake_executor_plugin_slurm-1.8.0.dist-info}/METADATA +4 -2
- snakemake_executor_plugin_slurm-1.8.0.dist-info/RECORD +8 -0
- {snakemake_executor_plugin_slurm-1.6.1.dist-info → snakemake_executor_plugin_slurm-1.8.0.dist-info}/WHEEL +1 -1
- snakemake_executor_plugin_slurm-1.6.1.dist-info/RECORD +0 -8
- {snakemake_executor_plugin_slurm-1.6.1.dist-info → snakemake_executor_plugin_slurm-1.8.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -140,6 +140,14 @@ class ExecutorSettings(ExecutorSettingsBase):
|
|
|
140
140
|
"This flag has no effect, if not set.",
|
|
141
141
|
},
|
|
142
142
|
)
|
|
143
|
+
qos: Optional[str] = field(
|
|
144
|
+
default=None,
|
|
145
|
+
metadata={
|
|
146
|
+
"help": "If set, the given QoS will be used for job submission.",
|
|
147
|
+
"env_var": False,
|
|
148
|
+
"required": False,
|
|
149
|
+
},
|
|
150
|
+
)
|
|
143
151
|
reservation: Optional[str] = field(
|
|
144
152
|
default=None,
|
|
145
153
|
metadata={
|
|
@@ -299,7 +307,7 @@ class Executor(RemoteExecutor):
|
|
|
299
307
|
"run_uuid": self.run_uuid,
|
|
300
308
|
"slurm_logfile": slurm_logfile,
|
|
301
309
|
"comment_str": comment_str,
|
|
302
|
-
"account": self.get_account_arg(job),
|
|
310
|
+
"account": next(self.get_account_arg(job)),
|
|
303
311
|
"partition": self.get_partition_arg(job),
|
|
304
312
|
"workdir": self.workflow.workdir_init,
|
|
305
313
|
}
|
|
@@ -309,6 +317,9 @@ class Executor(RemoteExecutor):
|
|
|
309
317
|
if self.workflow.executor_settings.requeue:
|
|
310
318
|
call += " --requeue"
|
|
311
319
|
|
|
320
|
+
if self.workflow.executor_settings.qos:
|
|
321
|
+
call += f" --qos={self.workflow.executor_settings.qos}"
|
|
322
|
+
|
|
312
323
|
if self.workflow.executor_settings.reservation:
|
|
313
324
|
call += f" --reservation={self.workflow.executor_settings.reservation}"
|
|
314
325
|
|
|
@@ -657,10 +668,21 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
657
668
|
else raises an error - implicetly.
|
|
658
669
|
"""
|
|
659
670
|
if job.resources.get("slurm_account"):
|
|
660
|
-
#
|
|
661
|
-
#
|
|
662
|
-
|
|
663
|
-
|
|
671
|
+
# split the account upon ',' and whitespace, to allow
|
|
672
|
+
# multiple accounts being given
|
|
673
|
+
accounts = [
|
|
674
|
+
a for a in re.split(r"[,\s]+", job.resources.slurm_account) if a
|
|
675
|
+
]
|
|
676
|
+
for account in accounts:
|
|
677
|
+
# here, we check whether the given or guessed account is valid
|
|
678
|
+
# if not, a WorkflowError is raised
|
|
679
|
+
self.test_account(account)
|
|
680
|
+
# sbatch only allows one account per submission
|
|
681
|
+
# yield one after the other, if multiple were given
|
|
682
|
+
# we have to quote the account, because it might
|
|
683
|
+
# contain build-in shell commands - see issue #354
|
|
684
|
+
for account in accounts:
|
|
685
|
+
yield f" -A {shlex.quote(account)}"
|
|
664
686
|
else:
|
|
665
687
|
if self._fallback_account_arg is None:
|
|
666
688
|
self.logger.warning("No SLURM account given, trying to guess.")
|
|
@@ -668,7 +690,7 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
668
690
|
if account:
|
|
669
691
|
self.logger.warning(f"Guessed SLURM account: {account}")
|
|
670
692
|
self.test_account(f"{account}")
|
|
671
|
-
self._fallback_account_arg = f" -A {account}"
|
|
693
|
+
self._fallback_account_arg = f" -A {shlex.quote(account)}"
|
|
672
694
|
else:
|
|
673
695
|
self.logger.warning(
|
|
674
696
|
"Unable to guess SLURM account. Trying to proceed without."
|
|
@@ -676,7 +698,7 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
676
698
|
self._fallback_account_arg = (
|
|
677
699
|
"" # no account specific args for sbatch
|
|
678
700
|
)
|
|
679
|
-
|
|
701
|
+
yield self._fallback_account_arg
|
|
680
702
|
|
|
681
703
|
def get_partition_arg(self, job: JobExecutorInterface):
|
|
682
704
|
"""
|
|
@@ -691,7 +713,9 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
691
713
|
self._fallback_partition = self.get_default_partition(job)
|
|
692
714
|
partition = self._fallback_partition
|
|
693
715
|
if partition:
|
|
694
|
-
|
|
716
|
+
# we have to quote the partition, because it might
|
|
717
|
+
# contain build-in shell commands
|
|
718
|
+
return f" -p {shlex.quote(partition)}"
|
|
695
719
|
else:
|
|
696
720
|
return ""
|
|
697
721
|
|
|
@@ -719,32 +743,35 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
719
743
|
"""
|
|
720
744
|
tests whether the given account is registered, raises an error, if not
|
|
721
745
|
"""
|
|
722
|
-
|
|
746
|
+
# first we need to test with sacctmgr because sshare might not
|
|
747
|
+
# work in a multicluster environment
|
|
748
|
+
cmd = f'sacctmgr -n -s list user "{os.environ["USER"]}" format=account%256'
|
|
749
|
+
sacctmgr_report = sshare_report = ""
|
|
723
750
|
try:
|
|
724
751
|
accounts = subprocess.check_output(
|
|
725
752
|
cmd, shell=True, text=True, stderr=subprocess.PIPE
|
|
726
753
|
)
|
|
727
754
|
except subprocess.CalledProcessError as e:
|
|
728
|
-
|
|
755
|
+
sacctmgr_report = (
|
|
729
756
|
"Unable to test the validity of the given or guessed"
|
|
730
|
-
f" SLURM account '{account}' with
|
|
757
|
+
f" SLURM account '{account}' with sacctmgr: {e.stderr}."
|
|
731
758
|
)
|
|
732
759
|
accounts = ""
|
|
733
760
|
|
|
734
761
|
if not accounts.strip():
|
|
735
|
-
cmd =
|
|
762
|
+
cmd = "sshare -U --format Account%256 --noheader"
|
|
736
763
|
try:
|
|
737
764
|
accounts = subprocess.check_output(
|
|
738
765
|
cmd, shell=True, text=True, stderr=subprocess.PIPE
|
|
739
766
|
)
|
|
740
767
|
except subprocess.CalledProcessError as e:
|
|
741
|
-
|
|
768
|
+
sshare_report = (
|
|
742
769
|
"Unable to test the validity of the given or guessed "
|
|
743
|
-
f"SLURM account '{account}' with
|
|
770
|
+
f"SLURM account '{account}' with sshare: {e.stderr}."
|
|
744
771
|
)
|
|
745
772
|
raise WorkflowError(
|
|
746
|
-
f"The '
|
|
747
|
-
f"and likewise '
|
|
773
|
+
f"The 'sacctmgr' reported: '{sacctmgr_report}' "
|
|
774
|
+
f"and likewise 'sshare' reported: '{sshare_report}'."
|
|
748
775
|
)
|
|
749
776
|
|
|
750
777
|
# The set() has been introduced during review to eliminate
|
|
@@ -753,7 +780,7 @@ We leave it to SLURM to resume your job(s)"""
|
|
|
753
780
|
|
|
754
781
|
if not accounts:
|
|
755
782
|
self.logger.warning(
|
|
756
|
-
f"Both '
|
|
783
|
+
f"Both 'sacctmgr' and 'sshare' returned empty results for account "
|
|
757
784
|
f"'{account}'. Proceeding without account validation."
|
|
758
785
|
)
|
|
759
786
|
return ""
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
from snakemake_executor_plugin_slurm_jobstep import get_cpu_setting
|
|
2
2
|
from types import SimpleNamespace
|
|
3
|
+
import shlex
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def safe_quote(value):
|
|
7
|
+
"""
|
|
8
|
+
Safely quote a parameter value using shlex.quote.
|
|
9
|
+
Handles None values and converts to string if needed.
|
|
10
|
+
Returns empty quotes for empty strings.
|
|
11
|
+
"""
|
|
12
|
+
str_value = str(value)
|
|
13
|
+
if str_value == "":
|
|
14
|
+
return "''"
|
|
15
|
+
return shlex.quote(str_value)
|
|
3
16
|
|
|
4
17
|
|
|
5
18
|
def get_submit_command(job, params):
|
|
@@ -10,37 +23,41 @@ def get_submit_command(job, params):
|
|
|
10
23
|
params = SimpleNamespace(**params)
|
|
11
24
|
|
|
12
25
|
call = (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
f"--job-name {params.run_uuid} "
|
|
16
|
-
f
|
|
17
|
-
|
|
18
|
-
f
|
|
26
|
+
"sbatch "
|
|
27
|
+
"--parsable "
|
|
28
|
+
f"--job-name {safe_quote(params.run_uuid)} "
|
|
29
|
+
f"--output {safe_quote(params.slurm_logfile)} "
|
|
30
|
+
"--export=ALL "
|
|
31
|
+
f"--comment {safe_quote(params.comment_str)}"
|
|
19
32
|
)
|
|
20
33
|
|
|
21
34
|
# No accout or partition checking is required, here.
|
|
22
35
|
# Checking is done in the submit function.
|
|
23
36
|
|
|
24
37
|
# here, only the string is used, as it already contains
|
|
25
|
-
#
|
|
38
|
+
# "-A '{account_name}'"
|
|
26
39
|
call += f" {params.account}"
|
|
27
40
|
# here, only the string is used, as it already contains
|
|
28
|
-
#
|
|
41
|
+
# "- p '{partition_name}'"
|
|
29
42
|
call += f" {params.partition}"
|
|
30
43
|
|
|
31
44
|
if job.resources.get("clusters"):
|
|
32
|
-
call += f" --clusters {job.resources.clusters}"
|
|
45
|
+
call += f" --clusters {safe_quote(job.resources.clusters)}"
|
|
33
46
|
|
|
34
47
|
if job.resources.get("runtime"):
|
|
35
|
-
call += f" -t {job.resources.runtime}"
|
|
48
|
+
call += f" -t {safe_quote(job.resources.runtime)}"
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
# Both, constraint and qos are optional.
|
|
51
|
+
# If not set, they will not be added to the sbatch call.
|
|
52
|
+
# If explicitly set to an empty string,
|
|
53
|
+
# `--constraint ''` or `--qos ''` will be added.
|
|
54
|
+
constraint = job.resources.get("constraint")
|
|
55
|
+
if constraint is not None:
|
|
56
|
+
call += f" -C {safe_quote(constraint)}"
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
58
|
+
qos = job.resources.get("qos")
|
|
59
|
+
if qos is not None:
|
|
60
|
+
call += f" --qos={safe_quote(qos)}"
|
|
44
61
|
|
|
45
62
|
if job.resources.get("mem_mb_per_cpu"):
|
|
46
63
|
call += f" --mem-per-cpu {job.resources.mem_mb_per_cpu}"
|
|
@@ -77,6 +94,7 @@ def get_submit_command(job, params):
|
|
|
77
94
|
# ensure that workdir is set correctly
|
|
78
95
|
# use short argument as this is the same in all slurm versions
|
|
79
96
|
# (see https://github.com/snakemake/snakemake/issues/2014)
|
|
80
|
-
|
|
97
|
+
if params.workdir:
|
|
98
|
+
call += f" -D {safe_quote(params.workdir)}"
|
|
81
99
|
|
|
82
100
|
return call
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: snakemake-executor-plugin-slurm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: A Snakemake executor plugin for submitting jobs to a SLURM cluster.
|
|
5
5
|
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Keywords: snakemake,plugin,executor,cluster,slurm
|
|
7
8
|
Author: Christian Meesters
|
|
8
9
|
Author-email: meesters@uni-mainz.de
|
|
@@ -12,6 +13,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
17
|
Requires-Dist: numpy (>=1.26.4,<3)
|
|
16
18
|
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
17
19
|
Requires-Dist: snakemake-executor-plugin-slurm-jobstep (>=0.3.0,<0.4.0)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
snakemake_executor_plugin_slurm/__init__.py,sha256=G40Rbm62GFQF7bo38OJBFEFAxa4BLYeNO66wPQuki-c,34755
|
|
2
|
+
snakemake_executor_plugin_slurm/efficiency_report.py,sha256=crPfJDK4NojfRbu_wEw3ZmC3suMRABr5r-1rO5q3WEo,7429
|
|
3
|
+
snakemake_executor_plugin_slurm/submit_string.py,sha256=12DaJ9BIqEMC19dKuViPU8W5mZRjBRtNDQQu7M-iEjM,3448
|
|
4
|
+
snakemake_executor_plugin_slurm/utils.py,sha256=7XVXtzu7bg_89wWZisW-Zk7TNQyEgK4v_y4Y3F9uOwc,4491
|
|
5
|
+
snakemake_executor_plugin_slurm-1.8.0.dist-info/METADATA,sha256=8-ktC0sGhHDPOAyxpFl1LwWc7wPueZ2PxREKrQguhME,1507
|
|
6
|
+
snakemake_executor_plugin_slurm-1.8.0.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
|
|
7
|
+
snakemake_executor_plugin_slurm-1.8.0.dist-info/licenses/LICENSE,sha256=YVc4xTLWMqGfFL36120k7rzXtsT6e4RkJsh68VVn12s,1076
|
|
8
|
+
snakemake_executor_plugin_slurm-1.8.0.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
snakemake_executor_plugin_slurm/__init__.py,sha256=gQA7SwXAcpXAovDC7jlCKczjd6L3gLb-n37rGSm1MY8,33570
|
|
2
|
-
snakemake_executor_plugin_slurm/efficiency_report.py,sha256=crPfJDK4NojfRbu_wEw3ZmC3suMRABr5r-1rO5q3WEo,7429
|
|
3
|
-
snakemake_executor_plugin_slurm/submit_string.py,sha256=Cn9qopyQwBqs1MvZFxSyRR_7mZzCVj8_vO_JNzbiqew,2896
|
|
4
|
-
snakemake_executor_plugin_slurm/utils.py,sha256=7XVXtzu7bg_89wWZisW-Zk7TNQyEgK4v_y4Y3F9uOwc,4491
|
|
5
|
-
snakemake_executor_plugin_slurm-1.6.1.dist-info/LICENSE,sha256=YVc4xTLWMqGfFL36120k7rzXtsT6e4RkJsh68VVn12s,1076
|
|
6
|
-
snakemake_executor_plugin_slurm-1.6.1.dist-info/METADATA,sha256=12IQgnU3tuz2cQ6N6iqhyzSmR7BD_mt9HWfenEse2r4,1434
|
|
7
|
-
snakemake_executor_plugin_slurm-1.6.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
8
|
-
snakemake_executor_plugin_slurm-1.6.1.dist-info/RECORD,,
|
|
File without changes
|