Zum Inhalt

Teil 4: Hello Modules

KI-gestützte Übersetzung - mehr erfahren & Verbesserungen vorschlagen

Dieser Abschnitt behandelt, wie du deinen Workflow-Code organisierst, um die Entwicklung und Wartung deiner Pipeline effizienter und nachhaltiger zu gestalten. Konkret werden wir demonstrieren, wie man Module verwendet.

In Nextflow ist ein Modul eine einzelne process-Definition, die für sich allein in einer eigenständigen Codedatei gekapselt ist. Um ein Modul in einem Workflow zu verwenden, fügst du einfach eine einzeilige Import-Anweisung zu deiner Workflow-Codedatei hinzu; dann kannst du den process genauso in den Workflow integrieren, wie du es normalerweise tun würdest. Das ermöglicht es, process-Definitionen in mehreren Workflows wiederzuverwenden, ohne mehrere Kopien des Codes zu produzieren.

Als wir anfingen, unseren Workflow zu entwickeln, haben wir alles in einer einzigen Codedatei geschrieben. Jetzt werden wir die processes in einzelne Module auslagern.

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

Dies wird unseren Code besser teilbar, flexibler und wartbarer machen.

Wie du von diesem Abschnitt aus beginnen kannst

Dieser Abschnitt des Kurses setzt voraus, dass du die Teile 1-3 des Hello Nextflow-Kurses abgeschlossen hast, aber wenn du mit den dort behandelten Grundlagen vertraut bist, kannst du von hier aus starten, ohne etwas Besonderes tun zu müssen.


0. Aufwärmübung: hello-modules.nf ausführen

Wir werden das Workflow-Skript hello-modules.nf als Ausgangspunkt verwenden. Es entspricht dem Skript, das durch das Durcharbeiten von Teil 3 dieses Trainingskurses erstellt wurde, außer dass wir die Ausgabeziele geändert haben:

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

Um sicherzustellen, dass alles funktioniert, führe das Skript einmal aus, bevor du Änderungen vornimmst:

nextflow run hello-modules.nf
Befehlsausgabe
 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 ✔

Wie zuvor findest du die Ausgabedateien in dem im output-Block angegebenen Verzeichnis (hier results/hello_modules/).

Verzeichnisinhalte
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

Wenn das bei dir funktioniert hat, bist du bereit zu lernen, wie du deinen Workflow-Code modularisierst.


1. Ein Verzeichnis zum Speichern von Modulen erstellen

Es ist eine bewährte Praxis, deine Module in einem bestimmten Verzeichnis zu speichern. Du kannst dieses Verzeichnis beliebig nennen, aber die Konvention ist, es modules/ zu nennen.

mkdir modules

Tipp

Hier zeigen wir dir, wie du lokale Module verwendest, also Module, die lokal im selben Repository wie der Rest des Workflow-Codes gespeichert sind, im Gegensatz zu Remote-Modulen, die in anderen (entfernten) Repositories gespeichert sind. Für weitere Informationen über Remote-Module, siehe die Dokumentation.


2. Ein Modul für sayHello() erstellen

In seiner einfachsten Form ist das Umwandeln eines bestehenden process in ein Modul kaum mehr als eine Kopier-und-Einfüge-Operation. Wir werden einen Dateistub für das Modul erstellen, den relevanten Code hinüberkopieren und ihn dann aus der Haupt-Workflow-Datei löschen.

Dann müssen wir nur noch eine Import-Anweisung hinzufügen, damit Nextflow weiß, dass es den relevanten Code zur Laufzeit einziehen soll.

2.1. Einen Dateistub für das neue Modul erstellen

Lass uns eine leere Datei für das Modul namens sayHello.nf erstellen.

touch modules/sayHello.nf

Dies gibt uns einen Platz, um den process-Code zu platzieren.

2.2. Den sayHello-process-Code in die Moduldatei verschieben

Kopiere die gesamte process-Definition von der Workflow-Datei in die Moduldatei und stelle sicher, dass du auch den #!/usr/bin/env nextflow-Shebang mit kopierst.

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

/*
 * Verwende echo, um 'Hello World!' in eine Datei zu schreiben
 */
