2016-12-16 17 views
1

Давайте предположим, что у меня есть следующие файлы, на которые я хочу, чтобы автоматически применить некоторую обработку с использованием snakemake:Как использовать расширение в snakemake, когда некоторые особые комбинации подстановок не нужны?

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

Следующая snakefile использует expand, чтобы определить все потенциальные окончательные результаты файла:

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} 
     """ 

Выполнение вышеуказанных результатов snakefile в следующей ошибке:

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

The причиной этой ошибки является то, что expand использует itertools.product под капотом для генерации комбинаций подстановочных знаков, некоторые из которых, как представляется, соответствуют отсутствующим файлам.

Как отфильтровать нежелательные сочетания символов?

ответ

4

Функция expand принимает второй необязательный аргумент без ключевого слова для использования другой функции по умолчанию для объединения значений подстановочных знаков.

Можно создать фильтрованную версию itertools.product, обернув его в генераторе высшего порядка, который проверяет, что дало сочетание групповых символов не входит в заранее установленной черный список:

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} 
     """ 

Недостающая комбинации шаблонов можно прочитать из конфигурационного файла.

Ниже приведен пример в формате JSON:

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

forbidden набор будет следующим в snakefile:

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