+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

- Support modules with `exec:` blocks ([#3633](https://github.com/nf-core/tools/pull/3633))
- feat: nf-core modules bump-version supports specifying the toolkit ([#3608](https://github.com/nf-core/tools/pull/3608))
- use same logic for super-tool selection in modules lint and bump-version ([#3823](https://github.com/nf-core/tools/pull/3823))
- Override example keywords in modules test ([#3801](https://github.com/nf-core/tools/pull/3801))

### Subworkflows
Expand Down
8 changes: 1 addition & 7 deletions nf_core/modules/bump_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,7 @@ def bump_versions(
raise nf_core.modules.modules_utils.ModuleExceptionError(
"You cannot specify a tool and request all tools to be bumped."
)
# First try to find an exact match
exact_matches = [m for m in nfcore_modules if m.component_name == module]
if exact_matches:
nfcore_modules = exact_matches
else:
# If no exact match, look for modules that start with the given name (subtools)
nfcore_modules = [m for m in nfcore_modules if m.component_name.startswith(module + "/")]
nfcore_modules = nf_core.modules.modules_utils.filter_modules_by_name(nfcore_modules, module)

if len(nfcore_modules) == 0:
raise nf_core.modules.modules_utils.ModuleExceptionError(
Expand Down
2 changes: 1 addition & 1 deletion nf_core/modules/lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def lint(
if all_modules:
raise LintExceptionError("You cannot specify a tool and request all tools to be linted.")
local_modules = []
remote_modules = [m for m in self.all_remote_components if m.component_name == module]
remote_modules = nf_core.modules.modules_utils.filter_modules_by_name(self.all_remote_components, module)
if len(remote_modules) == 0:
raise LintExceptionError(f"Could not find the specified module: '{module}'")
else:
Expand Down
19 changes: 19 additions & 0 deletions nf_core/modules/modules_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,22 @@ def load_edam():
if extension not in edam_formats:
edam_formats[extension] = (fields[0], fields[1]) # URL, name
return edam_formats


def filter_modules_by_name(modules: list[NFCoreComponent], module_name: str) -> list[NFCoreComponent]:
"""
Filter modules by name, supporting exact matches and tool family matching.

Args:
modules (list[NFCoreComponent]): List of modules to filter
module_name (str): The module name or prefix to match

Returns:
list[NFCoreComponent]: List of matching modules
"""
# First try to find an exact match
exact_matches = [m for m in modules if m.component_name == module_name]
if exact_matches:
return exact_matches
# If no exact match, look for modules that start with the given name (subtools)
return [m for m in modules if m.component_name.startswith(module_name)]
64 changes: 64 additions & 0 deletions tests/modules/test_modules_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,67 @@ def test_get_installed_modules_with_files(self):

_, nfcore_modules = nf_core.modules.modules_utils.get_installed_modules(self.nfcore_modules)
assert len(nfcore_modules) == 1

def test_filter_modules_by_name_exact_match(self):
"""Test filtering modules by name with an exact match"""
# install bpipe/test
_, nfcore_modules = nf_core.modules.modules_utils.get_installed_modules(self.nfcore_modules)

# Test exact match
filtered = nf_core.modules.modules_utils.filter_modules_by_name(nfcore_modules, "bpipe/test")
assert len(filtered) == 1
assert filtered[0].component_name == "bpipe/test"

def test_filter_modules_by_name_tool_family(self):
"""Test filtering modules by name to get all subtools of a super-tool"""
# Create some mock samtools subtools in the modules directory
samtools_dir = self.nfcore_modules / "modules" / "nf-core" / "samtools"

for subtool in ["view", "sort", "index"]:
subtool_dir = samtools_dir / subtool
subtool_dir.mkdir(parents=True, exist_ok=True)
(subtool_dir / "main.nf").touch()

# Get the modules
_, nfcore_modules = nf_core.modules.modules_utils.get_installed_modules(self.nfcore_modules)

# Test filtering by tool family (super-tool)
filtered = nf_core.modules.modules_utils.filter_modules_by_name(nfcore_modules, "samtools")

assert set(m.component_name for m in filtered) == {"samtools/view", "samtools/sort", "samtools/index"}

def test_filter_modules_by_name_exact_match_preferred(self):
"""Test that exact matches are preferred over prefix matches"""
# Create a samtools super-tool and its subtools
samtools_dir = self.nfcore_modules / "modules" / "nf-core" / "samtools"
samtools_dir.mkdir(parents=True, exist_ok=True)
(samtools_dir / "main.nf").touch()

# Create subtools
for subtool in ["view", "sort"]:
subtool_dir = samtools_dir / subtool
subtool_dir.mkdir(parents=True, exist_ok=True)
(subtool_dir / "main.nf").touch()

# Get the modules
_, nfcore_modules = nf_core.modules.modules_utils.get_installed_modules(self.nfcore_modules)

# Test that exact match is returned when it exists
filtered = nf_core.modules.modules_utils.filter_modules_by_name(nfcore_modules, "samtools")
assert len(filtered) == 1
assert filtered[0].component_name == "samtools"

def test_filter_modules_by_name_no_match(self):
"""Test filtering modules by name with no matches"""
_, nfcore_modules = nf_core.modules.modules_utils.get_installed_modules(self.nfcore_modules)

# Test no match
filtered = nf_core.modules.modules_utils.filter_modules_by_name(nfcore_modules, "nonexistent")
assert len(filtered) == 0

def test_filter_modules_by_name_empty_list(self):
"""Test filtering an empty list of modules"""
modules = []

filtered = nf_core.modules.modules_utils.filter_modules_by_name(modules, "fastqc")
assert len(filtered) == 0
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载