process sayHello {

    input:
    val greeting

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

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

Sobald das erledigt ist, lösche die process-Definition aus der Workflow-Datei, aber stelle sicher, dass du den Shebang an Ort und Stelle lässt.

2.3. Eine Import-Deklaration vor dem workflow-Block hinzufügen

Die Syntax für das Importieren eines lokalen Moduls ist ziemlich unkompliziert:

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

Lass uns das oberhalb des params-Blocks einfügen und es entsprechend ausfüllen.

hello-modules.nf
// Module einbinden
include { sayHello } from './modules/sayHello.nf'

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

Du siehst, wir haben den Modulnamen sayHello und den Pfad zu der Datei, die den Modulcode enthält, ./modules/sayHello.nf, ausgefüllt.

2.4. Den Workflow ausführen

Wir führen den Workflow mit im Wesentlichen demselben Code und denselben Eingaben wie zuvor aus, also lass ihn uns mit dem -resume-Flag ausführen und sehen, was passiert.

nextflow run hello-modules.nf -resume
Befehlsausgabe
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 ✔

Dies sollte sehr schnell laufen, weil alles im Cache ist. Du kannst gerne die veröffentlichten Ausgaben überprüfen.

Nextflow hat erkannt, dass es immer noch dieselbe Arbeit zu erledigen gibt, auch wenn der Code auf mehrere Dateien aufgeteilt ist.

Zusammenfassung

Du weißt, wie du einen process in ein lokales Modul extrahierst und weißt, dass dies die Wiederaufnahmefähigkeit des Workflows nicht beeinträchtigt.

Was kommt als Nächstes?

Übe das Erstellen weiterer Module. Sobald du eines gemacht hast, kannst du eine Million weitere machen... Aber lass uns vorerst nur noch zwei weitere machen.


3. Den convertToUpper()-process modularisieren

3.1. Einen Dateistub für das neue Modul erstellen

Erstelle eine leere Datei für das Modul namens convertToUpper.nf.

touch modules/convertToUpper.nf

3.2. Den convertToUpper-process-Code in die Moduldatei verschieben

Kopiere die gesamte process-Definition von der Workflow-Datei in die Moduldatei und stelle sicher, dass du auch den #!/usr/bin/env nextflow-Shebang mit kopierst.

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

/*
 * Verwende ein Textersetzungstool, um die Begrüßung in Großbuchstaben umzuwandeln
 */
process convertToUpper {

    input:
    path input_file

    output:
    path "UPPER-${input_file}"

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

Sobald das erledigt ist, lösche die process-Definition aus der Workflow-Datei, aber stelle sicher, dass du den Shebang an Ort und Stelle lässt.

3.3. Eine Import-Deklaration vor dem params-Block hinzufügen

Füge die Import-Deklaration oberhalb des params-Blocks ein und fülle sie entsprechend aus.

hello-modules.nf
// Module einbinden
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'

/*
* Pipeline-Parameter
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}
hello-modules.nf
// Module einbinden
include { sayHello } from './modules/sayHello.nf'

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

Dies sollte jetzt sehr vertraut aussehen.

3.4. Den Workflow erneut ausführen

Führe dies mit dem -resume-Flag aus.

nextflow run hello-modules.nf -resume
Befehlsausgabe
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 ✔

Dies sollte immer noch dieselbe Ausgabe wie zuvor produzieren.

Zwei erledigt, noch eines übrig!


4. Den collectGreetings()-process modularisieren

4.1. Einen Dateistub für das neue Modul erstellen

Erstelle eine leere Datei für das Modul namens collectGreetings.nf.

touch modules/collectGreetings.nf

4.2. Den collectGreetings-process-Code in die Moduldatei verschieben

Kopiere die gesamte process-Definition von der Workflow-Datei in die Moduldatei und stelle sicher, dass du auch den #!/usr/bin/env nextflow-Shebang mit kopierst.

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

/*
 * Großbuchstaben-Begrüßungen in einer einzelnen Ausgabedatei sammeln
 */
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'
    """
}

Sobald das erledigt ist, lösche die process-Definition aus der Workflow-Datei, aber stelle sicher, dass du den Shebang an Ort und Stelle lässt.

4.3. Eine Import-Deklaration vor dem params-Block hinzufügen

Füge die Import-Deklaration oberhalb des params-Blocks ein und fülle sie entsprechend aus.

hello-modules.nf
// Module einbinden
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'
include { collectGreetings } from './modules/collectGreetings.nf'

/*
* Pipeline-Parameter
*/
params {
    greeting: Path = 'data/greetings.csv'
    batch: String = 'batch'
}
hello-modules.nf
// Module einbinden
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'

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

Das letzte!

4.4. Den Workflow ausführen

Führe dies mit dem -resume-Flag aus.

nextflow run hello-modules.nf -resume
Befehlsausgabe
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 ✔

Dies sollte immer noch dieselbe Ausgabe wie zuvor produzieren.

Zusammenfassung

Du weißt, wie du mehrere processes in einem Workflow modularisierst.

Herzlichen Glückwunsch, du hast all diese Arbeit geleistet und absolut nichts hat sich daran geändert, wie die Pipeline funktioniert!

Scherz beiseite, jetzt ist dein Code modularer, und wenn du dich entscheidest, eine andere Pipeline zu schreiben, die einen dieser processes aufruft, musst du nur eine kurze Import-Anweisung eingeben, um das relevante Modul zu verwenden. Das ist besser als den Code zu kopieren und einzufügen, denn wenn du dich später entscheidest, das Modul zu verbessern, werden alle deine Pipelines die Verbesserungen erben.

Was kommt als Nächstes?

Mach eine kurze Pause, wenn du möchtest.

Wenn du bereit bist, gehe zu Teil 5: Hallo Container, um zu lernen, wie du Container verwendest, um Softwareabhängigkeiten bequemer und reproduzierbarer zu verwalten.


Quiz

#

Was ist ein Modul in Nextflow?

#

Was ist die empfohlene Namenskonvention für Moduldateien?

#

Wo sollten Moduldateien gespeichert werden?

#

Was ist die korrekte Syntax, um ein Modul zu importieren?

#

Was passiert mit der -resume-Funktionalität bei der Verwendung von Modulen?

#

Was sind die Vorteile der Verwendung von Modulen? (Wähle alle zutreffenden aus)