Przejdź do treści

Część 4: Hello Modules

Tłumaczenie wspomagane przez AI - dowiedz się więcej i zasugeruj ulepszenia

Ta sekcja opisuje, jak organizować kod workflow, aby rozwój i utrzymanie pipeline było bardziej efektywne i zrównoważone. W szczególności pokażemy, jak używać modułów.

W Nextflow moduł to pojedyncza definicja procesu zamknięta w samodzielnym pliku kodu. Aby go użyć w pipeline, wystarczy dodać jednoliniową instrukcję importu; następnie można zintegrować dany proces ze strukturą workflow w standardowy sposób. Umożliwia to ponowne wykorzystanie definicji w wielu pipeline'ach bez tworzenia wielu kopii kodu.

Kiedy zaczęliśmy rozwijać nasz workflow, napisaliśmy wszystko w jednym pliku kodu. Teraz przeniesiemy procesy do indywidualnych modułów.

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

To sprawi, że nasz kod będzie bardziej współdzielny, elastyczny i łatwy w utrzymaniu.

Jak zacząć od tej sekcji

Ta sekcja kursu zakłada, że ukończyłeś Części 1-3 kursu Hello Nextflow, ale jeśli znasz podstawy omówione w tych sekcjach, możesz zacząć od tego miejsca bez żadnych dodatkowych przygotowań.


0. Rozgrzewka: Uruchom hello-modules.nf

Użyjemy skryptu workflow hello-modules.nf jako punktu wyjścia. Jest on równoważny skryptowi utworzonemu podczas pracy nad Częścią 3 tego szkolenia, z tą różnicą, że zmieniliśmy miejsca docelowe wyjść:

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

Aby upewnić się, że wszystko działa, uruchom skrypt raz przed wprowadzeniem jakichkolwiek zmian:

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

Jak poprzednio, pliki wyjściowe znajdziesz w katalogu określonym w bloku output (tutaj results/hello_modules/).

Zawartość katalogu
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

Jeśli to zadziałało, jesteś gotowy do nauki modularyzacji kodu workflow.


1. Utwórz katalog do przechowywania modułów

Najlepszą praktyką jest przechowywanie modułów w konkretnym katalogu. Możesz nazwać ten katalog jak chcesz, ale konwencja nakazuje nazywać go modules/.

mkdir modules

Wskazówka

Tutaj pokazujemy, jak używać lokalnych modułów, czyli modułów przechowywanych lokalnie w tym samym repozytorium co reszta kodu workflow, w przeciwieństwie do modułów zdalnych, które są przechowywane w innych (zdalnych) repozytoriach. Więcej informacji o modułach zdalnych znajdziesz w dokumentacji.


2. Utwórz moduł dla sayHello()

W najprostszej formie przekształcenie istniejącego procesu w moduł to niewiele więcej niż operacja kopiuj-wklej. Utworzymy plik dla modułu, skopiujemy odpowiedni kod, a następnie usuniemy go z głównego pliku workflow.

Potem wystarczy dodać instrukcję importu, aby Nextflow wiedział, że ma pobrać odpowiedni kod w czasie wykonania.

2.1. Utwórz plik dla nowego modułu

Utwórzmy pusty plik dla modułu o nazwie sayHello.nf.

touch modules/sayHello.nf

To daje nam miejsce na umieszczenie kodu procesu.

2.2. Przenieś kod procesu sayHello do pliku modułu

Skopiuj całą definicję procesu z pliku workflow do pliku modułu, upewniając się, że kopiujesz również shebang #!/usr/bin/env nextflow.

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

/*
 * Użyj echo do wypisania 'Hello World!' do pliku
 */
process sayHello {

    input:
    val greeting

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

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

Po wykonaniu tego usuń definicję procesu z pliku workflow, ale upewnij się, że zostawiasz shebang na miejscu.

2.3. Dodaj deklarację importu przed blokiem workflow

Składnia importowania lokalnego modułu jest dość prosta:

Składnia: Deklaracja importu
include { <NAZWA_MODUŁU> } from '<ścieżka_do_modułu>'

Wstawmy ją powyżej bloku params i wypełnijmy odpowiednio.

hello-modules.nf
// Dołącz moduły
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'
}

Widzisz, że wypełniliśmy nazwę modułu, sayHello, oraz ścieżkę do pliku zawierającego kod modułu, ./modules/sayHello.nf.

2.4. Uruchom workflow

Uruchamiamy workflow z zasadniczo tym samym kodem i wejściami co poprzednio, więc uruchommy z flagą -resume i zobaczmy, co się stanie.

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

