Skip to content

Commit 4cb669b

Browse files
authored
Merge branch 'dev' into renovate/editorconfig-checker-editorconfig-checker.python-3.x
2 parents c06dd8d + 8382b29 commit 4cb669b

29 files changed

+582
-287
lines changed

.github/workflows/pytest.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ jobs:
7575
name: Run ${{matrix.test}} with Python ${{ needs.setup.outputs.python-version }} on ${{ needs.setup.outputs.runner }}
7676
needs: [setup, list_tests]
7777
if: ${{ needs.setup.outputs.run-tests }}
78-
# run on self-hosted runners for test_components.py (because of the gitlab branch), based on the input if it is dispatched manually, on github if it is a rerun or on self-hosted by default
79-
runs-on: ${{ matrix.test == 'test_components.py' && 'self-hosted' || (github.event.inputs.runners || github.run_number > 1 && 'ubuntu-latest' || 'self-hosted') }}
78+
# run on self-hosted runners for test_components_generate_snapshot.py (because of the gitlab branch), based on the input if it is dispatched manually, on github if it is a rerun or on self-hosted by default
79+
runs-on: ${{ matrix.test == 'components/test_components_generate_snapshot.py' && 'self-hosted' || (github.event.inputs.runners || github.run_number > 1 && 'ubuntu-latest' || 'self-hosted') }}
8080
strategy:
8181
matrix: ${{ fromJson(needs.list_tests.outputs.tests) }}
8282
fail-fast: false # run all tests even if one fails

.pre-commit-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.9.4
3+
rev: v0.9.5
44
hooks:
55
- id: ruff # linter
66
args: [--fix, --exit-non-zero-on-fix] # sort imports and fix
@@ -10,7 +10,7 @@ repos:
1010
hooks:
1111
- id: prettier
1212
additional_dependencies:
13-
- prettier@3.3.3
13+
- prettier@3.5.0
1414

1515
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
1616
rev: "3.2.0"
@@ -19,7 +19,7 @@ repos:
1919
alias: ec
2020

2121
- repo: https://github.com/pre-commit/mirrors-mypy
22-
rev: "v1.14.1"
22+
rev: "v1.15.0"
2323
hooks:
2424
- id: mypy
2525
additional_dependencies:

CHANGELOG.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
### Template
66

