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 lint fails when custom module is patched #2659

Closed RHReynolds closed 8 months ago

RHReynolds commented 8 months ago

Description of the bug

If a module installed from a custom repository contains a patch, nf-core lint fails with the error ValueError: 'modules/nf-core-test/bwa/mem/main.nf' does not start with 'modules/nf-core/bwa/mem'

To reproduce this error, the following can be done. In a pipeline created using the nf-core template:

  1. Install bwa/mem using nf-core modules --branch nf-test-tests --git-remote https://gitlab.com/nf-core/modules-test.git install bwa/mem
  2. Alter a file. For example, I altered main.nf , adding an echo "HELLO WORLD" to the script.
  3. Add a patch with nf-core modules --branch nf-test-tests --git-remote https://gitlab.com/nf-core/modules-test.git patch bwa/mem
  4. Run nf-core lint

Command used and terminal output

$ nf-core lint

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

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

INFO     Testing pipeline: .                                                                                                                                                                                                    
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/ec2-user/miniconda3/envs/nf-core/bin/nf-core:10 in <module>                                │
│                                                                                                  │
│    7                                                                                             │
│    8 if __name__ == '__main__':                                                                  │
│    9 │   sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])                       │
│ ❱ 10 │   sys.exit(run_nf_core())                                                                 │
│   11                                                                                             │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/__main__.py:111 in    │
│ run_nf_core                                                                                      │
│                                                                                                  │
│    108 │   │   │   log.debug(f"Could not check latest version: {e}")                             │
│    109 │   │   stderr.print("\n")                                                                │
│    110 │   # Launch the click cli                                                                │
│ ❱  111 │   nf_core_cli(auto_envvar_prefix="NFCORE")                                              │
│    112                                                                                           │
│    113                                                                                           │
│    114 @click.group(context_settings=dict(help_option_names=["-h", "--help"]))                   │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/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):                                                               │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/rich_click/rich_command.py:12 │
│ 6 in main                                                                                        │
│                                                                                                  │
│   123 │   │   try:                                                                               │
│   124 │   │   │   try:                                                                           │
│   125 │   │   │   │   with self.make_context(prog_name, args, **extra) as ctx:                   │
│ ❱ 126 │   │   │   │   │   rv = self.invoke(ctx)                                                  │
│   127 │   │   │   │   │   if not standalone_mode:                                                │
│   128 │   │   │   │   │   │   return rv                                                          │
│   129 │   │   │   │   │   # it's not safe to `ctx.exit(rv)` here!                                │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/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                 │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/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                   │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/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             │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/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                                                                                            │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/__main__.py:468 in    │
│ lint                                                                                             │
│                                                                                                  │
│    465 │                                                                                         │
│    466 │   # Run the lint tests!                                                                 │
│    467 │   try:                                                                                  │
│ ❱  468 │   │   lint_obj, module_lint_obj = run_linting(                                          │
│    469 │   │   │   dir,                                                                          │
│    470 │   │   │   release,                                                                      │
│    471 │   │   │   fix,                                                                          │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/lint/__init__.py:121  │
│ in run_linting                                                                                   │
│                                                                                                  │
│   118 │   if len(module_lint_obj.all_local_components) > 0:                                      │
│   119 │   │   module_lint_obj.lint_modules(module_lint_obj.all_local_components, local=True)     │
│   120 │   if len(module_lint_obj.all_remote_components) > 0:                                     │
│ ❱ 121 │   │   module_lint_obj.lint_modules(module_lint_obj.all_remote_components, local=False)   │
│   122 │                                                                                          │
│   123 │   # Print the results                                                                    │
│   124 │   lint_obj._print_results(show_passed)                                                   │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/modules/lint/__init__ │
│ .py:187 in lint_modules                                                                          │
│                                                                                                  │
│   184 │   │   │                                                                                  │
│   185 │   │   │   for mod in modules:                                                            │
│   186 │   │   │   │   progress_bar.update(lint_progress, advance=1, test_name=mod.component_na   │
│ ❱ 187 │   │   │   │   self.lint_module(mod, progress_bar, registry=registry, local=local, fix_   │
│   188 │                                                                                          │
│   189 │   def lint_module(self, mod, progress_bar, registry, local=False, fix_version=False):    │
│   190 │   │   """                                                                                │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/modules/lint/__init__ │
│ .py:222 in lint_module                                                                           │
│                                                                                                  │
│   219 │   │   │   │   if test_name == "main_nf":                                                 │
│   220 │   │   │   │   │   getattr(self, test_name)(mod, fix_version, self.registry, progress_b   │
│   221 │   │   │   │   else:                                                                      │
│ ❱ 222 │   │   │   │   │   getattr(self, test_name)(mod)                                          │
│   223 │   │   │                                                                                  │
│   224 │   │   │   self.passed += [LintResult(mod, *m) for m in mod.passed]                       │
│   225 │   │   │   warned = [LintResult(mod, *m) for m in mod.warned]                             │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/modules/lint/module_c │
│ hanges.py:32 in module_changes                                                                   │
│                                                                                                  │
│   29 │   │   tempdir = tempdir_parent / "tmp_module_dir"                                         │
│   30 │   │   shutil.copytree(module.component_dir, tempdir)                                      │
│   31 │   │   try:                                                                                │
│ ❱ 32 │   │   │   new_lines = ModulesDiffer.try_apply_patch(                                      │
│   33 │   │   │   │   module.component_name,                                                      │
│   34 │   │   │   │   module_lint_object.modules_repo.repo_path,                                  │
│   35 │   │   │   │   module.patch_path,                                                          │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/site-packages/nf_core/modules/modules_diffe │
│ r.py:448 in try_apply_patch                                                                      │
│                                                                                                  │
│   445 │   │   new_files = {}                                                                     │
│   446 │   │   for file, patch in patches.items():                                                │
│   447 │   │   │   log.debug(f"Applying patch to {file}")                                         │
│ ❱ 448 │   │   │   fn = Path(file).relative_to(module_relpath)                                    │
│   449 │   │   │   file_path = module_dir / fn                                                    │
│   450 │   │   │   with open(file_path, "r") as fh:                                               │
│   451 │   │   │   │   file_lines = fh.readlines()                                                │
│                                                                                                  │
│ /home/ec2-user/miniconda3/envs/nf-core/lib/python3.8/pathlib.py:908 in relative_to               │
│                                                                                                  │
│    905 │   │   cf = self._flavour.casefold_parts                                                 │
│    906 │   │   if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):            │
│    907 │   │   │   formatted = self._format_parsed_parts(to_drv, to_root, to_parts)              │
│ ❱  908 │   │   │   raise ValueError("{!r} does not start with {!r}"                              │
│    909 │   │   │   │   │   │   │    .format(str(self), str(formatted)))                          │
│    910 │   │   return self._from_parsed_parts('', root if n == 1 else '',                        │
│    911 │   │   │   │   │   │   │   │   │      abs_parts[n:])                                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ValueError: 'modules/nf-core-test/bwa/mem/main.nf' does not start with 'modules/nf-core/bwa/mem'

System information

mirpedrol commented 8 months ago

Fixed with #2669