I would like to use a function to set output log file names easily.
I tried the following function
# output_path=simulations/sim1/model/test.out
# idx=2 == add <x> after 2nd element
# x=logs
# returns= simulations/sim1/logs/model/test.out
def get_xpath(wildcards,x,idx):
outbase=wildcards.output[0]
return str('/'.join(outbase.split('/')[:idx])+"/"+x+"/"+'/'.join(outbase.split('/')[idx:]))
rule testme:
...
log: lambda wildcards: get_xpath(wildcards,"logs",2),
But it gives the following AttributeError
'function' object has no attribute 'get_wildcard_names'
I also tried using lambda:
rule testme:
...
log: lambda wildcards, output: output[0].split('.')[0],
Which gives the same error. I could not find any examples to achieve this in the snakemake documentation, so I am not sure if this is even possible. Any ideas?
Thanks!
Here is a workaround.
You still cannot get the output file name without copying it manually, but you can use a function to make it easier to name log files by using rule names as variables. It can be improved by making use of certain wildcards or by providing a hard copy of the output filename. Though setting rule names as variables limits some functionality such as directly calling a rule by its name.
def logfile(rule_name,wildcards=None,output=None):
return f"{config['dataset_id']}/logs/{rule_name}.log"
ruleid="get_fasta_per_locus"
rule ruleid:
input:
output:
log:
lambda wildcards: logfile(ruleid)
My current workaround:
def get_output_log(wildcards, output):
out=output[0].split('/')
if len(out) < 4:
raise ValueError("Output path must have at least 4 components")
out.insert(2, "logs")
# create the directory if it does not exist
out = [x.format(**wildcards) for x in out]
os.makedirs('/'.join(out[:-1]), exist_ok=True)
return '/'.join(out)
Usage:
rule xx:
input: ...
output: ...
params:
log=lambda wildcards, output: get_output_log(wildcards, output),
shell:
"""
command &> {params.log}
"""