77
- Remove the on `pull_request_target` trigger and `pull_request` types from the download test. Also drop `push` triggers on other CI tests. ([#3399](https://github.com/nf-core/tools/pull/3399))
8+
- Add nf-core template version badges to README ([#3396](https://github.com/nf-core/tools/pull/3396))
89

910
### Linting
1011

1112
- Add linting for ifEmpty(null) ([#3411](https://github.com/nf-core/tools/pull/3411))
13+
- Fix arbitrarily nested params schema linting ([#3443](https://github.com/nf-core/tools/pull/3443))
14+
- fix: linting with comments after the input directive ([#3458](https://github.com/nf-core/tools/pull/3458))
15+
- EDAM ontology fixes ([#3460](https://github.com/nf-core/tools/pull/3460))
1216

1317
### Modules
1418

@@ -21,6 +25,12 @@
2125
- chore(deps): update pre-commit hook astral-sh/ruff-pre-commit to v0.9.4 ([#3438](https://github.com/nf-core/tools/pull/3438))
2226
- format name/value with YAML syntax ([#3442](https://github.com/nf-core/tools/pull/3442))
2327
- chore(deps): update pre-commit hook editorconfig-checker/editorconfig-checker.python to v3.2.0 ([#3446](https://github.com/nf-core/tools/pull/3446))
28+
- chore(deps): update pre-commit hook astral-sh/ruff-pre-commit to v0.9.5 ([#3445](https://github.com/nf-core/tools/pull/3445))
29+
- chore(deps): update pre-commit hook pre-commit/mirrors-mypy to v1.15.0 ([#3447](https://github.com/nf-core/tools/pull/3447))
30+
- Update prettier to 3.5.0 ([#3448](https://github.com/nf-core/tools/pull/3448))
31+
- chore(deps): update python:3.12-slim docker digest to 34656cd ([#3450](https://github.com/nf-core/tools/pull/3450))
32+
- Remove Twitter from README ([#3454](https://github.com/nf-core/tools/pull/3454))
33+
- docs: fix contributing link in the main README ([#3459](https://github.com/nf-core/tools/pull/3459))
2434

2535
## [v3.2.0 - Pewter Pangolin](https://github.com/nf-core/tools/releases/tag/3.2.0) - [2025-01-27]
2636

@@ -73,7 +83,7 @@
7383
- Use outputs instead of the environment to pass around values between steps in the Download Test Action ([#3351](https://github.com/nf-core/tools/pull/3351))
7484
- Fix pre commit template ([#3358](https://github.com/nf-core/tools/pull/3358))
7585
- Set LICENSE copyright to nf-core community ([#3366](https://github.com/nf-core/tools/pull/3366))
76-
- fix including modules.config ([#3356](https://github.com/nf-core/tools/pull/3356))
86+
- Fix including modules.config ([#3356](https://github.com/nf-core/tools/pull/3356))
7787

7888
### Linting
7989

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.12-slim@sha256:69ce3aed05675d284bee807e7c45e560e98db21fb1e4c670252b4ee0f2496b6d
1+
FROM python:3.12-slim@sha256:34656cd90456349040784165b9decccbcee4de66f3ead0a1168ba893455afd1e
22
33
description="Docker image containing requirements for nf-core/tools"
44

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pip install --upgrade -r requirements-dev.txt -e .
6161

6262
## Contributions and Support
6363

64-
If you would like to contribute to this package, please see the [contributing guidelines](.github/CONTRIBUTING.md).
64+
If you would like to contribute to this package, please see the [contributing guidelines](CONTRIBUTING.md).
6565

6666
For further information or help, don't hesitate to get in touch on the [Slack `#tools` channel](https://nfcore.slack.com/channels/tools) (you can join with [this invite](https://nf-co.re/join/slack)).
6767

nf_core/components/components_utils.py

+71-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
import re
33
from pathlib import Path
4-
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
4+
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
55

66
import questionary
77
import requests
@@ -165,9 +165,9 @@ def get_components_to_install(subworkflow_dir: Union[str, Path]) -> Tuple[List[s
165165
return modules, subworkflows
166166

167167

168-
def get_biotools_id(tool_name) -> str:
168+
def get_biotools_response(tool_name: str) -> Optional[Dict]:
169169
"""
170-
Try to find a bio.tools ID for 'tool'
170+
Try to get bio.tools information for 'tool'
171171
"""
172172
url = f"https://bio.tools/api/t/?q={tool_name}&format=json"
173173
try:
@@ -176,16 +176,74 @@ def get_biotools_id(tool_name) -> str:
176176
response.raise_for_status() # Raise an error for bad status codes
177177
# Parse the JSON response
178178
data = response.json()
179+
log.info(f"Found bio.tools information for '{tool_name}'")
180+
return data
179181

180-
# Iterate through the tools in the response to find the tool name
181-
for tool in data["list"]:
182-
if tool["name"].lower() == tool_name:
183-
return tool["biotoolsCURIE"]
182+
except requests.exceptions.RequestException as e:
183+
log.warning(f"Could not find bio.tools information for '{tool_name}': {e}")
184+
return None
184185

185-
# If the tool name was not found in the response
186-
log.warning(f"Could not find a bio.tools ID for '{tool_name}'")
187-
return ""
188186

189-
except requests.exceptions.RequestException as e:
190-
log.warning(f"Could not find a bio.tools ID for '{tool_name}': {e}")
191-
return ""
187+
def get_biotools_id(data: dict, tool_name: str) -> str:
188+
"""
189+
Try to find a bio.tools ID for 'tool'
190+
"""
191+
# Iterate through the tools in the response to find the tool name
192+
for tool in data["list"]:
193+
if tool["name"].lower() == tool_name:
194+
log.info(f"Found bio.tools ID: '{tool['biotoolsCURIE']}'")
195+
return tool["biotoolsCURIE"]
196+
197+
# If the tool name was not found in the response
198+
log.warning(f"Could not find a bio.tools ID for '{tool_name}'")
199+
return ""
200+
201+
202+
DictWithStrAndTuple = Dict[str, Tuple[List[str], List[str], List[str]]]
203+
204+
205+
def get_channel_info_from_biotools(
206+
data: dict, tool_name: str
207+
) -> Optional[Tuple[DictWithStrAndTuple, DictWithStrAndTuple]]:
208+
"""
209+
Try to find input and output channels and the respective EDAM ontology terms
210+
211+
Args:
212+
data (dict): The bio.tools API response
213+
tool_name (str): The name of the tool
214+
"""
215+
inputs = {}
216+
outputs = {}
217+
218+
def _iterate_input_output(type) -> DictWithStrAndTuple:
219+
type_info = {}
220+
if type in funct:
221+
for element in funct[type]:
222+
if "data" in element:
223+
element_name = "_".join(element["data"]["term"].lower().split(" "))
224+
uris = [element["data"]["uri"]]
225+
terms = [element["data"]["term"]]
226+
patterns = []
227+
if "format" in element:
228+
for format in element["format"]:
229+
# Append the EDAM URI
230+
uris.append(format["uri"])
231+
# Append the EDAM term, getting the first word in case of complicated strings. i.e. "FASTA format"
232+
patterns.append(format["term"].lower().split(" ")[0])
233+
terms.append(format["term"])
234+
type_info[element_name] = (uris, terms, patterns)
235+
return type_info
236+
237+
# Iterate through the tools in the response to find the tool name
238+
for tool in data["list"]:
239+
if tool["name"].lower() == tool_name:
240+
if "function" in tool:
241+
# Parse all tool functions
242+
for funct in tool["function"]:
243+
inputs.update(_iterate_input_output("input"))
244+
outputs.update(_iterate_input_output("output"))
245+
return inputs, outputs
246+
247+
# If the tool name was not found in the response
248+
log.warning(f"Could not find an EDAM ontology term for '{tool_name}'")
249+
return None

nf_core/components/create.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import nf_core
2222
import nf_core.utils
2323
from nf_core.components.components_command import ComponentCommand
24-
from nf_core.components.components_utils import get_biotools_id
24+
from nf_core.components.components_utils import get_biotools_id, get_biotools_response, get_channel_info_from_biotools
2525
from nf_core.pipelines.lint_utils import run_prettier_on_file
2626

2727
log = logging.getLogger(__name__)
@@ -151,8 +151,15 @@ def create(self) -> bool:
151151
if self.component_type == "modules":
152152
# Try to find a bioconda package for 'component'
153153
self._get_bioconda_tool()
154+
name = self.tool_conda_name if self.tool_conda_name else self.component
154155
# Try to find a biotools entry for 'component'
155-
self.tool_identifier = get_biotools_id(self.component)
156+
biotools_data = get_biotools_response(name)
157+
if biotools_data:
158+
self.tool_identifier = get_biotools_id(biotools_data, name)
159+
# Obtain EDAM ontologies for inputs and outputs
160+
channel_info = get_channel_info_from_biotools(biotools_data, name)
161+
if channel_info:
162+
self.inputs, self.outputs = channel_info
156163

157164
# Prompt for GitHub username
158165
self._get_username()
@@ -176,6 +183,8 @@ def create(self) -> bool:
176183

177184
new_files = [str(path) for path in self.file_paths.values()]
178185

186+
run_prettier_on_file(new_files)
187+
179188
log.info("Created following files:\n " + "\n ".join(new_files))
180189
return True
181190

nf_core/components/nfcore_component.py

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def get_inputs_from_main_nf(self) -> None:
206206
input_data = data.split("input:")[1].split("output:")[0]
207207
for line in input_data.split("\n"):
208208
channel_elements: Any = []
209+
line = line.split("//")[0] # remove any trailing comments
209210
regex = r"(val|path)\s*(\(([^)]+)\)|\s*([^)\s,]+))"
210211
matches = re.finditer(regex, line)
211212
for _, match in enumerate(matches, start=1):

nf_core/module-template/environment.yml

+3
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ channels:
44
- conda-forge
55
- bioconda
66
dependencies:
7+
# TODO nf-core: List required Conda package(s).
8+
# Software MUST be pinned to channel (i.e. "bioconda"), version (i.e. "1.10").
9+
# For Conda, the build (i.e. "h9402c20_2") must be EXCLUDED to support installation on different operating systems.
710
- "{{ bioconda if bioconda else 'YOUR-TOOL-HERE' }}"

nf_core/module-template/main.nf

+41-10
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ process {{ component_name_underscore|upper }} {
2222
label '{{ process_label }}'
2323

2424
{% if not_empty_template -%}
25-
// TODO nf-core: List required Conda package(s).
26-
// Software MUST be pinned to channel (i.e. "bioconda"), version (i.e. "1.10").
27-
// For Conda, the build (i.e. "h9402c20_2") must be EXCLUDED to support installation on different operating systems.
2825
// TODO nf-core: See section in main README for further information regarding finding and adding container addresses to the section below.
2926
{% endif -%}
3027
conda "${moduleDir}/environment.yml"
@@ -33,6 +30,12 @@ process {{ component_name_underscore|upper }} {
3330
'{{ docker_container if docker_container else 'biocontainers/YOUR-TOOL-HERE' }}' }"
3431

3532
input:
33+
{%- if inputs %}
34+
// TODO nf-core: Update the information obtained from bio.tools and make sure that it is correct
35+
{%- for input_name, ontologies in inputs.items() %}
36+
{{ 'tuple val(meta), path(' + input_name + ')' if has_meta else 'path ' + input_name }}
37+
{%- endfor %}
38+
{%- else -%}
3639
{% if not_empty_template -%}
3740
// TODO nf-core: Where applicable all sample-specific information e.g. "id", "single_end", "read_group"
3841
// MUST be provided as an input via a Groovy Map called "meta".
@@ -44,16 +47,22 @@ process {{ component_name_underscore|upper }} {
4447
{%- else -%}
4548
{{ 'tuple val(meta), path(input)' if has_meta else 'path input' }}
4649
{%- endif %}
50+
{%- endif %}
4751

4852
output:
53+
{%- if outputs %}
54+
// TODO nf-core: Update the information obtained from bio.tools and make sure that it is correct
55+
{%- for output_name, ontologies in outputs.items() %}
56+
{{ 'tuple val(meta), path("*.{' + ontologies[2]|join(',') + '}")' if has_meta else 'path ' + output_name }}, emit: {{ output_name }}
57+
{%- endfor %}
58+
{%- else %}
4959
{% if not_empty_template -%}
5060
// TODO nf-core: Named file extensions MUST be emitted for ALL output channels
5161
{{ 'tuple val(meta), path("*.bam")' if has_meta else 'path "*.bam"' }}, emit: bam
62+
// TODO nf-core: List additional required output channels/values here
5263
{%- else -%}
5364
{{ 'tuple val(meta), path("*")' if has_meta else 'path "*"' }}, emit: output
5465
{%- endif %}
55-
{% if not_empty_template -%}
56-
// TODO nf-core: List additional required output channels/values here
5766
{%- endif %}
5867
path "versions.yml" , emit: versions
5968

@@ -78,20 +87,33 @@ process {{ component_name_underscore|upper }} {
7887
{%- endif %}
7988
"""
8089
{% if not_empty_template -%}
81-
samtools \\
82-
sort \\
90+
{{ component }} \\
8391
$args \\
8492
-@ $task.cpus \\
8593
{%- if has_meta %}
94+
{%- if inputs %}
95+
{%- for input_name, ontologies in inputs.items() %}
96+
{%- set extensions = ontologies[2] %}
97+
{%- for ext in extensions %}
98+
-o ${prefix}.{{ ext }} \\
99+
{%- endfor %}
100+
{%- endfor %}
101+
{%- else %}
86102
-o ${prefix}.bam \\
87-
-T $prefix \\
88103
{%- endif %}
104+
{%- endif %}
105+
{%- if inputs %}
106+
{%- for input_name, ontologies in inputs.items() %}
107+
${{ input_name }} \\
108+
{%- endfor %}
109+
{%- else %}
89110
$bam
111+
{%- endif %}
90112
{%- endif %}
91113
92114
cat <<-END_VERSIONS > versions.yml
93115
"${task.process}":
94-
{{ component }}: \$(samtools --version |& sed '1!d ; s/samtools //')
116+
{{ component }}: \$({{ component }} --version)
95117
END_VERSIONS
96118
"""
97119

@@ -108,12 +130,21 @@ process {{ component_name_underscore|upper }} {
108130
{%- endif %}
109131
"""
110132
{% if not_empty_template -%}
133+
{%- if inputs %}
134+
{%- for input_name, ontologies in inputs.items() %}
135+
{%- set extensions = ontologies[2] %}
136+
{%- for ext in extensions %}
137+
touch ${prefix}.{{ ext }}
138+
{%- endfor %}
139+
{%- endfor %}
140+
{%- else %}
111141
touch ${prefix}.bam
112142
{%- endif %}
143+
{%- endif %}
113144
114145
cat <<-END_VERSIONS > versions.yml
115146
"${task.process}":
116-
{{ component }}: \$(samtools --version |& sed '1!d ; s/samtools //')
147+
{{ component }}: \$({{ component }} --version)
117148
END_VERSIONS
118149
"""
119150
}

0 commit comments

Comments
 (0)