3

I am attempting to create an iterative rule in snakemake. I have an empty text file in data/ called basic_0. I am hoping to apply a rule to it "x" times (where "x" is an integer) by calling $ snakemake data/basic_<x>.txt --cores 1, where the snakefile is as follows:

rule iterative_addHi:
    input:
        "data/basic_{iter}.txt"
    output:
        "data/basic_{iter+1}.txt"
    shell:
        "python addHi.py {input} {output}"

The addHi.py file just adds a new line with "Hi" to the text file (just toy code), so if I call $ snakemake data/basic_5.txt --cores 1 I would hope to find a file called data/basic_5.txt that has five new lines with "Hi". However I'm only getting

MissingRuleException: No rule to produce data/basic_5.txt (if you use input functions make sure that they don't raise unexpected exceptions).

Is there a way to do what I'm thinking? I've tried converting the wildcard into an integer using int(), then adding 1, then converting this back to a string using str().

Thanks

SultanOrazbayev
  • 14,900
  • 3
  • 16
  • 46
jabbo12
  • 31
  • 1

1 Answers1

3

Snakemake allows expressing inputs as a function of wildcards. This applies to inputs directive, so the arithmetic should be moved from output to input and lambda used to delay the computation/evaluation of inputs:

rule iterative_addHi:
    input:
        lambda wildcards: f"data/basic_{int(wildcards.iter)-1}.txt"
    output:
        "data/basic_{iter}.txt"
    shell:
        "python addHi.py {input} {output}"

As @dariober noted in a comment: the wildcards are stored as strings, so for arithmetic, we need to convert them to an integer representation.

SultanOrazbayev
  • 14,900
  • 3
  • 16
  • 46
  • 1
    +1, really cool! Minor bug: The string formatting should be `{int(wildcards.iter)-1}` to convert string to int first. – dariober Jun 30 '22 at 16:13