snakemake — не удалять выходные данные сбойных правил

#snakemake

#snakemake

Вопрос:

У меня есть рабочий процесс snakemake, содержащий правило, которое запускает другой «внутренний» рабочий процесс snakemake.
Иногда происходит сбой определенного правила внутреннего рабочего процесса, что означает сбой внутреннего рабочего процесса. В результате все файлы, перечисленные в разделе output внутреннего рабочего процесса, удаляются внешним рабочим процессом, даже если правила внутреннего рабочего процесса, которые их создали, завершились успешно.
Есть ли способ предотвратить удаление snakemake выходных данных сбойных правил? Или, может быть, вы можете предложить другой обходной путь?
Несколько замечаний:

  • Выходные данные внутреннего рабочего процесса должны быть перечислены, поскольку они используются в качестве входных данных для других правил во внешнем рабочем процессе.
  • Я попытался установить выходные данные внутреннего рабочего процесса как protected , но это не помогло.
  • Я также попытался добавить exit 0 в конец вызова внутреннего рабочего процесса, чтобы snakemake считал, что он успешно завершен,

вот так:

 rule run_inner:
    input:
        inputs...
    output:
        outputs...
    shell:
        """
        snakemake -s inner.snakefile
        exit 0
        """
 

но выходные данные все равно удаляются.
Был бы признателен за любую помощь. Спасибо!

Ответ №1:

Одним из вариантов может быть run_inner создание фиктивного выходного файла, который помечает завершение правила. Следующие правила run_inner будут принимать на входе фиктивный файл. Например:

 rule run_inner:
    ...
    output:
        # or just 'run_inner.done' if wildcards are not involved
        touch('{sample}.run_inner.done'), 
    shell:
        'snakemake -s inner.snakefile'

run next:
    input:
        '{sample}.run_inner.done',
    params:
        real_input= '{sample}.data.txt', # This is what run_inner actually produces
    shell:
        'do stuff {params.real_input}'
 

В случае snakemake -s inner.snakefile сбоя фиктивный вывод будет удален, но snakemake -s inner.snakefile будет перезапущен с того места, где он был оставлен.

Другим вариантом может быть интеграция правил inner.snakefile в ваш внешний конвейер, используя, например, оператор include . Я считаю, что этот вариант предпочтительнее, но, конечно, его было бы сложнее реализовать.

Комментарии:

1. Спасибо! include это было именно то, что мне было нужно, и на самом деле довольно просто в использовании.

Ответ №2:

Одним из обходных путей является использование run вместо shell :

 rule run_inner:
    input:
        inputs...
    output:
        outputs...
    run:
        shell("""snakemake -s inner.snakefile""")
        # Add your code here to store the files before removing
 

Даже если сценарий в shell вызове функции завершается с ошибкой, файлы все еще существуют, пока сценарий в run разделе не завершится. Вы можете скопировать файлы в безопасное место.

Обновление: вам необходимо обрабатывать исключения, чтобы продолжить выполнение всякий раз, когда скрипт возвращает ошибку. Приведенный ниже сценарий иллюстрирует идею: print функция из except: блока печатает True , другая из onerror печатает False

 rule run_inner:
    output:
        "output.txt"
    run:
        try:
            shell("""touch output.txt; exit 1""")
        except:
            print(os.path.exists("output.txt"))

onerror:
    print(os.path.exists("output.txt"))
 

Комментарии:

1. Спасибо, это интересное направление, но как мне таким образом вернуть выходные файлы к их ожидаемому пути? Они мне понадобятся для возобновления рабочего процесса.

2. Я не думаю, что это сработает. Если shell команда не выполняется, snakemake удалит файлы, перечисленные в output , и завершит работу. Он не будет продолжаться и выполнять остальную часть run директивы.

3. @dariober, не думай, просто проверь. Это не shell() функция, которая удаляет выходные данные, а процедура очистки правила. Эта процедура не вызывается до завершения run работы скрипта.

4. @DmitryKuzminov Я тестировал это, я все еще не думаю, что сценарий запуска выполняется до конца. В каталоге запуска я помещаю shell("touch {output}; exit 1"); os.rename(output[0], output[0] '.done') . shell создает выходные данные и завершается сбоем, поэтому os.rename никогда не выполняется и output[0] '.done' не создается. Можете ли вы опубликовать воспроизводимый пример?

5. @dariober, хм, мой первоначальный сценарий был некорректным. После переноса shell в try / except это начинает работать.

Ответ №3:

Программа «завершается с ошибкой», когда возвращает ненулевое возвращаемое значение. Поэтому нам нужно только «исправить» эту проблему, чтобы обмануть внутреннюю оболочку, думая, что все программы успешно завершены. Самый простой способ — использовать some error command || true . Ниже приведен минимальный пример:

 rule test:
    output:
        "test.output",
    shell:
        """
        touch test.output
        # below cat will trigger error 
        cat file_not_exist || true
        """
 

Вы обнаружите, что, несмотря на ошибку, выданную cat , test.output все еще сохраняется.