Conditional Snakemake
Today’s problem was how to write a Snakefile that would apply a user-created mask if one was created when automatic masking was unsuccessful. Snakemake is very python-y under the hood so in a way this should be obvious but it took me some time to figure out.
The inputs to a rule can be a python function instead of a static list of files so we can write a Snakefile like the following:
import os.path
def should_apply_user_mask(wildcards):
if os.path.exists("user_mask.txt"):
return "image_masked.txt"
else:
return "image.txt"
rule all:
input:
"result.txt"
rule apply_user_mask:
input:
"user_mask.txt",
"image.txt"
output:
"image_masked.txt"
shell:
"cat {input} > {output}"
rule optional_mask:
input:
should_apply_user_mask
output:
"result.txt"
shell:
"cat {input} > {output}"
When the Snakefile is evaluated the inputs to optional mask will be either just the image or the masked image if one is available. The first execution will not use the manual mask. The second execution will apply the mask (assuming the modification date is later than the final result). Snakemake allows an even fancier version of this where the graph can be re-evaluated after completion of a step but we don’t need that in this case.