Vai al contenuto

Parte 4: Hello Modules

Traduzione assistita da IA - scopri di più e suggerisci miglioramenti

Questa sezione tratta come organizzare il codice del workflow per rendere lo sviluppo e la manutenzione della pipeline più efficienti e sostenibili. Nello specifico, dimostreremo come usare i moduli.

In Nextflow, un modulo è una singola definizione di processo che è incapsulata da sola in un file di codice autonomo. Per usare un modulo in un workflow, basta aggiungere una singola riga di import al file di codice del workflow; poi potete integrare il processo nel workflow nello stesso modo in cui farebbe normalmente. Questo rende possibile riutilizzare le definizioni dei processi in più workflow senza produrre copie multiple del codice.

Quando abbiamo iniziato a sviluppare il nostro workflow, abbiamo scritto tutto in un singolo file di codice. Ora sposteremo i processi in moduli individuali.

hello-modules.nfsayHello.nfconvertToUpper.nfcollectGreetings.nfincludemodules/sayHelloconvertToUppercollectGreetings

Questo renderà il nostro codice più condivisibile, flessibile e manutenibile.

Come iniziare da questa sezione

Questa sezione del corso presuppone che abbiate completato le Parti 1-3 del corso Hello Nextflow, ma se avete familiarità con i concetti base trattati in quelle sezioni, potete iniziare da qui senza fare nulla di speciale.


0. Riscaldamento: Eseguire hello-modules.nf

Useremo lo script del workflow hello-modules.nf come punto di partenza. È equivalente allo script prodotto seguendo la Parte 3 di questo corso di formazione, tranne che abbiamo cambiato le destinazioni dell'output:

hello-modules.nf
output {
    first_output {
        path 'hello_modules'
        mode 'copy'
    }
    uppercased {
        path 'hello_modules'
        mode 'copy'
    }
    collected {
        path 'hello_modules'
        mode 'copy'
    }
    batch_report {
        path 'hello_modules'
        mode 'copy'
    }
}

Solo per assicurarci che tutto funzioni, eseguite lo script una volta prima di apportare modifiche:

nextflow run hello-modules.nf
Output del comando
 N E X T F L O W   ~  version 25.10.2

Launching `hello-modules.nf` [hopeful_avogadro] DSL2 - revision: b09af1237d

executor >  local (7)
[0f/8795c9] sayHello (3)       [100%] 3 of 3 ✔
[6a/eb2510] convertToUpper (3) [100%] 3 of 3 ✔
[af/479117] collectGreetings   [100%] 1 of 1 ✔

Come in precedenza, troverete i file di output nella directory specificata nel blocco output (qui, results/hello_modules/).

Contenuti della directory
results/hello_modules/
├── Bonjour-output.txt
├── COLLECTED-batch-output.txt
├── Hello-output.txt
├── Holà-output.txt
├── batch-report.txt
├── UPPER-Bonjour-output.txt
├── UPPER-Hello-output.txt
└── UPPER-Holà-output.txt

Se tutto ha funzionato, siete pronti a imparare come modularizzare il codice del workflow.


1. Creare una directory per memorizzare i moduli

È buona pratica memorizzare i moduli in una directory specifica. Potete chiamare quella directory come volete, ma la convenzione è chiamarla modules/.

mkdir modules

Suggerimento

Qui vi stiamo mostrando come usare moduli locali, cioè moduli memorizzati localmente nello stesso repository del resto del codice del workflow, in contrasto con i moduli remoti, che sono memorizzati in altri repository (remoti). Per maggiori informazioni sui moduli remoti, vedete la documentazione.


2. Creare un modulo per sayHello()

Nella sua forma più semplice, trasformare un processo esistente in un modulo è poco più di un'operazione di copia-incolla. Creeremo uno stub di file per il modulo, copieremo il codice rilevante e poi lo cancelleremo dal file del workflow principale.

Poi tutto ciò che dovremo fare è aggiungere un'istruzione di import in modo che Nextflow sappia di importare il codice rilevante a runtime.

