¿Cómo usar expandir en snakemake cuando no se desean algunas combinaciones particulares de comodines?

Supongamos que tengo los siguientes archivos, en los que quiero aplicar un poco de procesamiento automáticamente usando snakemake:

test_input_C_1.txt test_input_B_2.txt test_input_A_2.txt test_input_A_1.txt 

El siguiente snakefile utiliza expand para determinar todo el archivo de resultados finales potenciales:

 rule all: input: expand("test_output_{text}_{num}.txt", text=["A", "B", "C"], num=[1, 2]) rule make_output: input: "test_input_{text}_{num}.txt" output: "test_output_{text}_{num}.txt" shell: """ md5sum {input} > {output} """ 

La ejecución del archivo de serpiente anterior genera el siguiente error:

 MissingInputException in line 4 of /tmp/Snakefile: Missing input files for rule make_output: test_input_B_1.txt 

La razón de ese error es que expand usa itertools.product under the hood para generar las combinaciones de comodines, algunas de las cuales corresponden a archivos faltantes.

¿Cómo filtrar las combinaciones de comodines no deseados?

    La función expand acepta un segundo argumento opcional sin palabra clave para usar una función diferente de la predeterminada para combinar valores comodín.

    Uno puede crear una versión filtrada de itertools.product envolviéndolo en un generador de orden superior que verifique que la combinación de caracteres comodín no se encuentre entre una lista negra preestablecida:

     from itertools import product def filter_combinator(combinator, blacklist): def filtered_combinator(*args, **kwargs): for wc_comb in combinator(*args, **kwargs): # Use frozenset instead of tuple # in order to accomodate # unpredictable wildcard order if frozenset(wc_comb) not in blacklist: yield wc_comb return filtered_combinator # "B_1" and "C_2" are undesired forbidden = { frozenset({("text", "B"), ("num", 1)}), frozenset({("text", "C"), ("num", 2)})} filtered_product = filter_combinator(product, forbidden) rule all: input: # Override default combination generator expand("test_output_{text}_{num}.txt", filtered_product, text=["A", "B", "C"], num=[1, 2]) rule make_output: input: "test_input_{text}_{num}.txt" output: "test_output_{text}_{num}.txt" shell: """ md5sum {input} > {output} """ 

    Las combinaciones de comodines que faltan se pueden leer desde el archivo de configuración.

    Aquí hay un ejemplo en formato json:

     { "missing" : [ { "text" : "B", "num" : 1 }, { "text" : "C", "num" : 2 } ] } 

    El conjunto forbidden se leerá de la siguiente manera en el archivo snake:

     forbidden = {frozenset(wc_comb.items()) for wc_comb in config["missing"]}