Skip to content

Commit

Permalink
Merge branch 'dev' into nicer-lint-bot-comment
Browse files Browse the repository at this point in the history
  • Loading branch information
mashehu authored Jan 26, 2024
2 parents 14fdea5 + 86ffafe commit 6f52fac
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 1 deletion.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Remove `nfcore_external_java_deps.jar` from lib directory in pipeline template ([#2675](https://github.com/nf-core/tools/pull/2675))
- Add function to check `-profile` is well formatted ([#2678](https://github.com/nf-core/tools/pull/2678))
- Add new pipeline error message pointing to docs when 'requirement exceeds available memory' error message ([#2680](https://github.com/nf-core/tools/pull/2680))
- add 👀👍🏻🎉😕 reactions to fix-linting-bot action ([#2692](https://github.com/nf-core/tools/pull/2692))

### Download

Expand All @@ -21,7 +22,8 @@
- 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))
- template: add 👀👍🏻🎉😕 reactions to fix-bot action ([#2692](https://github.com/nf-core/tools/pull/2692))
- 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

0 comments on commit 6f52fac

Please sign in to comment.