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

incompatibility with using rules.rulename.output and importing snakefile as a module, using use rule a from somemodule as a with... #2838

Open
LukaP-BB opened this issue Apr 23, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@LukaP-BB
Copy link

Snakemake version
tested with :
8.10.8
7.32.3

Describe the bug
I have a snakefile using the Rule object to reference outputs from previous rules.
I have a second snakefile in which I want to import some of the rules from first snakefile.
Doing so, Snakemake raises a WorkflowError, that is not raised if I use strings for inputs/outputs instead of using input: rules.somerule.output

Logs

WorkflowError in file imported.smk, line 8:
Rule a is not defined in this workflow. Available rules: 

Minimal example
You can create the 2 following files to recreate the bug :

# main.smk

module imported:
    snakefile: "imported.smk"

rule a:
    output: "a.from_main.txt"
    shell: "touch {output}"

use rule b from imported as b with:
    input: rules.a.output

rule target:
    input: 
        rules.b.output
# imported.smk

rule a:
    output: "a.from_imported.txt"
    shell: "touch {output}"

rule b:
    input: rules.a.output
    output: "b.txt"
    shell: "touch {output}"

rule target:
    input: 
        "b.txt",

And run :

snakemake -s main.smk target -n

doing the following change to imported.smk fixes the error

rule b:
    # input: rules.a.output
    input: "a.from_imported.txt"
    output: "b.txt"
    shell: "touch {output}"
@LukaP-BB LukaP-BB added the bug Something isn't working label Apr 23, 2024
@cademirch
Copy link
Contributor

cademirch commented Apr 24, 2024

Which rule a is this referencing? :

use rule b from imported as b with:
    input: rules.a.output

Seems like main's rule a would shadow imported's since they both are called rule a.

Assuming you want to use main's rule a as input you could do this in your main.smk:

# main.smk

module imported:
    snakefile: "imported.smk"
use rule * from imported as imported_*

rule a:
    output: "a.from_main.txt"
    shell: "touch {output}"

use rule imported_b as b with:
    input: rules.a.output

rule target:
    input: 
        rules.b.output

Dryrun output:

❯ snakemake -s main.smk target -n
Building DAG of jobs...
Job stats:
job       count
------  -------
a             1
b             1
target        1
total         3

Execute 1 jobs...

[Wed Apr 24 16:32:44 2024]
localrule a:
    output: a.from_main.txt
    jobid: 2
    reason: Missing output files: a.from_main.txt
    resources: tmpdir=<TBD>

Execute 1 jobs...

[Wed Apr 24 16:32:44 2024]
localrule b:
    input: a.from_main.txt
    output: b.txt
    jobid: 1
    reason: Missing output files: b.txt; Input files updated by another job: a.from_main.txt
    resources: tmpdir=<TBD>

Execute 1 jobs...

[Wed Apr 24 16:32:44 2024]
localrule target:
    input: b.txt
    jobid: 0
    reason: Input files updated by another job: b.txt
    resources: tmpdir=<TBD>

Job stats:
job       count
------  -------
a             1
b             1
target        1
total         3

@Hocnonsense
Copy link
Contributor

I also meet this exception, and I've found that it is caused by refering rules.a.output in rules.b in imported.smk

It happened when loading module module imported:
as you ONLY select b to be used (use rule b from imported as b with:),
snakemake go through each rule and only record the one you select, otherwise, it does nothing:

def rule(self, name=None, lineno=None, snakefile=None, checkpoint=False):
# choose a name for an unnamed rule
if name is None:
name = str(len(self._rules) + 1)
if self.modifier.skip_rule(name):
def decorate(ruleinfo):
# do nothing, ignore rule
return ruleinfo.func
return decorate

def skip_rule(self, rulename):
return (
self.rule_whitelist is not None and rulename not in self.rule_whitelist
) or (self.rule_exclude_list is not None and rulename in self.rule_exclude_list)

if you try to print workflow.modifier.rule_whitelist, you will find that it is not None

I think this is more similar to a bug than a behavier.

@LukaP-BB
Copy link
Author

LukaP-BB commented Apr 25, 2024

Which rule a is this referencing? :

Well, rule.a is referencing the only rule that is in scope, aka the one defined in main.smk.

Thanks for providing an option that is working, I appreciate it ❤️
However, I believe it to be more of a workaround than an actual "good" way of doing it. I would much rather specify only the rules I'm interested in instead of importing everything and then only use a subset of the rules.

I think Hocnonsense is right here :

and I've found that it is caused by refering rules.a.output in rules.b in imported.smk

and this is indeed a bug.
Since I'm overwriting the inputs, I don't see the point in trying to interpret input: rules.a.output in imported.smk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants