Skip to content

Commit 7a757e4

Browse files
authored
Merge pull request #2 from mashehu/files-unchanged
add more typing
2 parents c4be616 + e0cf4eb commit 7a757e4

File tree

3 files changed

+86
-79
lines changed

3 files changed

+86
-79
lines changed

nf_core/lint/__init__.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import json
99
import logging
1010
import os
11+
from pathlib import Path
12+
from typing import List, Union
1113

1214
import git
1315
import rich
@@ -621,7 +623,7 @@ def _save_json_results(self, json_fn):
621623
with open(json_fn, "w") as fh:
622624
json.dump(results, fh, indent=4)
623625

624-
def _wrap_quotes(self, files):
626+
def _wrap_quotes(self, files: Union[List[str], List[Path], Path]) -> str:
625627
"""Helper function to take a list of filenames and format with markdown.
626628
627629
Args:
@@ -636,5 +638,5 @@ def _wrap_quotes(self, files):
636638
"""
637639
if not isinstance(files, list):
638640
files = [files]
639-
bfiles = [f"`{f}`" for f in files]
641+
bfiles = [f"`{str(f)}`" for f in files]
640642
return " or ".join(bfiles)

nf_core/lint/files_exist.py

+43-40
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import logging
22
from pathlib import Path
3-
from typing import Union
3+
from typing import Dict, List, Tuple, Union
4+
5+
from nf_core.lint import PipelineLint
46

57
log = logging.getLogger(__name__)
68

79

