+
Skip to content

Add autocompletion for modules / subworkflows and pipeline #3660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jul 15, 2025
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 @@ -54,6 +54,7 @@
- Update error message for rocrate_readme_sync ([#3652](https://github.com/nf-core/tools/pull/3652))
- Update `nf-core modules info` command after `meta.yml` restructuring ([#3659](https://github.com/nf-core/tools/pull/3659))
- Enable parsing of multi-line config values ([#3629](https://github.com/nf-core/tools/pull/3629))
- Add modules / subworkflows and pipelines names autocompletion to the CLI ([#3660](https://github.com/nf-core/tools/pull/3660))

#### Version updates

Expand Down
171 changes: 149 additions & 22 deletions nf_core/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@
test_datasets_list_remote,
test_datasets_search,
)
from nf_core.components.components_completion import autocomplete_modules, autocomplete_subworkflows
from nf_core.components.constants import NF_CORE_MODULES_REMOTE
from nf_core.pipelines.download import DownloadError
from nf_core.pipelines.list import autocomplete_pipelines
from nf_core.utils import check_if_outdated, nfcore_logo, rich_force_colors, setup_nfcore_dir

# Set up logging as the root logger
Expand Down Expand Up @@ -354,7 +356,12 @@ def command_pipelines_lint(

# nf-core pipelines download
@pipelines.command("download")
@click.argument("pipeline", required=False, metavar="<pipeline name>")
@click.argument(
"pipeline",
required=False,
metavar="<pipeline name>",
shell_complete=autocomplete_pipelines,
)
@click.option(
"-r",
"--revision",
Expand Down Expand Up @@ -461,7 +468,12 @@ def command_pipelines_download(

# nf-core pipelines create-params-file
@pipelines.command("create-params-file")
@click.argument("pipeline", required=False, metavar="<pipeline name>")
@click.argument(
"pipeline",
required=False,
metavar="<pipeline name>",
shell_complete=autocomplete_pipelines,
)
@click.option("-r", "--revision", help="Release/branch/SHA of the pipeline (if remote)")
@click.option(
"-o",
Expand Down Expand Up @@ -489,7 +501,12 @@ def command_pipelines_create_params_file(ctx, pipeline, revision, output, force,

# nf-core pipelines launch
@pipelines.command("launch")
@click.argument("pipeline", required=False, metavar="<pipeline name>")
@click.argument(
"pipeline",
required=False,
metavar="<pipeline name>",
shell_complete=autocomplete_pipelines,
)
@click.option("-r", "--revision", help="Release/branch/SHA of the project to run (if remote)")
@click.option("-i", "--id", help="ID for web-gui launch parameter set")
@click.option(
Expand Down Expand Up @@ -745,7 +762,12 @@ def pipeline_schema():
default=".",
help=r"Pipeline directory. [dim]\[default: current working directory][/]",
)
@click.argument("pipeline", required=True, metavar="<pipeline name>")
@click.argument(
"pipeline",
required=False,
metavar="<pipeline name>",
shell_complete=autocomplete_pipelines,
)
@click.argument("params", type=click.Path(exists=True), required=True, metavar="<JSON params file>")
def command_pipelines_schema_validate(directory, pipeline, params):
"""
Expand Down Expand Up @@ -944,7 +966,14 @@ def command_modules_list_local(ctx, keywords, json, directory): # pylint: disab
# nf-core modules install
@modules.command("install")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -978,7 +1007,14 @@ def command_modules_install(ctx, tool, directory, prompt, force, sha):
# nf-core modules update
@modules.command("update")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1055,7 +1091,14 @@ def command_modules_update(
# nf-core modules patch
@modules.command("patch")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand All @@ -1075,7 +1118,14 @@ def command_modules_patch(ctx, tool, directory, remove):
# nf-core modules remove
@modules.command("remove")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1194,7 +1244,14 @@ def command_modules_create(
# nf-core modules test
@modules.command("test")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-v",
"--verbose",
Expand Down Expand Up @@ -1249,7 +1306,14 @@ def command_modules_test(ctx, tool, directory, no_prompts, update, once, profile
# nf-core modules lint
@modules.command("lint")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1303,7 +1367,14 @@ def command_modules_lint(
# nf-core modules info
@modules.command("info")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand All @@ -1322,7 +1393,14 @@ def command_modules_info(ctx, tool, directory):
# nf-core modules bump-versions
@modules.command("bump-versions")
@click.pass_context
@click.argument("tool", type=str, callback=normalize_case, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"tool",
type=str,
callback=normalize_case,
required=False,
metavar="<tool> or <tool/subtool>",
shell_complete=autocomplete_modules,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1414,7 +1492,14 @@ def command_subworkflows_create(ctx, subworkflow, directory, author, force, migr
# nf-core subworkflows test
@subworkflows.command("test")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1502,7 +1587,14 @@ def command_subworkflows_list_local(ctx, keywords, json, directory): # pylint:
# nf-core subworkflows lint
@subworkflows.command("lint")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1551,7 +1643,14 @@ def command_subworkflows_lint(
# nf-core subworkflows info
@subworkflows.command("info")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand All @@ -1570,7 +1669,14 @@ def command_subworkflows_info(ctx, subworkflow, directory):
# nf-core subworkflows install
@subworkflows.command("install")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand Down Expand Up @@ -1610,7 +1716,14 @@ def command_subworkflows_install(ctx, subworkflow, directory, prompt, force, sha
# nf-core subworkflows patch
@subworkflows.command("patch")
@click.pass_context
@click.argument("tool", type=str, required=False, metavar="<tool> or <tool/subtool>")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand All @@ -1619,7 +1732,7 @@ def command_subworkflows_install(ctx, subworkflow, directory, prompt, force, sha
help=r"Pipeline directory. [dim]\[default: current working directory][/]",
)
@click.option("-r", "--remove", is_flag=True, default=False, help="Remove an existent patch file and regenerate it.")
def subworkflows_patch(ctx, tool, dir, remove):
def subworkflows_patch(ctx, subworkflow, dir, remove):
"""
Create a patch file for minor changes in a subworkflow

Expand All @@ -1636,9 +1749,9 @@ def subworkflows_patch(ctx, tool, dir, remove):
ctx.obj["modules_repo_no_pull"],
)
if remove:
subworkflow_patch.remove(tool)
subworkflow_patch.remove(subworkflow)
else:
subworkflow_patch.patch(tool)
subworkflow_patch.patch(subworkflow)
except (UserWarning, LookupError) as e:
log.error(e)
sys.exit(1)
Expand All @@ -1647,7 +1760,14 @@ def subworkflows_patch(ctx, tool, dir, remove):
# nf-core subworkflows remove
@subworkflows.command("remove")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand All @@ -1666,7 +1786,14 @@ def command_subworkflows_remove(ctx, directory, subworkflow):
# nf-core subworkflows update
@subworkflows.command("update")
@click.pass_context
@click.argument("subworkflow", type=str, callback=normalize_case, required=False, metavar="subworkflow name")
@click.argument(
"subworkflow",
type=str,
callback=normalize_case,
required=False,
metavar="subworkflow name",
shell_complete=autocomplete_subworkflows,
)
@click.option(
"-d",
"--dir",
Expand Down
37 changes: 37 additions & 0 deletions nf_core/components/components_completion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import sys

from click.shell_completion import CompletionItem

from nf_core.modules.list import ModuleList
from nf_core.subworkflows.list import SubworkflowList


def autocomplete_components(ctx, param, incomplete: str, component_type: str, list_class):
# Defaults
modules_repo_url = "https://github.com/nf-core/modules"
modules_repo_branch = "master"
modules_repo_no_pull = False
dir_folder = ctx.params.get("dir", ".")

try:
if ctx.obj is not None:
modules_repo_url = ctx.obj.get("modules_repo_url", modules_repo_url)
modules_repo_branch = ctx.obj.get("modules_repo_branch", modules_repo_branch)
modules_repo_no_pull = ctx.obj.get("modules_repo_no_pull", modules_repo_no_pull)

components_list = list_class(dir_folder, True, modules_repo_url, modules_repo_branch, modules_repo_no_pull)

available_components = components_list.modules_repo.get_avail_components(component_type)

return [CompletionItem(comp) for comp in available_components if comp.startswith(incomplete)]
except Exception as e:
print(f"[ERROR] Autocomplete failed: {e}", file=sys.stderr)
return []


def autocomplete_modules(ctx, param, incomplete: str):
return autocomplete_components(ctx, param, incomplete, "modules", ModuleList)


def autocomplete_subworkflows(ctx, param, incomplete: str):
return autocomplete_components(ctx, param, incomplete, "subworkflows", SubworkflowList)
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载