Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linting: lint nextflow.config default values match the ones specified in nextflow_schema.json #2684

Merged
merged 4 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Fix linting of a pipeline with patched custom module ([#2669](https://github.com/nf-core/tools/pull/2669))
- linting a pipeline also lints the installed subworkflows ([#2677](https://github.com/nf-core/tools/pull/2677))
- environment.yml name must be lowercase ([#2676](https://github.com/nf-core/tools/pull/2676))
- lint `nextflow.config` default values match the ones specified in `nextflow_schema.json` ([#2684](https://github.com/nf-core/tools/pull/2684))

### Modules

Expand Down
51 changes: 51 additions & 0 deletions nf_core/lint/nextflow_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import logging
import os
import re
from pathlib import Path

from nf_core.schema import PipelineSchema

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -113,6 +116,18 @@ def nextflow_config(self):

* A ``test`` configuration profile should exist.

**The default values in ``nextflow.config`` should match the default values defined in the ``nextflow_schema.json``.**

.. tip:: You can choose to ignore tests for the default value of an specific parameter
by creating a file called ``.nf-core.yml`` in the root of your pipeline and creating
a list the config parameters that should be ignored. For example to ignore the default value for the input parameter:

.. code-block:: yaml

lint:
nextflow_config:
- config_defaults:
- params.input
"""
passed = []
warned = []
Expand Down Expand Up @@ -347,4 +362,40 @@ def nextflow_config(self):
else:
failed.append("nextflow.config does not contain configuration profile `test`")

# Check that the default values in nextflow.config match the default values defined in the nextflow_schema.json
ignore_defaults = []
for item in ignore_configs:
if isinstance(item, dict) and "config_defaults" in item:
ignore_defaults = item.get("config_defaults", [])
schema_path = Path(self.wf_path) / "nextflow_schema.json"
schema = PipelineSchema()
schema.schema_filename = schema_path
schema.no_prompts = True
schema.load_schema()
schema.get_schema_defaults() # Get default values from schema
self.nf_config.keys() # Params in nextflow.config
for param_name in schema.schema_defaults.keys():
param = "params." + param_name
# Convert booleans to strings if needed
schema_default = (
"true"
if str(schema.schema_defaults[param_name]) == "True"
else "false"
if str(schema.schema_defaults[param_name]) == "False"
else str(schema.schema_defaults[param_name])
)
if param in ignore_defaults:
ignored.append(f"Config default ignored: {param}")
elif param in self.nf_config.keys():
if str(self.nf_config[param]) == schema_default:
passed.append(f"Config default value correct: {param}")
else:
failed.append(
f"Config default value incorrect: `{param}` is set as {self._wrap_quotes(schema_default)} in `nextflow_schema.json` but is {self._wrap_quotes(self.nf_config[param])} in `nextflow.config`."
)
else:
failed.append(
f"Default value from the Nextflow schema '{param} = {self._wrap_quotes(schema_default)}' not found in `nextflow.config`."
)

return {"passed": passed, "warned": warned, "failed": failed, "ignored": ignored}
64 changes: 64 additions & 0 deletions tests/lint/nextflow_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import re
from pathlib import Path

import nf_core.create
import nf_core.lint
Expand Down Expand Up @@ -53,3 +54,66 @@ def test_nextflow_config_missing_test_profile_failed(self):
result = lint_obj.nextflow_config()
assert len(result["failed"]) > 0
assert len(result["warned"]) == 0


def test_default_values_match(self):
"""Test that the default values in nextflow.config match the default values defined in the nextflow_schema.json."""
new_pipeline = self._make_pipeline_copy()
lint_obj = nf_core.lint.PipelineLint(new_pipeline)
lint_obj._load_pipeline_config()
result = lint_obj.nextflow_config()
assert len(result["failed"]) == 0
assert len(result["warned"]) == 0
assert "Config default value correct: params.max_cpus" in result["passed"]
assert "Config default value correct: params.validate_params" in result["passed"]


def test_default_values_fail(self):
"""Test linting fails if the default values in nextflow.config do not match the ones defined in the nextflow_schema.json."""
new_pipeline = self._make_pipeline_copy()
# Change the default value of max_cpus in nextflow.config
nf_conf_file = Path(new_pipeline) / "nextflow.config"
with open(nf_conf_file) as f:
content = f.read()
fail_content = re.sub(r"\bmax_cpus = 16\b", "max_cpus = 0", content)
with open(nf_conf_file, "w") as f:
f.write(fail_content)
# Change the default value of max_memory in nextflow_schema.json
nf_schema_file = Path(new_pipeline) / "nextflow_schema.json"
with open(nf_schema_file) as f:
content = f.read()
fail_content = re.sub(r'"default": "128.GB"', '"default": "18.GB"', content)
print(fail_content)
with open(nf_schema_file, "w") as f:
f.write(fail_content)
lint_obj = nf_core.lint.PipelineLint(new_pipeline)
lint_obj._load_pipeline_config()
result = lint_obj.nextflow_config()
assert len(result["failed"]) == 2
assert (
"Config default value incorrect: `params.max_cpus` is set as `16` in `nextflow_schema.json` but is `0` in `nextflow.config`."
in result["failed"]
)
assert (
"Config default value incorrect: `params.max_memory` is set as `18.GB` in `nextflow_schema.json` but is `128.GB` in `nextflow.config`."
in result["failed"]
)


def test_default_values_ignored(self):
"""Test ignoring linting of default values."""
new_pipeline = self._make_pipeline_copy()
# Add max_cpus to the ignore list
nf_core_yml = Path(new_pipeline) / ".nf-core.yml"
with open(nf_core_yml, "w") as f:
f.write(
"repository_type: pipeline\nlint:\n nextflow_config:\n - config_defaults:\n - params.max_cpus\n"
)
lint_obj = nf_core.lint.PipelineLint(new_pipeline)
lint_obj._load_pipeline_config()
lint_obj._load_lint_config()
result = lint_obj.nextflow_config()
assert len(result["failed"]) == 0
assert len(result["ignored"]) == 1
assert "Config default value correct: params.max_cpus" not in result["passed"]
assert "Config default ignored: params.max_cpus" in result["ignored"]
3 changes: 3 additions & 0 deletions tests/test_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ def test_sphinx_md_files(self):
test_multiqc_incorrect_export_plots,
)
from .lint.nextflow_config import ( # type: ignore[misc]
test_default_values_fail,
test_default_values_ignored,
test_default_values_match,
test_nextflow_config_bad_name_fail,
test_nextflow_config_dev_in_release_mode_failed,
test_nextflow_config_example_pass,
Expand Down
Loading