/
multiqc_config.py
118 lines (100 loc) · 5.47 KB
/
multiqc_config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import os
from typing import Dict, List
import yaml
def multiqc_config(self) -> Dict[str, List[str]]:
"""Make sure basic multiQC plugins are installed and plots are exported
Basic template:
.. code-block:: yaml
report_comment: >
This report has been generated by the <a href="https://github.com/nf-core/quantms" target="_blank">nf-core/quantms</a>
analysis pipeline. For information about how to interpret these results, please see the
<a href="https://nf-co.re/quantms" target="_blank">documentation</a>.
report_section_order:
software_versions:
order: -1000
nf-core-quantms-summary:
order: -1001
export_plots: true
"""
passed: List[str] = []
failed: List[str] = []
# Remove field that should be ignored according to the linting config
ignore_configs = self.lint_config.get("multiqc_config", [])
fn = os.path.join(self.wf_path, "assets", "multiqc_config.yml")
# Return a failed status if we can't find the file
if not os.path.isfile(fn):
return {"ignored": ["'assets/multiqc_config.yml' not found"]}
try:
with open(fn, "r") as fh:
mqc_yml = yaml.safe_load(fh)
except Exception as e:
return {"failed": [f"Could not parse yaml file: {fn}, {e}"]}
# check if requried sections are present
required_sections = ["report_section_order", "export_plots", "report_comment"]
for section in required_sections:
if section not in mqc_yml and section not in ignore_configs:
failed.append(f"'assets/multiqc_config.yml' does not contain `{section}`")
return {"passed": passed, "failed": failed}
else:
passed.append(f"'assets/multiqc_config.yml' contains `{section}`")
try:
orders = {}
summary_plugin_name = f"{self.pipeline_prefix}-{self.pipeline_name}-summary"
min_plugins = ["software_versions", summary_plugin_name]
for plugin in min_plugins:
if plugin not in mqc_yml["report_section_order"]:
raise AssertionError(f"Section {plugin} missing in report_section_order")
if "order" not in mqc_yml["report_section_order"][plugin]:
raise AssertionError(f"Section {plugin} 'order' missing. Must be < 0")
plugin_order = mqc_yml["report_section_order"][plugin]["order"]
if plugin_order >= 0:
raise AssertionError(f"Section {plugin} 'order' must be < 0")
for plugin in mqc_yml["report_section_order"]:
if "order" in mqc_yml["report_section_order"][plugin]:
orders[plugin] = mqc_yml["report_section_order"][plugin]["order"]
if orders[summary_plugin_name] != min(orders.values()):
raise AssertionError(f"Section {summary_plugin_name} should have the lowest order")
orders.pop(summary_plugin_name)
if orders["software_versions"] != min(orders.values()):
raise AssertionError("Section software_versions should have the second lowest order")
except (AssertionError, KeyError, TypeError) as e:
failed.append(f"'assets/multiqc_config.yml' does not meet requirements: {e}")
else:
passed.append("'assets/multiqc_config.yml' follows the ordering scheme of the minimally required plugins.")
if "report_comment" not in ignore_configs:
# Check that the minimum plugins exist and are coming first in the summary
version = self.nf_config.get("manifest.version", "").strip(" '\"")
if "dev" in version:
version = "dev"
report_comments = (
f'This report has been generated by the <a href="https://github.com/nf-core/{self.pipeline_name}/tree/dev" target="_blank">nf-core/{self.pipeline_name}</a>'
f" analysis pipeline. For information about how to interpret these results, please see the "
f'<a href="https://nf-co.re/{self.pipeline_name}/dev/docs/output" target="_blank">documentation</a>.'
)
else:
report_comments = (
f'This report has been generated by the <a href="https://github.com/nf-core/{self.pipeline_name}/releases/tag/{version}" target="_blank">nf-core/{self.pipeline_name}</a>'
f" analysis pipeline. For information about how to interpret these results, please see the "
f'<a href="https://nf-co.re/{self.pipeline_name}/{version}/docs/output" target="_blank">documentation</a>.'
)
if mqc_yml["report_comment"].strip() != report_comments:
# find where the report_comment is wrong and give it as a hint
hint = report_comments
failed.append(
f"'assets/multiqc_config.yml' does not contain a matching 'report_comment'. \n"
f"The expected comment is: \n"
f"```{hint}``` \n"
f"The current comment is: \n"
f"```{ mqc_yml['report_comment'].strip()}```"
)
else:
passed.append("'assets/multiqc_config.yml' contains a matching 'report_comment'.")
# Check that export_plots is activated
try:
if not mqc_yml["export_plots"]:
raise AssertionError()
except (AssertionError, KeyError, TypeError):
failed.append("'assets/multiqc_config.yml' does not contain 'export_plots: true'.")
else:
passed.append("'assets/multiqc_config.yml' contains 'export_plots: true'.")
return {"passed": passed, "failed": failed}