nf-core / tools

Python package with helper tools for the nf-core community.
https://nf-co.re
MIT License
232 stars 187 forks source link

nf-core modules install <tool> throws a stack trace when first installing a module to a non-nf-core pipeline #2999

Closed mahesh-panchal closed 3 months ago

mahesh-panchal commented 4 months ago

Description of the bug

When using nf-core modules install <tool> in a fresh workflow with only a main.nf and empty nextflow.config, nf-core tools tries to make the .nf-core.yml, but ends up trying to write to /.nf-core.yml instead resulting in an error. This is also true for when trying to make the modules folder ( it tries /modules and fails ).

Making the file and folder manually let's it succeed though.

Command used and terminal output

$ nf-core modules install untar

                                          ,--./,-.
          ___     __   __   __   ___     /,-._.--~\
    |\ | |__  __ /  ` /  \ |__) |__         }  {
    | \| |       \__, \__/ |  \ |___     \`-._,-`-,
                                          `._,._,'

    nf-core/tools version 2.14.1 - https://nf-co.re

WARNING  'repository_type' not defined in .nf-core.yml                                                                                                                        
? Is this repository an nf-core pipeline or a fork of nf-core/modules? Pipeline
INFO     To avoid this prompt in the future, add the 'repository_type' key to your .nf-core.yml file.                                                                         
? Would you like me to add this config now? [y/n] (y): y
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /opt/conda/bin/nf-core:8 in <module>                                                             │
│                                                                                                  │
│   5 from nf_core.__main__ import run_nf_core                                                     │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(run_nf_core())                                                                  │
│   9                                                                                              │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/__main__.py:150 in run_nf_core                   │
│                                                                                                  │
│    147 │   │   │   log.debug(f"Could not check latest version: {e}")                             │
│    148 │   │   stderr.print("\n")                                                                │
│    149 │   # Launch the click cli                                                                │
│ ❱  150 │   nf_core_cli(auto_envvar_prefix="NFCORE")                                              │
│    151                                                                                           │
│    152                                                                                           │
│    153 @tui()                                                                                    │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/rich_click/rich_command.py:367 in __call__               │
│                                                                                                  │
│   364 │   │   # Include this here because I run into a false warning                             │
│   365 │   │   # in the PyCharm IDE otherwise; for some reason PyCharm doesn't                    │
│   366 │   │   # seem to think RichGroups are callable. (No issues with Mypy, though.)            │
│ ❱ 367 │   │   return super().__call__(*args, **kwargs)                                           │
│   368                                                                                            │
│   369                                                                                            │
│   370 class RichCommandCollection(CommandCollection, RichGroup):                                 │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/core.py:1157 in __call__                           │
│                                                                                                  │
│   1154 │                                                                                         │
│   1155 │   def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any:                           │
│   1156 │   │   """Alias for :meth:`main`."""                                                     │
│ ❱ 1157 │   │   return self.main(*args, **kwargs)                                                 │
│   1158                                                                                           │
│   1159                                                                                           │
│   1160 class Command(BaseCommand):                                                               │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/rich_click/rich_command.py:152 in main                   │
│                                                                                                  │
│   149 │   │   try:                                                                               │
│   150 │   │   │   try:                                                                           │
│   151 │   │   │   │   with self.make_context(prog_name, args, **extra) as ctx:                   │
│ ❱ 152 │   │   │   │   │   rv = self.invoke(ctx)                                                  │
│   153 │   │   │   │   │   if not standalone_mode:                                                │
│   154 │   │   │   │   │   │   return rv                                                          │
│   155 │   │   │   │   │   # it's not safe to `ctx.exit(rv)` here!                                │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/core.py:1688 in invoke                             │
│                                                                                                  │
│   1685 │   │   │   │   super().invoke(ctx)                                                       │
│   1686 │   │   │   │   sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)                    │
│   1687 │   │   │   │   with sub_ctx:                                                             │
│ ❱ 1688 │   │   │   │   │   return _process_result(sub_ctx.command.invoke(sub_ctx))               │
│   1689 │   │                                                                                     │
│   1690 │   │   # In chain mode we create the contexts step by step, but after the                │
│   1691 │   │   # base command has been invoked.  Because at that point we do not                 │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/core.py:1688 in invoke                             │
│                                                                                                  │
│   1685 │   │   │   │   super().invoke(ctx)                                                       │
│   1686 │   │   │   │   sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)                    │
│   1687 │   │   │   │   with sub_ctx:                                                             │
│ ❱ 1688 │   │   │   │   │   return _process_result(sub_ctx.command.invoke(sub_ctx))               │
│   1689 │   │                                                                                     │
│   1690 │   │   # In chain mode we create the contexts step by step, but after the                │
│   1691 │   │   # base command has been invoked.  Because at that point we do not                 │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/core.py:1434 in invoke                             │
│                                                                                                  │
│   1431 │   │   │   echo(style(message, fg="red"), err=True)                                      │
│   1432 │   │                                                                                     │
│   1433 │   │   if self.callback is not None:                                                     │
│ ❱ 1434 │   │   │   return ctx.invoke(self.callback, **ctx.params)                                │
│   1435 │                                                                                         │
│   1436 │   def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:  │
│   1437 │   │   """Return a list of completions for the incomplete value. Looks                   │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/core.py:783 in invoke                              │
│                                                                                                  │
│    780 │   │                                                                                     │
│    781 │   │   with augment_usage_errors(__self):                                                │
│    782 │   │   │   with ctx:                                                                     │
│ ❱  783 │   │   │   │   return __callback(*args, **kwargs)                                        │
│    784 │                                                                                         │
│    785 │   def forward(                                                                          │
│    786 │   │   __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any  # noqa: B902             │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/click/decorators.py:33 in new_func                       │
│                                                                                                  │
│    30 │   """                                                                                    │
│    31 │                                                                                          │
│    32 │   def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R":                            │
│ ❱  33 │   │   return f(get_current_context(), *args, **kwargs)                                   │
│    34 │                                                                                          │
│    35 │   return update_wrapper(new_func, f)                                                     │
│    36                                                                                            │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/__main__.py:839 in modules_install               │
│                                                                                                  │
│    836 │   from nf_core.modules import ModuleInstall                                             │
│    837 │                                                                                         │
│    838 │   try:                                                                                  │
│ ❱  839 │   │   module_install = ModuleInstall(                                                   │
│    840 │   │   │   dir,                                                                          │
│    841 │   │   │   force,                                                                        │
│    842 │   │   │   prompt,                                                                       │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/modules/install.py:16 in __init__                │
│                                                                                                  │
│   13 │   │   no_pull=False,                                                                      │
│   14 │   │   installed_by=False,                                                                 │
│   15 │   ):                                                                                      │
│ ❱ 16 │   │   super().__init__(                                                                   │
│   17 │   │   │   pipeline_dir,                                                                   │
│   18 │   │   │   "modules",                                                                      │
│   19 │   │   │   force=force,                                                                    │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/components/install.py:35 in __init__             │
│                                                                                                  │
│    32 │   │   no_pull=False,                                                                     │
│    33 │   │   installed_by=False,                                                                │
│    34 │   ):                                                                                     │
│ ❱  35 │   │   super().__init__(component_type, pipeline_dir, remote_url, branch, no_pull)        │
│    36 │   │   self.force = force                                                                 │
│    37 │   │   self.prompt = prompt                                                               │
│    38 │   │   self.sha = sha                                                                     │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/components/components_command.py:40 in __init__  │
│                                                                                                  │
│    37 │   │   self.modules_repo = ModulesRepo(remote_url, branch, no_pull, hide_progress)        │
│    38 │   │   self.hide_progress = hide_progress                                                 │
│    39 │   │   self.no_prompts = no_prompts                                                       │
│ ❱  40 │   │   self._configure_repo_and_paths()                                                   │
│    41 │                                                                                          │
│    42 │   def _configure_repo_and_paths(self, nf_dir_req: bool = True) -> None:                  │
│    43 │   │   """                                                                                │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/components/components_command.py:53 in           │
│ _configure_repo_and_paths                                                                        │
│                                                                                                  │
│    50 │   │                                                                                      ��
│    51 │   │   try:                                                                               │
│    52 │   │   │   if self.dir:                                                                   │
│ ❱  53 │   │   │   │   self.dir, self.repo_type, self.org = get_repo_info(self.dir, use_prompt=   │
│    54 │   │   │   else:                                                                          │
│    55 │   │   │   │   self.repo_type = None                                                      │
│    56 │   │   │   │   self.org = ""                                                              │
│                                                                                                  │
│ /opt/conda/lib/python3.12/site-packages/nf_core/components/components_utils.py:47 in             │
│ get_repo_info                                                                                    │
│                                                                                                  │
│    44 │   │   # Save the choice in the config file                                               │
│    45 │   │   log.info(f"To avoid this prompt in the future, add the 'repository_type' key to    │
│    46 │   │   if rich.prompt.Confirm.ask("[bold][blue]?[/] Would you like me to add this confi   │
│ ❱  47 │   │   │   with open(config_fn, "a+") as fh:                                              │
│    48 │   │   │   │   fh.write(f"repository_type: {repo_type}\n")                                │
│    49 │   │   │   │   log.info(f"Config added to '{config_fn.name}'")                            │
│    50                                                                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
PermissionError: [Errno 13] Permission denied: '/.nf-core.yml'

System information

Repo: https://github.com/mahesh-panchal/Nextflow_sandbox

awgymer commented 3 months ago

This looks suspiciously like the bug fixed in https://github.com/nf-core/tools/pull/2863. But that fix should be in 2.14.1 🤔

awgymer commented 3 months ago

Wow. I am a 🤡. I fixed the issue but for some reason reverted the actual fix from the previous MR at the same time and never noticed. One day I will add tests when I fix this function which stops all this foot-gunning.

Luckily it seems Julia already fixed this in dev with #3003

mahesh-panchal commented 3 months ago

Verified it's been fixed in dev.