8-
def files_exist(self):
10+
def files_exist(self: PipelineLint) -> dict[str, Union[List[str], bool]]:
911
"""Checks a given pipeline directory for required files.
1012
1113
Iterates through the pipeline's directory content and checks that specified
@@ -129,19 +131,19 @@ def files_exist(self):
129131
short_name = self.nf_config["manifest.name"].strip("\"'").split("/")
130132

131133
files_fail = [
132-
[".gitattributes"],
133-
[".gitignore"],
134-
[".nf-core.yml"],
135-
[".editorconfig"],
136-
[".prettierignore"],
137-
[".prettierrc.yml"],
138-
["CHANGELOG.md"],
139-
["CITATIONS.md"],
140-
["CODE_OF_CONDUCT.md"],
141-
["LICENSE", "LICENSE.md", "LICENCE", "LICENCE.md"], # NB: British / American spelling
142-
["nextflow_schema.json"],
143-
["nextflow.config"],
144-
["README.md"],
134+
[Path(".gitattributes")],
135+
[Path(".gitignore")],
136+
[Path(".nf-core.yml")],
137+
[Path(".editorconfig")],
138+
[Path(".prettierignore")],
139+
[Path(".prettierrc.yml")],
140+
[Path("CHANGELOG.md")],
141+
[Path("CITATIONS.md")],
142+
[Path("CODE_OF_CONDUCT.md")],
143+
[Path("LICENSE", "LICENSE.md", "LICENCE", "LICENCE.md")], # NB: British / American spelling
144+
[Path("nextflow_schema.json")],
145+
[Path("nextflow.config")],
146+
[Path("README.md")],
145147
[Path(".github", ".dockstore.yml")],
146148
[Path(".github", "CONTRIBUTING.md")],
147149
[Path(".github", "ISSUE_TEMPLATE", "bug_report.yml")],
@@ -171,37 +173,39 @@ def files_exist(self):
171173
]
172174

173175
files_warn = [
174-
["main.nf"],
176+
[Path("main.nf")],
175177
[Path("assets", "multiqc_config.yml")],
176178
[Path("conf", "base.config")],
177179
[Path("conf", "igenomes.config")],
178180
[Path(".github", "workflows", "awstest.yml")],
179181
[Path(".github", "workflows", "awsfulltest.yml")],
180182
[Path("lib", f"Workflow{short_name[0].upper()}{short_name[1:]}.groovy")],
181-
["modules.json"],
182-
["pyproject.toml"],
183+
[Path("modules.json")],
184+
[Path("pyproject.toml")],
183185
]
184186

185187
# List of strings. Fails / warns if any of the strings exist.
186188
files_fail_ifexists = [
187-
"Singularity",
188-
"parameters.settings.json",
189-
"pipeline_template.yml", # saving information in .nf-core.yml
190-
".nf-core.yaml", # yml not yaml
189+
Path("Singularity"),
190+
Path("parameters.settings.json"),
191+
Path("pipeline_template.yml"), # saving information in .nf-core.yml
192+
Path(".nf-core.yaml"), # yml not yaml
191193
Path("bin", "markdown_to_html.r"),
192194
Path("conf", "aws.config"),
193195
Path(".github", "workflows", "push_dockerhub.yml"),
194196
Path(".github", "ISSUE_TEMPLATE", "bug_report.md"),
195197
Path(".github", "ISSUE_TEMPLATE", "feature_request.md"),
196198
Path("docs", "images", f"nf-core-{short_name}_logo.png"),
197-
".markdownlint.yml",
198-
".yamllint.yml",
199+
Path(".markdownlint.yml"),
200+
Path(".yamllint.yml"),
199201
Path("lib", "Checks.groovy"),
200202
Path("lib", "Completion.groovy"),
201203
Path("lib", "Workflow.groovy"),
202204
]
203-
files_warn_ifexists = [".travis.yml"]
204-
files_fail_ifinconfig = [[Path("lib", "nfcore_external_java_deps.jar"), "nf-validation"]]
205+
files_warn_ifexists = [Path(".travis.yml")]
206+
files_fail_ifinconfig: List[Tuple[Path, Dict[str, str]]] = [
207+
(Path("lib", "nfcore_external_java_deps.jar"), {"plugins": "nf_validation"}),
208+
]
205209

206210
# Remove files that should be ignored according to the linting config
207211
ignore_files = self.lint_config.get("files_exist", [])
@@ -242,22 +246,21 @@ def pf(file_path: Union[str, Path]) -> Path:
242246
else:
243247
passed.append(f"File not found check: {self._wrap_quotes(file)}")
244248
# Files that cause an error if they exists together with a certain entry in nextflow.config
245-
for file in files_fail_ifinconfig:
246-
if str(file[0]) in ignore_files:
249+
for file_cond in files_fail_ifinconfig:
250+
if str(file_cond[0]) in ignore_files:
247251
continue
248-
nextflow_config = pf("nextflow.config")
249252
in_config = False
250-
with open(nextflow_config) as f:
251-
if file[1] in f.read():
252-
in_config = True
253-
if pf(file[0]).is_file() and in_config:
254-
failed.append(f"File must be removed: {self._wrap_quotes(file[0])}")
255-
elif pf(file[0]).is_file() and not in_config:
256-
passed.append(f"File found check: {self._wrap_quotes(file[0])}")
257-
elif not pf(file[0]).is_file() and not in_config:
258-
failed.append(f"File not found check: {self._wrap_quotes(file[0])}")
259-
elif not pf(file[0]).is_file() and in_config:
260-
passed.append(f"File not found check: {self._wrap_quotes(file[0])}")
253+
config_key, config_value = list(file_cond[1].items())[0]
254+
if config_key in self.nf_config and self.nf_config[config_key] == config_value:
255+
in_config = True
256+
if pf(file_cond[0]).is_file() and in_config:
257+
failed.append(f"File must be removed: {self._wrap_quotes(file_cond[0])}")
258+
elif pf(file_cond[0]).is_file() and not in_config:
259+
passed.append(f"File found check: {self._wrap_quotes(file_cond[0])}")
260+
elif not pf(file_cond[0]).is_file() and not in_config:
261+
failed.append(f"File not found check: {self._wrap_quotes(file_cond[0])}")
262+
elif not pf(file_cond[0]).is_file() and in_config:
263+
passed.append(f"File not found check: {self._wrap_quotes(file_cond[0])}")
261264
# Files that cause a warning if they exist
262265
for file in files_warn_ifexists:
263266
if file in ignore_files:

nf_core/lint/files_unchanged.py

+39-37
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
import shutil
44
import tempfile
55
from pathlib import Path
6-
from typing import Union
6+
from typing import Dict, List, Tuple, Union
77

88
import yaml
99

1010
import nf_core.create
11+
from nf_core.lint import PipelineLint
1112

1213
log = logging.getLogger(__name__)
1314

1415

15-
def files_unchanged(self):
16+
def files_unchanged(self: PipelineLint) -> dict[str, Union[List[str], bool]]:
1617
"""Checks that certain pipeline files are not modified from template output.
1718
1819
Iterates through the pipeline's directory content and compares specified files
@@ -64,11 +65,11 @@ def files_unchanged(self):
6465
6566
"""
6667

67-
passed = []
68-
failed = []
69-
ignored = []
70-
fixed = []
71-
could_fix = False
68+
passed: List[str] = []
69+
failed: List[str] = []
70+
ignored: List[str] = []
71+
fixed: List[str] = []
72+
could_fix: bool = False
7273

7374
# Check that we have the minimum required config
7475
required_pipeline_config = {"manifest.name", "manifest.description", "manifest.author"}
@@ -87,10 +88,10 @@ def files_unchanged(self):
8788
# NB: Should all be files, not directories
8889
# List of lists. Passes if any of the files in the sublist are found.
8990
files_exact = [
90-
[".gitattributes"],
91-
[".prettierrc.yml"],
92-
["CODE_OF_CONDUCT.md"],
93-
["LICENSE", "LICENSE.md", "LICENCE", "LICENCE.md"], # NB: British / American spelling
91+
[Path(".gitattributes")],
92+
[Path(".prettierrc.yml")],
93+
[Path("CODE_OF_CONDUCT.md")],
94+
[Path("LICENSE", "LICENSE.md", "LICENCE", "LICENCE.md")], # NB: British / American spelling
9495
[Path(".github", ".dockstore.yml")],
9596
[Path(".github", "CONTRIBUTING.md")],
9697
[Path(".github", "ISSUE_TEMPLATE", "bug_report.yml")],
@@ -110,10 +111,10 @@ def files_unchanged(self):
110111
[Path("lib", "NfcoreTemplate.groovy")],
111112
]
112113
files_partial = [
113-
[".gitignore", ".prettierignore", "pyproject.toml"],
114+
[Path(".gitignore"), Path(".prettierignore"), Path("pyproject.toml")],
114115
]
115-
files_conditional = [
116-
[Path("lib", "nfcore_external_java_deps.jar"), {"plugins": "nf_validation"}],
116+
files_conditional: List[Tuple[List[Path], Dict[str, str]]] = [
117+
([Path("lib", "nfcore_external_java_deps.jar")], {"plugins": "nf_validation"}),
117118
]
118119

119120
# Only show error messages from pipeline creation
@@ -215,37 +216,38 @@ def _tf(file_path: Union[str, Path]) -> Path:
215216
pass
216217

217218
# Files that should be there only if an entry in nextflow config is not set
218-
for files in files_conditional:
219+
for file_conditional in files_conditional:
219220
# Ignore if file specified in linting config
220221
ignore_files = self.lint_config.get("files_unchanged", [])
221-
if str(files[0]) in ignore_files:
222-
ignored.append(f"File ignored due to lint config: {self._wrap_quotes(files)}")
222+
if any(str(f) in ignore_files for f in files_conditional[0]):
223+
ignored.append(f"File ignored due to lint config: {self._wrap_quotes(file_conditional[0])}")
223224

224225
# Ignore if we can't find the file
225-
elif _pf(files[0]).is_file():
226-
ignored.append(f"File does not exist: {self._wrap_quotes(files[0])}")
226+
elif not any([_pf(f).is_file() for f in file_conditional[0]]):
227+
ignored.append(f"File does not exist: {self._wrap_quotes(file_conditional[0])}")
227228

228229
# Check that the file has an identical match
229230
else:
230-
config_key, config_value = list(files[1].items())[0]
231-
if config_key in self.nf_config and self.nf_config[config_key] == config_value:
232-
# Ignore if the config key is set to the expected value
233-
ignored.append(f"File ignored due to config: {self._wrap_quotes(files)}")
234-
else:
235-
try:
236-
if filecmp.cmp(_pf(files[0]), _tf(files[0]), shallow=True):
237-
passed.append(f"`{files[0]}` matches the template")
238-
else:
239-
if "files_unchanged" in self.fix:
240-
# Try to fix the problem by overwriting the pipeline file
241-
shutil.copy(_tf(files[0]), _pf(files[0]))
242-
passed.append(f"`{files[0]}` matches the template")
243-
fixed.append(f"`{files[0]}` overwritten with template file")
231+
config_key, config_value = list(file_conditional[1].items())[0]
232+
for f in file_conditional[0]:
233+
if config_key in self.nf_config and self.nf_config[config_key] == config_value:
234+
# Ignore if the config key is set to the expected value
235+
ignored.append(f"File ignored due to config: {self._wrap_quotes(file_conditional[0])}")
236+
else:
237+
try:
238+
if filecmp.cmp(_pf(f), _tf(f), shallow=True):
239+
passed.append(f"`{f}` matches the template")
244240
else:
245-
failed.append(f"`{files[0]}` does not match the template")
246-
could_fix = True
247-
except FileNotFoundError:
248-
pass
241+
if "files_unchanged" in self.fix:
242+
# Try to fix the problem by overwriting the pipeline file
243+
shutil.copy(_tf(f), _pf(f))
244+
passed.append(f"`{f}` matches the template")
245+
fixed.append(f"`{f}` overwritten with template file")
246+
else:
247+
failed.append(f"`{f}` does not match the template")
248+
could_fix = True
249+
except FileNotFoundError:
250+
pass
249251

250252
# cleaning up temporary dir
251253
shutil.rmtree(tmp_dir)

0 commit comments

Comments
 (0)