Skip to content

Commit 8bb2b36

Browse files
committed
Workflow params
Signed-off-by: Ben Sherman <bentshermann@gmail.com>
1 parent 2d76d8f commit 8bb2b36

44 files changed

Lines changed: 945 additions & 243 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/migrations/25-10.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,33 @@ This page summarizes the upcoming changes in Nextflow 25.10, which will be relea
88
This page is a work in progress and will be updated as features are finalized. It should not be considered complete until the 25.10 release.
99
:::
1010

11+
## New features
12+
13+
<h3>Workflow params</h3>
14+
15+
The `params` block is a new way to declare pipeline parameters in a Nextflow script:
16+
17+
```nextflow
18+
params {
19+
// Path to input data.
20+
input: Path
21+
22+
// Whether to save intermediate files.
23+
save_intermeds: Boolean = false
24+
}
25+
26+
workflow {
27+
println "params.input = ${params.input}"
28+
println "params.save_intermeds = ${params.save_intermeds}"
29+
}
30+
```
31+
32+
This syntax allows you to declare all parameters in one place with explicit type annotations, and it allows Nextflow to validate parameters at runtime.
33+
34+
See {ref}`workflow-params-def` for details.
35+
1136
## Breaking changes
1237

1338
- The AWS Java SDK used by Nextflow was upgraded from v1 to v2, which introduced some breaking changes to the `aws.client` config options. See {ref}`the guide <aws-java-sdk-v2-page>` for details.
39+
40+
- The legacy type detection of CLI parameters is disabled when using the strict syntax (`NXF_SYNTAX_PARSER=v2`). {ref}`Legacy parameters <workflow-params-legacy>` in the strict syntax should not rely on legacy type detection. Alternatively, use the new `params` block to convert CLI parameters based on their type annotations. Legacy type detection can be disabled globally by setting the environment variable `NXF_DISABLE_PARAMS_TYPE_DETECTION=true`.

docs/reference/syntax.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ A Nextflow script may contain the following top-level declarations:
2828
- Shebang
2929
- Feature flags
3030
- Include declarations
31-
- Parameter declarations
31+
- Params block
32+
- Parameter declarations (legacy)
3233
- Workflow definitions
3334
- Process definitions
3435
- Function definitions
@@ -107,9 +108,22 @@ The following definitions can be included:
107108
- Processes
108109
- Named workflows
109110

110-
### Parameter
111+
### Params block
111112

112-
A parameter declaration is an assignment. The target should be a pipeline parameter and the source should be an expression:
113+
The params block consists of one or more *parameter declarations*. A parameter declaration consists of a name and an optional default value:
114+
115+
```nextflow
116+
params {
117+
input: Path
118+
save_intermeds: Boolean = false
119+
}
120+
```
121+
122+
Only one params block may be defined in a script.
123+
124+
### Parameter (legacy)
125+
126+
A legacy parameter declaration is an assignment. The target should be a pipeline parameter and the source should be an expression:
113127

114128
```nextflow
115129
params.message = 'Hello world!'

docs/vscode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The language server parses scripts and config files according to the {ref}`Nextf
2626

2727
When you hover over certain source code elements, such as variable names and function calls, the extension provides a tooltip with related information, such as the definition and/or documentation for the element.
2828

29-
If a [Javadoc](https://en.wikipedia.org/wiki/Javadoc) comment is defined above a workflow, process, or function, the extension will include the contents of the comment in hover hints. The following is an example Javadoc comment:
29+
If a [Javadoc](https://en.wikipedia.org/wiki/Javadoc) comment is defined above a workflow, process, function, or parameter in a `params` block, the extension will include the contents of the comment in hover hints. The following is an example Javadoc comment:
3030

3131
```nextflow
3232
/**

docs/workflow.md

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,60 @@ workflow {
2222
}
2323
```
2424

25-
### Parameters
25+
(workflow-params-def)=
26+
27+
## Parameters
28+
29+
Parameters can be declared in a Nextflow script with the `params` block or with *legacy* parameter declarations.
30+
31+
### Params block
32+
33+
:::{versionadded} 25.10.0
34+
:::
35+
36+
:::{note}
37+
This feature requires the {ref}`strict syntax <strict-syntax-page>` to be enabled (`NXF_SYNTAX_PARSER=v2`).
38+
:::
39+
40+
A script can declare parameters using the `params` block:
41+
42+
```nextflow
43+
params {
44+
// Path to input data.
45+
input: Path
46+
47+
// Whether to save intermediate files.
48+
save_intermeds: Boolean = false
49+
}
50+
```
51+
52+
The following types can be used for parameters:
53+
54+
- Boolean
55+
- Integer
56+
- Number
57+
- {ref}`stdlib-types-path`
58+
- {ref}`stdlib-types-string`
59+
60+
Parameters can be used in the entry workflow:
61+
62+
```nextflow
63+
workflow {
64+
analyze(params.input, params.save_intermeds)
65+
}
66+
```
67+
68+
:::{note}
69+
As a best practice, params should be used only in the entry workflow and passed to workflows and processes as explicit inputs.
70+
:::
71+
72+
The default value can be overridden by the command line, params file, or config file. Parameters from multiple sources are resolved in the order described in {ref}`cli-params`. Parameters specified on the command line are converted to the appropriate type based on the corresponding type annotation.
73+
74+
A parameter that doesn't specify a default value is a *required* param. If a required param is not given a value at runtime, the run will fail.
75+
76+
(workflow-params-legacy)=
77+
78+
### Legacy parameters
2679

2780
Parameters can be declared by assigning a `params` property to a default value:
2881

@@ -38,10 +91,6 @@ workflow {
3891
}
3992
```
4093

41-
:::{note}
42-
As a best practice, params should be used only in the entry workflow and passed to workflows and processes as explicit inputs.
43-
:::
44-
4594
The default value can be overridden by the command line, params file, or config file. Parameters from multiple sources are resolved in the order described in {ref}`cli-params`.
4695

4796
## Named workflows

modules/nextflow/src/main/groovy/nextflow/Session.groovy

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ class Session implements ISession {
113113
*/
114114
ScriptBinding binding
115115

116+
/**
117+
* Params that were specified on the command line.
118+
*/
119+
Map cliParams
120+
121+
/**
122+
* Params that were specified in the configuration.
123+
*/
124+
Map configParams
125+
116126
/**
117127
* Holds the configuration object
118128
*/
@@ -418,7 +428,7 @@ class Session implements ISession {
418428
/**
419429
* Initialize the session workDir, libDir, baseDir and scriptName variables
420430
*/
421-
Session init( ScriptFile scriptFile, List<String> args=null ) {
431+
Session init( ScriptFile scriptFile, List<String> args=null, Map<String,?> cliParams=null, Map<String,?> configParams=null ) {
422432

423433
if(!workDir.mkdirs()) throw new AbortOperationException("Cannot create work-dir: $workDir -- Make sure you have write permissions or specify a different directory by using the `-w` command line option")
424434
log.debug "Work-dir: ${workDir.toUriString()} [${FileHelper.getPathFsType(workDir)}]"
@@ -445,6 +455,8 @@ class Session implements ISession {
445455
this.workflowMetadata = new WorkflowMetadata(this, scriptFile)
446456

447457
// configure script params
458+
this.cliParams = cliParams
459+
this.configParams = configParams
448460
binding.setParams( (Map)config.params )
449461
binding.setArgs( new ScriptRunner.ArgsList(args) )
450462

modules/nextflow/src/main/groovy/nextflow/cli/CmdRun.groovy

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,12 +325,18 @@ class CmdRun extends CmdBase implements HubOptions {
325325
// -- specify the arguments
326326
final scriptFile = getScriptFile(pipeline)
327327

328+
// -- load command line params
329+
final baseDir = scriptFile.parent
330+
final cliParams = parsedParams(ConfigBuilder.getConfigVars(baseDir))
331+
328332
// create the config object
329333
final builder = new ConfigBuilder()
330334
.setOptions(launcher.options)
331335
.setCmdRun(this)
332-
.setBaseDir(scriptFile.parent)
333-
final config = builder .build()
336+
.setBaseDir(baseDir)
337+
.setCliParams(cliParams)
338+
final config = builder.build()
339+
final configParams = builder.getConfigParams()
334340

335341
// check DSL syntax in the config
336342
launchInfo(config, scriptFile)
@@ -376,7 +382,7 @@ class CmdRun extends CmdBase implements HubOptions {
376382
}
377383

378384
// -- run it!
379-
runner.execute(scriptArgs, this.entryName)
385+
runner.execute(scriptArgs, cliParams, configParams, this.entryName)
380386
}
381387

382388
protected void printBanner() {
@@ -698,7 +704,7 @@ class CmdRun extends CmdBase implements HubOptions {
698704
}
699705

700706
static protected parseParamValue(String str) {
701-
if ( SysEnv.get('NXF_DISABLE_PARAMS_TYPE_DETECTION') )
707+
if ( SysEnv.get('NXF_DISABLE_PARAMS_TYPE_DETECTION') || NF.isSyntaxParserV2() )
702708
return str
703709

704710
if ( str == null ) return null

modules/nextflow/src/main/groovy/nextflow/config/ConfigBuilder.groovy

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class ConfigBuilder {
6161

6262
Path currentDir
6363

64+
Map<String,?> cliParams
65+
6466
boolean showAllProfiles
6567

6668
String profile = DEFAULT_PROFILE
@@ -81,9 +83,11 @@ class ConfigBuilder {
8183

8284
Map<String,String> env = new HashMap<>(System.getenv())
8385

84-
List<String> warnings = new ArrayList<>(10);
86+
List<String> warnings = new ArrayList<>(10)
87+
88+
Map<String,Object> declaredParams = [:]
8589

86-
{
90+
ConfigBuilder() {
8791
setHomeDir(Const.APP_HOME_DIR)
8892
setCurrentDir(Paths.get('.'))
8993
}
@@ -114,6 +118,11 @@ class ConfigBuilder {
114118
return this
115119
}
116120

121+
ConfigBuilder setCliParams( Map<String,?> cliParams ) {
122+
this.cliParams = cliParams
123+
return this
124+
}
125+
117126
ConfigBuilder setBaseDir( Path path ) {
118127
this.baseDir = path.complete()
119128
return this
@@ -162,6 +171,10 @@ class ConfigBuilder {
162171
return this
163172
}
164173

174+
Map<String,Object> getConfigParams() {
175+
return declaredParams
176+
}
177+
165178
static private wrapValue( value ) {
166179
if( !value )
167180
return ''
@@ -327,11 +340,11 @@ class ConfigBuilder {
327340
// this is needed to make sure to reuse the same
328341
// instance of the config vars across different instances of the ConfigBuilder
329342
// and prevent multiple parsing of the same params file (which can even be remote resource)
330-
return cacheableConfigVars(baseDir)
343+
return getConfigVars(baseDir)
331344
}
332345

333346
@Memoized
334-
static private Map cacheableConfigVars(Path base) {
347+
static Map getConfigVars(Path base) {
335348
final binding = new HashMap(10)
336349
binding.put('baseDir', base)
337350
binding.put('projectDir', base)
@@ -351,8 +364,8 @@ class ConfigBuilder {
351364
.setIgnoreIncludes(ignoreIncludes)
352365
ConfigObject result = new ConfigObject()
353366

354-
if( cmdRun && (cmdRun.hasParams()) )
355-
parser.setParams(cmdRun.parsedParams(configVars()))
367+
if( cliParams )
368+
parser.setParams(cliParams)
356369

357370
// add the user specified environment to the session env
358371
env.sort().each { name, value -> result.env.put(name,value) }
@@ -383,7 +396,7 @@ class ConfigBuilder {
383396
}
384397

385398
if( validateProfile ) {
386-
checkValidProfile(parser.getProfiles())
399+
checkValidProfile(parser.getDeclaredProfiles())
387400
}
388401

389402
}
@@ -417,6 +430,7 @@ class ConfigBuilder {
417430
final config = parse0(parser, entry)
418431
if( NF.getSyntaxParserVersion() == 'v1' )
419432
validate(config, entry)
433+
declaredParams.putAll(parser.getDeclaredParams())
420434
result.merge(config)
421435
}
422436

@@ -734,8 +748,8 @@ class ConfigBuilder {
734748
}
735749

736750
// -- add the command line parameters to the 'taskConfig' object
737-
if( cmdRun.hasParams() )
738-
config.params = mergeMaps( (Map)config.params, cmdRun.parsedParams(configVars()), NF.strictMode )
751+
if( cliParams )
752+
config.params = mergeMaps( (Map)config.params, cliParams, NF.strictMode )
739753

740754
if( cmdRun.withoutDocker && config.docker instanceof Map ) {
741755
// disable docker execution

modules/nextflow/src/main/groovy/nextflow/config/ConfigParser.groovy

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ interface ConfigParser {
6767
*/
6868
ConfigParser setParams(Map vars)
6969

70+
/**
71+
* Set the profiles that should be applied.
72+
*/
73+
ConfigParser setProfiles(List<String> profiles)
74+
7075
/**
7176
* Parse a config object from the given source.
7277
*/
@@ -75,13 +80,13 @@ interface ConfigParser {
7580
ConfigObject parse(Path path)
7681

7782
/**
78-
* Set the profiles that should be applied.
83+
* Get the set of declared profiles.
7984
*/
80-
ConfigParser setProfiles(List<String> profiles)
85+
Set<String> getDeclaredProfiles()
8186

8287
/**
83-
* Get the set of available profiles.
88+
* Get the map of declared params.
8489
*/
85-
Set<String> getProfiles()
90+
Map<String,Object> getDeclaredParams()
8691

8792
}

modules/nextflow/src/main/groovy/nextflow/config/parser/v1/ConfigParserV1.groovy

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,15 @@ class ConfigParserV1 implements ConfigParser {
123123
}
124124

125125
@Override
126-
Set<String> getProfiles() {
126+
Set<String> getDeclaredProfiles() {
127127
Collections.unmodifiableSet(conditionalNames)
128128
}
129129

130+
@Override
131+
Map<String,Object> getDeclaredParams() {
132+
[:]
133+
}
134+
130135
private Grengine getGrengine() {
131136
if( grengine ) {
132137
return grengine

0 commit comments

Comments
 (0)