-
Notifications
You must be signed in to change notification settings - Fork 182
/
meta_yml.py
130 lines (117 loc) · 5.52 KB
/
meta_yml.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
119
120
121
122
123
124
125
126
127
128
129
130
import json
from pathlib import Path
import jsonschema.validators
import yaml
import nf_core.components.components_utils
def meta_yml(subworkflow_lint_object, subworkflow):
"""
Lint a ``meta.yml`` file
The lint test checks that the subworkflow has
a ``meta.yml`` file and that it follows the
JSON schema defined in the ``subworkflows/yaml-schema.json``
file in the nf-core/modules repository.
In addition it checks that the subworkflow name
and subworkflow input is consistent between the
``meta.yml`` and the ``main.nf``.
Checks that all input and output channels are specified in ``meta.yml``.
Checks that all included components in ``main.nf`` are specified in ``meta.yml``.
"""
# Read the meta.yml file
try:
with open(subworkflow.meta_yml) as fh:
meta_yaml = yaml.safe_load(fh)
subworkflow.passed.append(("meta_yml_exists", "Subworkflow `meta.yml` exists", subworkflow.meta_yml))
except FileNotFoundError:
subworkflow.failed.append(("meta_yml_exists", "Subworkflow `meta.yml` does not exist", subworkflow.meta_yml))
return
# Confirm that the meta.yml file is valid according to the JSON schema
valid_meta_yml = True
try:
with open(Path(subworkflow_lint_object.modules_repo.local_repo_dir, "subworkflows/yaml-schema.json")) as fh:
schema = json.load(fh)
jsonschema.validators.validate(instance=meta_yaml, schema=schema)
subworkflow.passed.append(("meta_yml_valid", "Subworkflow `meta.yml` is valid", subworkflow.meta_yml))
except jsonschema.exceptions.ValidationError as e:
valid_meta_yml = False
hint = ""
if len(e.path) > 0:
hint = f"\nCheck the entry for `{e.path[0]}`."
if e.message.startswith("None is not of type 'object'") and len(e.path) > 2:
hint = f"\nCheck that the child entries of {e.path[0]+'.'+e.path[2]} are indented correctly."
subworkflow.failed.append(
(
"meta_yml_valid",
f"The `meta.yml` of the subworkflow {subworkflow.component_name} is not valid: {e.message}.{hint}",
subworkflow.meta_yml,
)
)
return
# Confirm that all input and output channels are specified
if valid_meta_yml:
if "input" in meta_yaml:
meta_input = [list(x.keys())[0] for x in meta_yaml["input"]]
for input in subworkflow.inputs:
if input in meta_input:
subworkflow.passed.append(("meta_input", f"`{input}` specified", subworkflow.meta_yml))
else:
subworkflow.failed.append(("meta_input", f"`{input}` missing in `meta.yml`", subworkflow.meta_yml))
if "output" in meta_yaml:
meta_output = [list(x.keys())[0] for x in meta_yaml["output"]]
for output in subworkflow.outputs:
if output in meta_output:
subworkflow.passed.append(("meta_output", f"`{output}` specified", subworkflow.meta_yml))
else:
subworkflow.failed.append(
("meta_output", f"`{output}` missing in `meta.yml`", subworkflow.meta_yml)
)
# confirm that the name matches the process name in main.nf
if meta_yaml["name"].upper() == subworkflow.workflow_name:
subworkflow.passed.append(("meta_name", "Correct name specified in `meta.yml`", subworkflow.meta_yml))
else:
subworkflow.failed.append(
(
"meta_name",
f"Conflicting workflow name between meta.yml (`{meta_yaml['name']}`) and main.nf (`{subworkflow.workflow_name}`)",
subworkflow.meta_yml,
)
)
# confirm that all included components in ``main.nf`` are specified in ``meta.yml``
included_components = nf_core.components.components_utils.get_components_to_install(subworkflow.component_dir)
included_components = (
included_components[0] + included_components[1]
) # join included modules and included subworkflows in a single list
if "components" in meta_yaml:
meta_components = [x for x in meta_yaml["components"]]
for component in set(included_components):
if component in meta_components:
subworkflow.passed.append(
(
"meta_include",
f"Included module/subworkflow `{component}` specified in `meta.yml`",
subworkflow.meta_yml,
)
)
else:
subworkflow.failed.append(
(
"meta_include",
f"Included module/subworkflow `{component}` missing in `meta.yml`",
subworkflow.meta_yml,
)
)
if "modules" in meta_yaml:
subworkflow.failed.append(
(
"meta_modules_deprecated",
"Deprecated section 'modules' found in `meta.yml`, use 'components' instead",
subworkflow.meta_yml,
)
)
else:
subworkflow.passed.append(
(
"meta_modules_deprecated",
"Deprecated section 'modules' not found in `meta.yml`",
subworkflow.meta_yml,
)
)