Parte 6: Configurazione¶
Traduzione assistita da IA - scopri di più e suggerisci miglioramenti
Il tuo plugin ha funzioni personalizzate e un observer, ma tutto è hardcoded. Gli utenti non possono disattivare il contatore delle attività, né cambiare il decoratore, senza modificare il codice sorgente e ricompilare.
Nella Parte 1, hai usato i blocchi validation {} e co2footprint {} in nextflow.config per controllare il comportamento di nf-schema e nf-co2footprint.
Quei blocchi di configurazione esistono perché gli autori del plugin hanno implementato quella funzionalità.
In questa sezione, farai lo stesso per il tuo plugin.
Obiettivi:
- Permettere agli utenti di personalizzare il prefisso e il suffisso del decoratore di saluti
- Permettere agli utenti di abilitare o disabilitare il plugin tramite
nextflow.config - Registrare un config scope formale affinché Nextflow riconosca il blocco
greeting {}
Cosa cambierai:
| File | Modifica |
|---|---|
GreetingExtension.groovy |
Leggere la configurazione di prefisso/suffisso in init() |
GreetingFactory.groovy |
Leggere i valori di configurazione per controllare la creazione dell'observer |
GreetingConfig.groovy |
Nuovo file: classe formale @ConfigScope |
build.gradle |
Registrare la classe di configurazione come extension point |
nextflow.config |
Aggiungere un blocco greeting {} per testarlo |
Stai iniziando da qui?
Se ti unisci a questa parte, copia la soluzione dalla Parte 5 da usare come punto di partenza:
Documentazione ufficiale
Per dettagli completi sulla configurazione, consulta la documentazione sui config scope di Nextflow.
1. Rendere il decoratore configurabile¶
La funzione decorateGreeting avvolge ogni saluto in *** ... ***.
Gli utenti potrebbero volere marcatori diversi, ma al momento l'unico modo per cambiarli è modificare il codice sorgente e ricompilare.
La sessione Nextflow fornisce un metodo chiamato session.config.navigate() che legge valori annidati da nextflow.config:
// Legge 'greeting.prefix' da nextflow.config, con valore predefinito '***'
final prefix = session.config.navigate('greeting.prefix', '***') as String
Questo corrisponde a un blocco di configurazione nel nextflow.config dell'utente:
1.1. Aggiungere la lettura della configurazione (questo fallirà!)¶
Modifica GreetingExtension.groovy per leggere la configurazione in init() e usarla in decorateGreeting():
Prova a compilare:
1.2. Osservare l'errore¶
La compilazione fallisce:
> Task :compileGroovy FAILED
GreetingExtension.groovy: 30: [Static type checking] - The variable [prefix] is undeclared.
@ line 30, column 9.
prefix = session.config.navigate('greeting.prefix', '***') as String
^
GreetingExtension.groovy: 31: [Static type checking] - The variable [suffix] is undeclared.
In Groovy (e Java), è necessario dichiarare una variabile prima di usarla.
Il codice tenta di assegnare valori a prefix e suffix, ma la classe non ha campi con quei nomi.
1.3. Correggere dichiarando le variabili di istanza¶
Aggiungi le dichiarazioni delle variabili all'inizio della classe, subito dopo la parentesi graffa di apertura:
Queste due righe dichiarano variabili di istanza (chiamate anche campi) che appartengono a ogni oggetto GreetingExtension.
La parola chiave private significa che solo il codice all'interno di questa classe può accedervi.
Ogni variabile viene inizializzata con un valore predefinito di '***'.
Quando il plugin viene caricato, Nextflow chiama il metodo init(), che sovrascrive questi valori predefiniti con quelli impostati dall'utente in nextflow.config.
Se l'utente non ha impostato nulla, navigate() restituisce lo stesso valore predefinito, quindi il comportamento rimane invariato.
Il metodo decorateGreeting() legge poi questi campi ogni volta che viene eseguito.
Imparare dagli errori
Questo schema "dichiarare prima di usare" è fondamentale in Java/Groovy, ma può risultare insolito se si proviene da Python o R, dove le variabili prendono vita nel momento in cui vengono assegnate per la prima volta. Incontrare questo errore una volta aiuta a riconoscerlo e correggerlo rapidamente in futuro.
1.4. Compilare e testare¶
Compila e installa:
Aggiorna nextflow.config per personalizzare la decorazione:
Esegui la pipeline:
Il decoratore ora usa il prefisso e il suffisso personalizzati dal file di configurazione.
Nota che Nextflow stampa un avviso "Unrecognized config option" perché nulla ha ancora dichiarato greeting come config scope valido.
Il valore viene comunque letto correttamente tramite navigate(), ma Nextflow lo segnala come non riconosciuto.
Risolverai questo problema nella Sezione 3.
2. Rendere il contatore delle attività configurabile¶
La factory dell'observer attualmente crea gli observer in modo incondizionato. Gli utenti dovrebbero poter disabilitare completamente il plugin tramite la configurazione.
La factory ha accesso alla sessione Nextflow e alla sua configurazione, quindi è il posto giusto per leggere l'impostazione enabled e decidere se creare gli observer.
La factory ora legge greeting.enabled dalla configurazione e restituisce una lista vuota se l'utente l'ha impostato a false.
Quando la lista è vuota, non vengono creati observer, quindi gli hook del ciclo di vita del plugin vengono silenziosamente ignorati.
2.1. Compilare e testare¶
Ricompila e installa il plugin:
Esegui la pipeline per confermare che tutto funzioni ancora:
Disabilitare completamente il plugin
Prova a impostare greeting.enabled = false in nextflow.config ed esegui di nuovo la pipeline.
Cosa cambia nell'output?
Soluzione
// Configurazione per gli esercizi di sviluppo del plugin
plugins {
id 'nf-schema@2.6.1'
id 'nf-greeting@0.1.0'
}
greeting {
enabled = false
}
I messaggi "Pipeline is starting!", "Pipeline complete!" e il conteggio delle attività scompaiono tutti, perché la factory restituisce una lista vuota quando enabled è false.
La pipeline stessa continua a essere eseguita, ma nessun observer è attivo.
Ricordati di reimpostare enabled a true (o di rimuovere la riga) prima di continuare.
3. Configurazione formale con ConfigScope¶
La configurazione del tuo plugin funziona, ma Nextflow stampa ancora avvisi "Unrecognized config option".
Questo accade perché session.config.navigate() si limita a leggere i valori; nulla ha comunicato a Nextflow che greeting è un config scope valido.
Una classe ConfigScope colma questa lacuna.
Dichiara quali opzioni accetta il tuo plugin, i loro tipi e i loro valori predefiniti.
Non sostituisce le chiamate a navigate(). Lavora invece insieme a esse:
flowchart LR
A["nextflow.config<br/>greeting { ... }"] --> B["ConfigScope<br/><i>declares valid options</i>"]
A --> C["navigate()<br/><i>reads values at runtime</i>"]
B -. "validates &<br/>documents" .-> A
C -- "provides values to" --> D["Plugin code<br/><i>factory, extension</i>"]
style B fill:#e8f5e9,stroke:#4caf50
style C fill:#e3f2fd,stroke:#2196f3
Senza una classe ConfigScope, navigate() funziona comunque, ma:
- Nextflow avvisa sulle opzioni non riconosciute (come hai già visto)
- Nessun autocompletamento IDE per gli utenti che scrivono
nextflow.config - Le opzioni di configurazione non si autodocumentano
- La conversione dei tipi è manuale (
as String,as boolean)
Registrare una classe formale di config scope risolve l'avviso e affronta tutti e tre i problemi.
Questo è lo stesso meccanismo alla base dei blocchi validation {} e co2footprint {} che hai usato nella Parte 1.
3.1. Creare la classe di configurazione¶
Crea un nuovo file:
Aggiungi la classe di configurazione con tutte e tre le opzioni:
- Corrisponde al blocco
greeting { }innextflow.config - Interfaccia obbligatoria per le classi di configurazione
- Sia il costruttore senza argomenti che quello con Map sono necessari affinché Nextflow possa istanziare la configurazione
@ConfigOptioncontrassegna un campo come opzione di configurazione;@Descriptionlo documenta per gli strumenti di sviluppo
Punti chiave:
@ScopeName('greeting'): Corrisponde al bloccogreeting { }nella configurazioneimplements ConfigScope: Interfaccia obbligatoria per le classi di configurazione@ConfigOption: Ogni campo diventa un'opzione di configurazione@Description: Documenta ogni opzione per il supporto del language server (importato danextflow.script.dsl)- Costruttori: Sono necessari sia il costruttore senza argomenti che quello con Map
3.2. Registrare la classe di configurazione¶
Creare la classe non è sufficiente da sola.
Nextflow deve sapere che esiste, quindi la registri in build.gradle insieme agli altri extension point.
Nota la differenza tra la registrazione della factory e degli extension point:
extensionPointsinbuild.gradle: Registrazione a tempo di compilazione. Indica al sistema di plugin di Nextflow quali classi implementano gli extension point.- Metodo
create()della factory: Registrazione a runtime. La factory crea le istanze degli observer quando un flusso di lavoro viene effettivamente avviato.
3.3. Compilare e testare¶
Il comportamento della pipeline è identico, ma l'avviso "Unrecognized config option" è scomparso.
Cosa è cambiato e cosa no
GreetingFactory e GreetingExtension usano ancora session.config.navigate() per leggere i valori a runtime.
Nessuno di quel codice è cambiato.
La classe ConfigScope è una dichiarazione parallela che comunica a Nextflow quali opzioni esistono.
Entrambi gli elementi sono necessari: ConfigScope dichiara, navigate() legge.
Il tuo plugin ha ora la stessa struttura dei plugin che hai usato nella Parte 1.
Quando nf-schema espone un blocco validation {} o nf-co2footprint espone un blocco co2footprint {}, usano esattamente questo schema: una classe ConfigScope con campi annotati, registrata come extension point.
Il tuo blocco greeting {} funziona allo stesso modo.
Takeaway¶
Hai imparato che:
session.config.navigate()legge i valori di configurazione a runtime- Le classi
@ConfigScopedichiarano quali opzioni di configurazione esistono; lavorano insieme anavigate(), non al suo posto - La configurazione può essere applicata sia agli observer che alle funzioni di extension
- Le variabili di istanza devono essere dichiarate prima dell'uso in Groovy/Java;
init()le popola dalla configurazione quando il plugin viene caricato
| Caso d'uso | Approccio consigliato |
|---|---|
| Prototipo rapido o plugin semplice | Solo session.config.navigate() |
| Plugin di produzione con molte opzioni | Aggiungere una classe ConfigScope insieme alle chiamate navigate() |
| Plugin che condividerai pubblicamente | Aggiungere una classe ConfigScope insieme alle chiamate navigate() |
Cosa c'è dopo?¶
Il tuo plugin ha ora tutti gli elementi di un plugin di produzione: funzioni personalizzate, trace observer e configurazione accessibile agli utenti. Il passo finale è prepararlo per la distribuzione.