athiebaut
athiebaut

Reputation: 172

Access specific element of a list returned by a function in Snakemake

In my Snakemake workflow, I have defined a function that uses a file produced previously during the workflow, parses it and returns a list of 2 elements, for example :

def get_param_value(wildcards) :
    # do stuff with the wildcards and some files
    return ["element1","element2"]

I would then like to use each value of the returned list as independent params in a subsequent rule, such as :

rule example :
    input :
        'input_file.txt'
    output :
        'output_file.txt'
    params :
        param1 = "element1", # First element of the list returned by get_param_value function
        param2 = "element2" # Second element of the list returned by get_param_value function
    shell :
        'somecommand -i {input} -smth1 {params.param1} -smth2 {params.param2} -o {output} ;'

I have tried using the function directly in the rule, with

params :
    param1 = get_param_value[0],
    param2 = get_param_value[1]

but I get a TypeError : 'function' object is not subscriptable (which is expected because it's a function).

Do you have a workaround for this ?

Upvotes: 1

Views: 536

Answers (3)

athiebaut
athiebaut

Reputation: 172

After a bit of tinkering and thanks to Mario Abbruscato's suggestions, this did the trick : I used lambda functions in the params directive of the rule to extract the elements of the list and assign them to different parameters :

rule example :
    input :
        'input_file.txt'
    output :
        'output_file.txt'
    params :
        params = lambda wildcards : get_param_value(wildcards)
    shell :
        'somecommand -i {input} -smth1 {params.param1[0]} -smth2 {params.param2[1]} -o {output} ;'

Upvotes: 1

Cornelius Roemer
Cornelius Roemer

Reputation: 8158

You were close. You can avoid lambdas and use a function just by placing its name without parentheses or brackets like params: funcname. The function with that name is then automatically called by Snakemake and the wildcards are passed along, too.

This can be applied in your context as follows:

def get_param_value(wildcards) :
    return ["elem1","elem2"]

rule example :
    output :
        'output_file.txt'
    params : 
        string_list = get_param_value
    shell :
        'echo  -param1 {params.string_list[0]} -param2: {params.string_list[1]}'

You can run this yourself, it's a minimal (working) example that yields the following results when executed:

$ snakemake -np -c1

rule example:
    output: output_file.txt
    jobid: 0
    resources: tmpdir=/var/folders/5_/6_lmbd65717dly07dk7r7q200000gn/T

echo "param1: elem1" "param2: elem2"

Read more about using functions in rule attributes in the documentation.

Upvotes: 1

Mario Abbruscato
Mario Abbruscato

Reputation: 819

you can do :

def get_param_value(wildcards,index) :
    with open('file_from_workflow_using_wildcards') as file :
        # do stuff
        res = ["element1","element2"] 
        return res[index]

rule example :
    input :
        'input_file.txt'
    output :
        'output_file.txt'
    params :
        param1 = get_param_value(wildcards,0), # First 
        param2 = get_param_value(wildcards,1) # Second 
    shell :
        'somecommand -i {input} -smth1 {params.param1} -smth2 {params.param2} -o {output} ;'

or better way using your function as it is in your code :

res = get_param_value(wildcards)

params :
    param1 = res[0],
    param2 = res[1]

Upvotes: 0

Related Questions