Skip to content

Fix: Add no-arg constructors for v2 config parser scope registration#362

Merged
JosuaCarl merged 11 commits intonextflow-io:devfrom
pinin4fjords:fix/config-scope-noarg-constructor
May 6, 2026
Merged

Fix: Add no-arg constructors for v2 config parser scope registration#362
JosuaCarl merged 11 commits intonextflow-io:devfrom
pinin4fjords:fix/config-scope-noarg-constructor

Conversation

@pinin4fjords
Copy link
Copy Markdown
Contributor

@pinin4fjords pinin4fjords commented Mar 25, 2026

Summary

Eliminates WARN: Unrecognized config option 'co2footprint.*' warnings under Nextflow's v2 syntax parser (NXF_SYNTAX_PARSER=v2, the default in 26.04+).

Problem

The v2 parser validates config keys by reflectively inspecting ConfigScope implementations. Without proper registration the parser cannot discover the co2footprint scope, so every co2footprint.* option triggers an "Unrecognized" warning even though the values still work at runtime.

Fix (per Ben's review)

Following nf-schema's ValidationConfig pattern, with the rules clarified across the review:

  1. Top-level scope (CO2FootprintConfig) carries the full ceremony:
    • @ScopeName('co2footprint')
    • no-arg constructor
    • listed in build.gradle extensionPoints
  2. Nested scope fields on CO2FootprintConfig (trace, summary, report, provenance) carry only @Description - no @ConfigOption (the parser walks fields whose type implements ConfigScope).
  3. Nested scope classes (TraceFileConfig, SummaryFileConfig, ReportFileConfig, ProvenanceFileConfig) drop @ScopeName and the no-arg constructor.
  4. @ConfigOption fields are not inherited. The v2 parser uses getDeclaredFields(), so BaseFileConfig's shared file/enabled/overwrite were invisible. Each nested scope class now declares those fields itself; BaseFileConfig is demoted to a plain helper providing defineFile(), defineEnabled(), defineOverwrite() utilities.
  5. types=[...] on @ConfigOption is restricted to its intended purpose (extra accepted standard types). Removed from fields that were using it for hint purposes; kept on ci (types=[Number, BigDecimal]) since CiRecord is constructed from a number.

Test plan

  • ./gradlew compileGroovy passes
  • ./gradlew test passes (151/152 unit tests; the one failure is CO2PluginFullTest, an integration test that requires Linux Docker - passes on CI)
  • Manual: live pipeline run with NXF_VER=26.04.0 NXF_SYNTAX_PARSER=v2 and a config exercising every option (top-level + all four nested scopes including provenance.emissionMetricsOnly, plus the Closure<Number> cpuPowerModel and Path customCpuTdpFile fields). Result: zero Unrecognized config option warnings. Sanity-checked by introducing a deliberately-misnamed option, which the validator correctly flagged.

Nextflow's v2 syntax parser requires ConfigScope implementations to
have a no-arg constructor so it can reflectively instantiate them at
parse time to discover and validate config options. Without this,
the co2footprint scope and its sub-scopes are not registered, causing
"Unrecognized config option" warnings for all co2footprint.* settings.

This adds no-arg constructors to CO2FootprintConfig and all
BaseFileConfig subclasses (TraceFileConfig, SummaryFileConfig,
ReportFileConfig, DataFileConfig), following the same pattern used
by nf-schema's ValidationConfig.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Jonathan Manning <[email protected]>
@pinin4fjords pinin4fjords force-pushed the fix/config-scope-noarg-constructor branch from 50d7f74 to 2745da2 Compare March 25, 2026 11:58
JosuaCarl
JosuaCarl previously approved these changes Mar 25, 2026
Copy link
Copy Markdown
Collaborator

@JosuaCarl JosuaCarl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I was not up-to-date regarding this requirement. Thanks for your addition 👍

@JosuaCarl JosuaCarl dismissed their stale review March 25, 2026 12:30

Accidentally still tried it with v1 parser. On v2 the warning still appears.

@JosuaCarl
Copy link
Copy Markdown
Collaborator

JosuaCarl commented Mar 25, 2026

There seems to be something wrong with the recognition of ConfigScope classes in our plugin. I don't know why and opened the issue nextflow-io/nextflow#6974 at the core repo. Maybe someone there knows what's going on.

Until then, I would put the approval on halt to preserve the discussion, although it seems like a good alignment to the template.

@JosuaCarl JosuaCarl self-assigned this Mar 25, 2026
@JosuaCarl JosuaCarl added 🪲 bug Something isn't working 📣 logging Concerning logging/warning/error throwing labels Mar 25, 2026
Comment thread src/main/nextflow/co2footprint/CO2FootprintConfig.groovy Outdated
Comment thread src/main/nextflow/co2footprint/CO2FootprintConfig.groovy Outdated
Comment thread src/main/nextflow/co2footprint/Config/DataFileConfig.groovy Outdated
Comment thread src/main/nextflow/co2footprint/Config/DataFileConfig.groovy Outdated
Comment thread src/main/nextflow/co2footprint/CO2FootprintConfig.groovy
@pinin4fjords
Copy link
Copy Markdown
Contributor Author

Apologies if I got stuff wrong!

@bentsherman
Copy link
Copy Markdown
Member

You need to add the top-level config scope to the list of extension points:

https://github.com/pinin4fjords/nf-co2footprint/blob/2745da2a2687e48001ca52acacb338bf0830b813/build.gradle#L108-L111

Most of the ceremony is only needed for the top-level scope:

  • the @ScopeName annotation
  • the no-arg constructor
  • including in the list of extension points

All of the nested scope classes should be referenced by fields in the top-level scope class, so they get pulled in that way

@pinin4fjords
Copy link
Copy Markdown
Contributor Author

Thanks Ben, really helpful review - applied all your suggestions:

  • Registered CO2FootprintConfig in build.gradle extensionPoints
  • Removed @ScopeName from nested scope classes (they get pulled in via fields on the top-level scope)
  • Removed no-arg constructors from nested scopes and BaseFileConfig
  • Stripped unnecessary types=[...] from @ConfigOption annotations (kept types=[Number, BigDecimal] on ci since it constructs a CiRecord from a number)

Per Ben's review, only the top-level scope needs @ScopeName, a no-arg
constructor, and extension point registration. Nested scopes are
discovered via fields on the parent class.

- Register CO2FootprintConfig in build.gradle extensionPoints
- Remove @ScopeName from nested scope classes (Trace/Summary/Report/DataFileConfig)
- Remove no-arg constructors from nested scopes and BaseFileConfig
- Remove unnecessary types=[...] from @ConfigOption annotations
  (kept types=[Number, BigDecimal] on ci since it constructs CiRecord from a number)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Jonathan Manning <[email protected]>
@pinin4fjords pinin4fjords force-pushed the fix/config-scope-noarg-constructor branch from ae79c64 to 80c3e23 Compare March 26, 2026 12:54
@pinin4fjords
Copy link
Copy Markdown
Contributor Author

@JosuaCarl hopefully this is better now. FYI the reason I'm doing this is because we use this plugin as an example in our new training: https://training.nextflow.io/0.dev/side_quests/plugin_development/01_plugin_basics/.

@JosuaCarl
Copy link
Copy Markdown
Collaborator

JosuaCarl commented Apr 9, 2026

Hi, I was on vacation for the last two weeks, so sorry for the wait.

@pinin4fjords We are very excited to see our work integrated into the training, thanks :)
Good job on incorporating the suggested changes, but I would prefer the more verbose ConfigOption to have a way of knowing which values are expected (can also be helpful during debugging).

