канал проверяется как пустой, даже если в нем есть контент

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

Рассмотрим следующий минимальный пример:

process one {

  output:
    file("test.txt") into _chProcessTwo

  script:
    """
    echo "Hello world" > "test.txt"
    """

}

// making a copy so I check first if something in the channel or not
// avoids raising exception of MultipleInputChannel
_chProcessTwo.into{
  _chProcessTwoView;
  _chProcessTwoCheck;
  _chProcessTwoUse
}

//print contents of channel
println "Channel contents: " + _chProcessTwoView.toList().view()

process two {

  input:
     file(myInput) from _chProcessTwoUse
  when:
     (!_chProcessTwoCheck.toList().isEmpty())

  script:
    def test = _chProcessTwoUse.toList().isEmpty() ? "I'm empty" : "I'm NOT empty"
    println "The outcome is: " + test

}

Я хочу, чтобы процесс два запускался тогда и только тогда, когда в канале _chProcessTwo есть файл. Если я запустил приведенный выше код, я получу:

marius@dev:~/pipeline$ ./bin/nextflow run test.nf 
N E X T F L O W  ~  version 19.09.0-edge
Launching `test.nf` [infallible_gutenberg] - revision: 9f57464dc1
[c8/bf38f5] process > one [100%] 1 of 1 ✔
[-        ] process > two -
[/home/marius/pipeline/work/c8/bf38f595d759686a497bb4a49e9778/test.txt]

где последняя строка на самом деле является содержимым _chProcessTwoView

Если я удалю директиву when из второго процесса, я получу:

marius@mg-dev:~/pipeline$ ./bin/nextflow run test.nf 
N E X T F L O W  ~  version 19.09.0-edge
Launching `test.nf` [modest_descartes] - revision: 5b2bbfea6a
[57/1b7b97] process > one [100%] 1 of 1 ✔
[a9/e4b82d] process > two [100%] 1 of 1 ✔
[/home/marius/pipeline/work/57/1b7b979933ca9e936a3c0bb640c37e/test.txt]

с содержимым второго рабочего .command.log файла: The outcome is: I'm empty

Я пробовал также без toList()

Что я делаю неправильно? заранее спасибо

Обновление: обходной путь - проверить _chProcessTwoUse.view() != "", но это довольно грязно

Обновление 2, как того требует @Steve, я обновил код, чтобы немного лучше отразить фактические условия, которые есть в моем собственном конвейере:

def runProcessOne = true

process one {

  when:
    runProcessOne

  output:
    file("inputProcessTwo.txt") into _chProcessTwo optional true
    file("inputProcessThree.txt") into _chProcessThree optional true

  script:
    // this would replace the probability that output is not created
    def outputSomething = false
    """
    if ${outputSomething}; then
       echo "Hello world" > "inputProcessTwo.txt"
       echo "Goodbye world" > "inputProcessThree.txt"
    else
       echo "Sorry. Process one did not write to file."
    fi
    """

}


// making a copy so I check first if something in the channel or not
// avoids raising exception of MultipleInputChannel
_chProcessTwo.into{
  _chProcessTwoView;
  _chProcessTwoCheck;
  _chProcessTwoUse
}

//print contents of channel
println "Channel contents: " + _chProcessTwoView.view()
println _chProcessTwoView.view() ? "Me empty" : "NOT empty"

process two {

  input:
     file(myInput) from _chProcessTwoUse
  when:
     (runProcessOne) 

  script:
    """
    echo "The outcome is:  ${myInput}"
    """
}


process three {

   input:
       file(defaultInput) from _chUpstreamProcesses
       file(inputFromProcessTwo) from _chProcessThree

   script:
      def extra_parameters = _chProcessThree.isEmpty() ? "" : "--extra-input " + inputFromProcessTwo
      """
        echo "Hooray! We got: ${extra_parameters}"
      """
}

Как упомянул @Steve, я не должен даже проверять, пуст ли канал, NextFlow лучше знать, чтобы не инициировать процесс. Но я думаю, что в этой конструкции мне придется.

Мариус


person Marius    schedule 30.09.2020    source источник
comment
Я не думаю, что метод isEmpty() работает должным образом. Обычно вам не нужно проверять, пуст ли канал. В приведенном выше примере процесс «два» не будет запущен, если _chProcessTwoUse пуст. Можете ли вы показать, как создается ваш входной канал, и некоторые примеры условий?   -  person Steve    schedule 01.10.2020
comment
Привет, @Steve, я обновил вопрос, включив в него то, что вы спрашивали. Спасибо, что изучили это!   -  person Marius    schedule 01.10.2020


Ответы (1)


Я думаю, что отчасти проблема здесь в том, что процесс 'one' создает только optional выходы. Это немного усложняет работу с необязательными входными данными в процессе «три». Я бы постарался примирить это, если возможно. Если это не может быть согласовано, вам нужно будет иметь дело с необязательными входными данными в процессе «три». Для этого вам в основном нужно создать фиктивный файл, передать его в канал, используя ifEmpty, затем используйте имя фиктивного файла, чтобы проверить, следует ли добавлять префикс аргумента в начале. Это немного похоже на хитрость, но работает довольно хорошо.

Первым шагом является создание фиктивного файла. Мне нравятся совместно используемые конвейеры, поэтому я бы просто создал это в вашем baseDir, возможно, в папке с именем «assets»:

mkdir assets
touch assets/NO_FILE

Затем передайте свой фиктивный файл, если ваш канал _chProcessThree пуст:

params.dummy_file = "${baseDir}/assets/NO_FILE"

dummy_file = file(params.dummy_file)


process three {

    input:
    file(defaultInput) from _chUpstreamProcesses
    file(optfile) from _chProcessThree.ifEmpty(dummy_file)

    script:
    def extra_parameters = optfile.name != 'NO_FILE' ? "--extra-input ${optfile}" : ''

    """
    echo "Hooray! We got: ${extra_parameters}"
    """
}

Кроме того, эти строки проблематичны:

//print contents of channel
println "Channel contents: " + _chProcessTwoView.view()
println _chProcessTwoView.view() ? "Me empty" : "NOT empty"

Вызов view () передаст все значения из канала в стандартный вывод. Вы можете игнорировать любое возвращаемое значение. Если вы не включите DSL2, канал будет пустым. Я думаю, что вы ищете здесь закрытие:

_chProcessTwoView.view { "Found: $it" }

Не забудьте добавить -ansi-log false к команде nextflow run, чтобы вывод не засорялся. HTH.

person Steve    schedule 01.10.2020
comment
Привет, Стив. Спасибо за ответ. Да, у меня действительно была рабочая реализация, создавая фиктивные файлы с touch, но я обнаружил, что это грязная реализация. Эти println строки предназначены только для облегчения воспроизведения этого вопроса. У меня их нет в коде. Я знаю, что содержимое канала расходуется после использования. Хотя не знал об уловке "Found: $it":] Так что я думаю, что нет хорошего способа сделать это. Однако я должен сообщить ifEmpty() как об ошибке команде NextFlow, верно? - person Marius; 01.10.2020
comment
Не беспокойся, Мариус! Подход с использованием фиктивного файла также задокументирован здесь, поэтому его может не быть считается слишком грязным. Я имел в виду, что приведенное выше эквивалентно: def ret = channel.view(); println(ret), который просто возвращает DataflowVariable с нулевым значением и будет оцениваться как «истина» в следующей строке. - person Steve; 02.10.2020
comment
Я думаю, в вашем комментарии выше может быть опечатка, в чем именно проблема с ifEmpty? Если вы имеете в виду isEmpty, ну, нет оператора isEmpty, который работает на канале AFAIK. Есть метод isEmpty для объектов файл / путь (unixpath), но он просто проверяет, есть ли в файле какое-либо содержимое или нет. HTH. - person Steve; 02.10.2020
comment
Да, ты прав. это была опечатка. Я имел в виду isEmpty(). Спасибо за разъяснения. - person Marius; 02.10.2020