Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: rule inheritance within modules (did previously lead to key errors) #1292

Merged
merged 2 commits into from Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 9 additions & 3 deletions snakemake/modules.py
Expand Up @@ -13,18 +13,24 @@
from snakemake.common import Rules, Scatter, Gather


def get_name_modifier_func(rules=None, name_modifier=None):
def get_name_modifier_func(rules=None, name_modifier=None, parent_modifier=None):
if name_modifier is None:
return None
else:
if parent_modifier is None:
parent_modifier_func = lambda rulename: rulename
else:
parent_modifier_func = parent_modifier.modify_rulename
if "*" in name_modifier:
return lambda rulename: name_modifier.replace("*", rulename)
return lambda rulename: parent_modifier_func(
name_modifier.replace("*", rulename)
)
elif name_modifier is not None:
if len(rules) > 1:
raise SyntaxError(
"Multiple rules in 'use rule' statement but name modification ('as' statement) does not contain a wildcard '*'."
)
return lambda rulename: name_modifier
return lambda rulename: parent_modifier_func(name_modifier)


class ModuleInfo:
Expand Down
6 changes: 4 additions & 2 deletions snakemake/workflow.py
Expand Up @@ -1819,11 +1819,13 @@ def decorate(maybe_ruleinfo):
raise WorkflowError(
"'use rule' statement from rule in the same module must declare a single rule but multiple rules are declared."
)
orig_rule = self._rules[rules[0]]
orig_rule = self._rules[self.modifier.modify_rulename(rules[0])]
ruleinfo = maybe_ruleinfo if not callable(maybe_ruleinfo) else None
with WorkflowModifier(
self,
rulename_modifier=get_name_modifier_func(rules, name_modifier),
rulename_modifier=get_name_modifier_func(
rules, name_modifier, parent_modifier=self.modifier
),
ruleinfo_overwrite=ruleinfo,
):
self.rule(
Expand Down
25 changes: 25 additions & 0 deletions tests/test_modules_ruledeps_inheritance/Snakefile
@@ -0,0 +1,25 @@
rule all:
input:
"test2.txt",
"test3.txt",
"test4.txt",


module somemodule:
snakefile:
"module/Snakefile"
config:
config


use rule * from somemodule as somemodule_*


module someothermodule:
snakefile:
"module2/Snakefile"
config:
config


use rule * from someothermodule as someothermodule_*
@@ -0,0 +1 @@
test
20 changes: 20 additions & 0 deletions tests/test_modules_ruledeps_inheritance/module/Snakefile
@@ -0,0 +1,20 @@
rule a:
output:
"test.txt"
shell:
"echo test > {output}"


rule b:
input:
rules.a.output[0]
output:
"test2.txt"
shell:
"cp {input} {output}"



use rule b as c with:
output:
"test4.txt"
5 changes: 5 additions & 0 deletions tests/test_modules_ruledeps_inheritance/module2/Snakefile
@@ -0,0 +1,5 @@
rule a:
output:
"test3.txt"
shell:
"echo foo > {output}"
5 changes: 5 additions & 0 deletions tests/tests.py
Expand Up @@ -1377,3 +1377,8 @@ def test_ancient_dag():
@skip_on_windows
def test_checkpoint_allowed_rules():
run(dpath("test_checkpoint_allowed_rules"), targets=["c"], cluster="./qsub")


@skip_on_windows
def test_modules_ruledeps_inheritance():
run(dpath("test_modules_ruledeps_inheritance"))