@bentsherman With the suggested changes the top-scope warnings are gone, but all lower-level/nested scopes are still persistent:

WARN: Unrecognized config option 'co2footprint.trace.file'
WARN: Unrecognized config option 'co2footprint.summary.file'
WARN: Unrecognized config option 'co2footprint.report.file'
WARN: Unrecognized config option 'co2footprint.dataFile.file'
WARN: Unrecognized config option 'co2footprint.dataFile.enabled'
WARN: Unrecognized config option 'co2footprint.dataFile.emissionMetricsOnly'

Do you have any idea how that could be addressed?
I tried adding the file configs to the extensions in build.gradle, but to no avail.

@JosuaCarl
Copy link
Copy Markdown
Collaborator

@bentsherman So I take it you have no idea why the nested plugin scopes are still in the warning?

Comment thread src/main/nextflow/co2footprint/CO2FootprintConfig.groovy Outdated
@bentsherman
Copy link
Copy Markdown
Member

I would prefer the more verbose ConfigOption to have a way of knowing which values are expected (can also be helpful during debugging).

The types option here should only be used to specify standard Nextflow types. These additional types are used by the language server to give guidance to the user, so if you use arbitrary runtime types like GString and Number, it will likely create confusing error messages

With the suggested changes the top-scope warnings are gone, but all lower-level/nested scopes are still persistent