To powinno się wykonać bardzo szybko, ponieważ wszystko jest w cache. Możesz sprawdzić opublikowane wyjścia.

Nextflow rozpoznał, że nadal jest to ta sama praca do wykonania, nawet jeśli kod jest podzielony na wiele plików.

Podsumowanie

Wiesz już, jak wyodrębnić proces do lokalnego modułu i wiesz, że nie wpływa to na możliwość wznawiania workflow.

Co dalej?

Ćwicz tworzenie kolejnych modułów. Gdy zrobisz jeden, możesz zrobić milion więcej... Ale na razie zróbmy jeszcze tylko dwa.


3. Zmodularyzuj proces convertToUpper()

3.1. Utwórz plik dla nowego modułu

Utwórz pusty plik dla modułu o nazwie convertToUpper.nf.

touch modules/convertToUpper.nf

3.2. Przenieś kod procesu convertToUpper do pliku modułu

Skopiuj całą definicję procesu z pliku workflow do pliku modułu, upewniając się, że kopiujesz również shebang #!/usr/bin/env nextflow.

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

/*
 * Użyj narzędzia zamiany tekstu do przekształcenia pozdrowienia na wielkie litery
 */
process convertToUpper {

    input:
    path input_file

    output:
    path "UPPER-${input_file}"

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

Po wykonaniu tego usuń definicję procesu z pliku workflow, ale upewnij się, że zostawiasz shebang na miejscu.

3.3. Dodaj deklarację importu przed blokiem params

Wstaw deklarację importu powyżej bloku params i wypełnij ją odpowiednio.

hello-modules.nf
// Dołącz moduły
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
// Dołącz moduły
include { sayHello } from './modules/sayHello.nf'

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

To powinno zacząć wyglądać bardzo znajomo.

3.4. Uruchom workflow ponownie

Uruchom z flagą -resume.

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

To powinno nadal produkować takie same wyjście jak poprzednio.

Dwa zrobione, jeszcze jeden do zrobienia!


4. Zmodularyzuj proces collectGreetings()

4.1. Utwórz plik dla nowego modułu

Utwórz pusty plik dla modułu o nazwie collectGreetings.nf.

touch modules/collectGreetings.nf

4.2. Przenieś kod procesu collectGreetings do pliku modułu

Skopiuj całą definicję procesu z pliku workflow do pliku modułu, upewniając się, że kopiujesz również shebang #!/usr/bin/env nextflow.

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

/*
 * Zbierz pozdrowienia pisane wielkimi literami do jednego pliku wyjściowego
 */
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'
    """
}

Po wykonaniu tego usuń definicję procesu z pliku workflow, ale upewnij się, że zostawiasz shebang na miejscu.

4.3. Dodaj deklarację importu przed blokiem params

Wstaw deklarację importu powyżej bloku params i wypełnij ją odpowiednio.

hello-modules.nf
// Dołącz moduły
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
// Dołącz moduły
include { sayHello } from './modules/sayHello.nf'
include { convertToUpper } from './modules/convertToUpper.nf'

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

Ostatni!

4.4. Uruchom workflow

Uruchom z flagą -resume.

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

To powinno nadal produkować takie same wyjście jak poprzednio.

Podsumowanie

Wiesz już, jak modularyzować wiele procesów w workflow.

Gratulacje, wykonałeś całą tę pracę i absolutnie nic się nie zmieniło w działaniu pipeline!

Żarty na bok, teraz Twój kod jest bardziej modularny, a jeśli zdecydujesz się napisać inny pipeline, który wywołuje jeden z tych procesów, wystarczy wpisać jedną krótką instrukcję importu, aby użyć odpowiedniego modułu. Jest to lepsze niż kopiowanie-wklejanie kodu, ponieważ jeśli później zdecydujesz się ulepszyć moduł, wszystkie Twoje projekty odziedziczą te ulepszenia.

Co dalej?

Zrób krótką przerwę, jeśli masz ochotę.

Gdy będziesz gotowy, przejdź do Część 5: Hello Containers, aby dowiedzieć się, jak używać kontenerów do wygodniejszego i bardziej powtarzalnego zarządzania zależnościami oprogramowania.


Quiz

#

Czym jest moduł w Nextflow?

#

Jaka jest zalecana konwencja nazewnictwa plików modułów?

#

Gdzie powinny być przechowywane pliki modułów?

#

Jaka jest poprawna składnia do importowania modułu?

#

Co się dzieje z funkcjonalnością -resume podczas używania modułów?

#

Jakie są korzyści z używania modułów? (Wybierz wszystkie pasujące)