2.1. Creare uno stub di file per il nuovo modulo

Creiamo un file vuoto per il modulo chiamato sayHello.nf.

touch modules/sayHello.nf

Questo ci dà un posto dove mettere il codice del processo.

2.2. Spostare il codice del processo sayHello nel file del modulo

Copiate l'intera definizione del processo dal file del workflow al file del modulo, assicurandovi di copiare anche lo shebang #!/usr/bin/env nextflow.

modules/sayHello.nf
#!/usr/bin/env nextflow

/*
 * Use echo to print 'Hello World!' to a file
 */
process sayHello {

    input:
    val greeting

    output:
    path "${greeting}-output.txt"

    script:
    """
    echo '${greeting}' > '${greeting}-output.txt'
    """
}

Una volta fatto, cancellate la definizione del processo dal file del workflow, ma assicuratevi di lasciare lo shebang al suo posto.

2.3. Aggiungere una dichiarazione di import prima del blocco workflow

La sintassi per importare un modulo locale è abbastanza semplice:

Syntax: Import declaration
include { <MODULE_NAME> } from '<path_to_module>'

Inseriamola sopra il blocco params e compiliamola appropriatamente.

hello-modules.nf
// Include i moduli
include { sayHello } from './modules/sayHello.nf'

/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}
hello-modules.nf
/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}

Vedete che abbiamo inserito il nome del modulo, sayHello, e il percorso al file contenente il codice del modulo, ./modules/sayHello.nf.

2.4. Eseguire il workflow

Stiamo eseguendo il workflow essenzialmente con lo stesso codice e input di prima, quindi eseguiamo con il flag -resume e vediamo cosa succede.

nextflow run hello-modules.nf -resume
Output del comando
N E X T F L O W   ~  version 25.10.2

Launching `hello-modules.nf` [romantic_poisson] DSL2 - revision: 96edfa9ad3

[f6/cc0107] sayHello (1)       | 3 of 3, cached: 3 ✔
[3c/4058ba] convertToUpper (2) | 3 of 3, cached: 3 ✔
[1a/bc5901] collectGreetings   | 1 of 1, cached: 1 ✔

Questo dovrebbe funzionare molto velocemente perché tutto è in cache. Sentitevi liberi di controllare gli output pubblicati.

Nextflow ha riconosciuto che è ancora tutto lo stesso lavoro da fare, anche se il codice è diviso in più file.

Takeaway

Sapete come estrarre un processo in un modulo locale e sapete che fare questo non compromette la ripristinabilità del workflow.

Cosa c'è dopo?

Fare pratica creando più moduli. Una volta che ne avete fatto uno, potete farne un milione di più... Ma per ora ne facciamo solo altri due.


3. Modularizzare il processo convertToUpper()

3.1. Creare uno stub di file per il nuovo modulo

Create un file vuoto per il modulo chiamato convertToUpper.nf.

touch modules/convertToUpper.nf

3.2. Spostare il codice del processo convertToUpper nel file del modulo

Copiate l'intera definizione del processo dal file del workflow al file del modulo, assicurandovi di copiare anche lo shebang #!/usr/bin/env nextflow.

modules/convertToUpper.nf
#!/usr/bin/env nextflow

/*
 * Use a text replacement tool to convert the greeting to uppercase
 */
process convertToUpper {

    input:
    path input_file

    output:
    path "UPPER-${input_file}"

    script:
    """
    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
    """
}

Una volta fatto, cancellate la definizione del processo dal file del workflow, ma assicuratevi di lasciare lo shebang al suo posto.

3.3. Aggiungere una dichiarazione di import prima del blocco params

Inserite la dichiarazione di import sopra il blocco params e compilatela appropriatamente.

hello-modules.nf
// Include i moduli
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'

/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}
hello-modules.nf
// Include i moduli
include { sayHello } from './modules/sayHello.nf'

/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}

Questo dovrebbe iniziare a sembrare molto familiare.

3.4. Eseguire di nuovo il workflow

Eseguite questo con il flag -resume.