I think there are two reasons:

  1. Some config options are defined in a superclass BaseFileConfig. These fields should be defined in each config scope class
  2. Fields that refer to nested config scopes don't need @ConfigOption -- I have pointed them out in the above comment

JosuaCarl added 2 commits May 4, 2026 11:09
# Conflicts:
#	src/main/nextflow/co2footprint/CO2FootprintConfig.groovy
#	src/main/nextflow/co2footprint/Config/DataFileConfig.groovy
Refactor: Removed nested ConfigOption annotations
Signed-off-by: Josua Carl <[email protected]>
@JosuaCarl
Copy link
Copy Markdown
Collaborator

I tried various configurations to get nested scopes on the nested provenance.emissionMetricsOnly option to work, but to no avail.

@ScopeName('co2footprint.provenance') X X X X
@ConfigOption boolean emissionMetricsOnly X X X
Add class to build 'nextflow.co2footprint.Config.CO2FootprintProvenanceFileConfig' X X X
@ConfigOption ProvenanceFileConfig provenance X X X X X X X
Result

What I don't want is to change the complete structure by eliminating BaseFileConfig, but this was not the case for emissionMetricsOnly anyway.

I will proceed with a workaround by declaring the nested configs as a Map @ConfigOption(types=[Map]). This eliminates the warning because it would be a valid method of supplying maps, but I am a bit unhappy about this outcome.

@JosuaCarl
Copy link
Copy Markdown
Collaborator

Update: In the end I deconstructed some of the BaseFileConfig, so the options would get recognized. I would encourage a better documentation for when (not) to use which annotation. Or are there any resources I have missed, regarding this topic?

@JosuaCarl
Copy link
Copy Markdown
Collaborator

JosuaCarl commented May 4, 2026

@pinin4fjords I made a PR onto your fix branch (pinin4fjords#1), to preserve this PR.

…or-2

Fix/config scope noarg constructor 2
Resolves conflicts in:
- src/main/nextflow/co2footprint/Config/BaseFileConfig.groovy
  (drop @ConfigOption imports; the annotations live on each subclass now)
- src/main/nextflow/co2footprint/Logging/CustomCaptureAppender.groovy
  (take dev's 26.04.0 LogObserver adaptation)
- src/testResources/{cli,observer,report}/* (take dev's calculator outputs)
- Mark file/enabled/overwrite/maxTasks final on the four nested file scopes
  and final on name/ending/defaultEnabled in BaseFileConfig (each is
  assigned exactly once in a constructor body)
- Normalise whitespace: drop trailing spaces and double-space after `=`
- Add CHANGELOG entry under New > Bug Fixes

Signed-off-by: Jonathan Manning <[email protected]>
@pinin4fjords
Copy link
Copy Markdown
Contributor Author

@JosuaCarl thanks for all the work fixing this up.

@bentsherman as a follow-up I've had a go at writing up the rules in nextflow-io/nextflow#7098 (extensionPoints registration, nested scope discovery, the getDeclaredFields() inheritance behaviour). It's based on what I picked up from this thread rather than first-hand expertise, so likely needs corrections. Would welcome your review.

Copy link
Copy Markdown
Collaborator

@JosuaCarl JosuaCarl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this topic and the documentation update 👍

@JosuaCarl JosuaCarl merged commit 4a1590e into nextflow-io:dev May 6, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🪲 bug Something isn't working 📣 logging Concerning logging/warning/error throwing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants