diff --git a/snakemake/cli.py b/snakemake/cli.py index 10d0378fd..3a567656d 100644 --- a/snakemake/cli.py +++ b/snakemake/cli.py @@ -81,7 +81,7 @@ def parse_set_resources(args): assignments = defaultdict(dict) if args is not None: for entry in args: - key, value = parse_key_value_arg(entry, errmsg=errmsg) + key, value = parse_key_value_arg(entry, errmsg=errmsg, strip_quotes=False) key = key.split(":") if len(key) != 2: raise ValueError(errmsg) diff --git a/snakemake/common/__init__.py b/snakemake/common/__init__.py index 20f216860..07939f2ad 100644 --- a/snakemake/common/__init__.py +++ b/snakemake/common/__init__.py @@ -60,12 +60,13 @@ def mb_to_mib(mb): return int(math.ceil(mb * 0.95367431640625)) -def parse_key_value_arg(arg, errmsg): +def parse_key_value_arg(arg, errmsg, strip_quotes=True): try: key, val = arg.split("=", 1) except ValueError: raise ValueError(errmsg + f" (Unparseable value: {repr(arg)})") - val = val.strip("'\"") + if strip_quotes: + val = val.strip("'\"") return key, val diff --git a/snakemake/resources.py b/snakemake/resources.py index 3c1ef9f06..98a5d0c4b 100644 --- a/snakemake/resources.py +++ b/snakemake/resources.py @@ -532,10 +532,10 @@ def generic_callable(val, threads_arg, **kwargs): if not is_file_not_found_error(e, kwargs["input"]): # Missing input files are handled by the caller raise WorkflowError( - "Failed to evaluate default resources value " + "Failed to evaluate resources value " f"'{val}'.\n" " String arguments may need additional " - "quoting. Ex: --default-resources " + "quoting. E.g.: --default-resources " "\"tmpdir='/home/user/tmp'\".", e, ) diff --git a/tests/Snakefile b/tests/Snakefile deleted file mode 100644 index f4764c34f..000000000 --- a/tests/Snakefile +++ /dev/null @@ -1,33 +0,0 @@ -localrules: all, clean - -rule all: - input: "pi.calc" - -rule clean: - shell: "rm -f pi.calc" - -rule compile: - input: "pi_MPI.c" - output: temp("pi_MPI") - resources: - walltime_minutes=10, - partition="smp", - tasks=1, - threads=1, - mem_mb_per_cpu=1800, - envmodules: "mpi/OpenMPI/4.0.5-GCC-10.2.0" - shell: - 'mpicc -o {output} {input}' - -rule calc_pi: - envmodules: "mpi/OpenMPI/4.0.5-GCC-10.2.0" - input: "pi_MPI" - output: "pi.calc" - resources: - nodes=2, - mem_mb=57000, - walltime_minutes=10, - tasks=2, - partition="parallel", - mpi=True, - shell: "{input} {output}" diff --git a/tests/test_resource_string_in_cli_or_profile/Snakefile b/tests/test_resource_string_in_cli_or_profile/Snakefile new file mode 100644 index 000000000..fc0b998d3 --- /dev/null +++ b/tests/test_resource_string_in_cli_or_profile/Snakefile @@ -0,0 +1,9 @@ +# fails when submitted as +# $ snakemake --executor slurm -j2 --workflow-profile ./profiles/ --default-resources slurm_account=m2_zdvhpc + +rule all: + input: "a.out" + +rule test1: + output: "a.out" + shell: "touch {output}" diff --git a/tests/test_resource_string_in_cli_or_profile/expected-results/a.out b/tests/test_resource_string_in_cli_or_profile/expected-results/a.out new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_resource_string_in_cli_or_profile/profiles/config.yaml b/tests/test_resource_string_in_cli_or_profile/profiles/config.yaml new file mode 100644 index 000000000..7420b386b --- /dev/null +++ b/tests/test_resource_string_in_cli_or_profile/profiles/config.yaml @@ -0,0 +1,4 @@ +set-resources: + test1: + slurm_partition: "smp" + slurm_extra: "'--nice=150'" diff --git a/tests/tests.py b/tests/tests.py index 5bb99dd9f..a11634614 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1969,6 +1969,17 @@ def test_issue1256(): assert "line 9" in stderr +def test_resource_string_in_cli_or_profile(): + test_path = dpath("test_resource_string_in_cli_or_profile") + profile = os.path.join(test_path, "profiles") + # workflow profile is loaded by default + run( + test_path, + snakefile="Snakefile", + shellcmd=f"snakemake --workflow-profile {profile} -c1 --default-resources slurm_account=foo other_resource='--test'", + ) + + def test_queue_input(): run(dpath("test_queue_input"))