nextflow run hello-modules.nf -resume
Output del comando
N E X T F L O W   ~  version 25.10.2

Launching `hello-modules.nf` [nauseous_heisenberg] DSL2 - revision: a04a9f2da0

[c9/763d42] sayHello (3)       | 3 of 3, cached: 3 ✔
[60/bc6831] convertToUpper (3) | 3 of 3, cached: 3 ✔
[1a/bc5901] collectGreetings   | 1 of 1, cached: 1 ✔

Questo dovrebbe ancora produrre lo stesso output di prima.

Due fatti, ne manca ancora uno!


4. Modularizzare il processo collectGreetings()

4.1. Creare uno stub di file per il nuovo modulo

Create un file vuoto per il modulo chiamato collectGreetings.nf.

touch modules/collectGreetings.nf

4.2. Spostare il codice del processo collectGreetings nel file del modulo

Copiate l'intera definizione del processo dal file del workflow al file del modulo, assicurandovi di copiare anche lo shebang #!/usr/bin/env nextflow.

modules/collectGreetings.nf
#!/usr/bin/env nextflow

/*
 * Collect uppercase greetings into a single output file
 */
process collectGreetings {

    input:
    path input_files
    val batch_name

    output:
    path "COLLECTED-${batch_name}-output.txt", emit: outfile
    path "${batch_name}-report.txt", emit: report

    script:
    count_greetings = input_files.size()
    """
    cat ${input_files} > 'COLLECTED-${batch_name}-output.txt'
    echo 'There were ${count_greetings} greetings in this batch.' > '${batch_name}-report.txt'
    """
}

Una volta fatto, cancellate la definizione del processo dal file del workflow, ma assicuratevi di lasciare lo shebang al suo posto.

4.3. Aggiungere una dichiarazione di import prima del blocco params

Inserite la dichiarazione di import sopra il blocco params e compilatela appropriatamente.

hello-modules.nf
// Include i moduli
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'
include { collectGreetings } from './modules/collectGreetings.nf'

/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}
hello-modules.nf
// Include i moduli
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'

/*
* Pipeline parameters
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}

Ultimo!

4.4. Eseguire il workflow

Eseguite questo con il flag -resume.

nextflow run hello-modules.nf -resume
Output del comando
N E X T F L O W   ~  version 25.10.2

Launching `hello-modules.nf` [friendly_coulomb] DSL2 - revision: 7aa2b9bc0f

[f6/cc0107] sayHello (1)       | 3 of 3, cached: 3 ✔
[3c/4058ba] convertToUpper (2) | 3 of 3, cached: 3 ✔
[1a/bc5901] collectGreetings   | 1 of 1, cached: 1 ✔

Questo dovrebbe ancora produrre lo stesso output di prima.

Takeaway

Sapete come modularizzare più processi in un workflow.

Congratulazioni, avete fatto tutto questo lavoro e non è cambiato assolutamente nulla nel funzionamento della pipeline!

A parte gli scherzi, ora il vostro codice è più modulare, e se decidete di scrivere un'altra pipeline che chiama uno di quei processi, vi basta digitare una breve istruzione di import per usare il modulo rilevante. Questo è meglio che fare copia-incolla del codice, perché se in seguito decidete di migliorare il modulo, tutte le vostre pipeline erediteranno i miglioramenti.

Cosa c'è dopo?

Prendetevi una breve pausa se ne avete voglia.

Quando siete pronti, passate alla Parte 5: Hello Containers per imparare come usare i container per gestire le dipendenze software in modo più conveniente e riproducibile.


Quiz

#

Cos'è un modulo in Nextflow?

#

Qual è la convenzione di denominazione raccomandata per i file dei moduli?

#

Dove dovrebbero essere memorizzati i file dei moduli?

#

Qual è la sintassi corretta per importare un modulo?

#

Cosa succede alla funzionalità -resume quando si usano i moduli?

#

Quali sono i vantaggi dell'uso dei moduli? (Selezioni tutte le risposte applicabili)