Как избежать ошибки «отсутствующие входные файлы» в функции Snakemake «expand»

#snakemake

#snakemake

Вопрос:

Я получаю MissingInputException , когда я запускаю следующий код snakemake:

 import re
import os

glob_vars = glob_wildcards(os.path.join(os.getcwd(), "inputs","{fileName}.{ext}"))

rule end:
    input:
        expand(os.path.join(os.getcwd(), "inputs", "{fileName}_rename.fas"), fileName=glob_vars.fileName)

rule rename:
    '''
    rename fasta file to avoid problems
    '''
    input:
        expand("inputs/{{fileName}}.{ext}", ext=glob_vars.ext)
    output:
        os.path.join(os.getcwd(), "inputs", "{fileName}_rename.fas")
    run:
        list_ = []
        with open(str(input)) as f2:
            line = f2.readline()
            while line:
                while not line.startswith('>') and line:
                    line = f2.readline()
                fas_name = re.sub(r"W", "_", line.strip())
                list_.append(fas_name)
                fas_seq = ""
                line = f2.readline()
                while not line.startswith('>') and line:
                    fas_seq  = re.sub(r"s","",line)
                    line = f2.readline()
                list_.append(fas_seq)
        with open(str(output), "w") as f:
            f.write("n".join(list_))
 

Моя Inputs папка содержит эти файлы:

 G.bullatarudis.fasta
goldfish_protein.faa
guppy_protein.faa
gyrodactylus_salaris.fasta
protopolystoma_xenopodis.fa
salmon_protein.faa
schistosoma_mansoni.fa
 

Сообщение об ошибке выглядит следующим образом:

 Building DAG of jobs...
MissingInputException in line 10 of /home/zhangdong/works/NCBI/BLAST/RHB/test.rule:
Missing input files for rule rename:
inputs/guppy_protein.fasta
inputs/guppy_protein.fa
 

Я предположил, что ошибка вызвана expand функцией, потому guppy_protein.faa что существует только file , но expand также generate guppy_protein.fasta и guppy_protein.fa files . Есть ли какие-то решения?

Ответ №1:

По умолчанию expand будут созданы все комбинации входных списков, так что это ожидаемое поведение. Вам нужен ваш ввод для поиска правильного расширения с учетом имени файла. Я не тестировал это:

 glob_vars = glob_wildcards(os.path.join(os.getcwd(), "inputs","{fileName}.{ext}"))

# create a dict to lookup extensions given fileNames
glob_vars_dict = {fname: ex for fname, ex in zip(glob_vars.fileName, glob_vars.ext)}

def rename_input(wildcards):
   ext = glob_vars_dict[wildcards.fileName]
   return f"inputs/{wildcards.fileName}.{ext}"

rule rename:
    input: rename_input
 

Несколько непрошеных комментариев по стилю:

  • Вам не нужно добавлять свой glob_wildcards с os.getcwd помощью, glob_wildcards("inputs", "{fileName}.{ext}")) должно работать, поскольку snakemake по умолчанию использует пути относительно рабочего каталога.
  • Попробуйте использовать snake_case вместо camalCase для имен ваших переменных в python
  • В этом случае fileName это не очень хороший дескриптор того, что вы фиксируете. Может species_name быть, или species было бы яснее

Ответ №2:

Благодаря Troy Comi я изменил свой код, и он заработал:

 import re
import os
import itertools

speciess,exts = glob_wildcards(os.path.join(os.getcwd(), "inputs_test","{species}.{ext}"))

rule end:
    input:
        expand("inputs_test/{species}_rename.fas", species=speciess)

def required_files(wildcards):
    list_combination = itertools.product([wildcards.species], list(set(exts)))
    exist_file = ""
    for file in list_combination:
        if os.path.exists(f"inputs_test/{'.'.join(file)}"):
            exist_file = f"inputs_test/{'.'.join(file)}"
    return exist_file

rule rename:
    '''
    rename fasta file to avoid problems
    '''
    input:
        required_files
    output:
        "inputs_test/{species}_rename.fas"
    run:
        list_ = []
        with open(str(input)) as f2:
            line = f2.readline()
            while line:
                while not line.startswith('>') and line:
                    line = f2.readline()
                fas_name = ">"   re.sub(r"W", "_", line.replace(">", "").strip())
                list_.append(fas_name)
                fas_seq = ""
                line = f2.readline()
                while not line.startswith('>') and line:
                    fas_seq  = re.sub(r"s","",line)
                    line = f2.readline()
                list_.append(fas_seq)
        with open(str(output), "w") as f:
            f.write("n".join(list_))