We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Show ignore modules in `nf-core modules bump-versions`
Modules ignore via the `.nf-core.yml` are currently not shown at all when running the `nf-core modules bump-versions` command. 

## Describe the solution you'd like

Add a new `Module ignored` section to `nf-core modules bump-versions` table with modules ignored via the `.nf-core.yml`. 

## Describe alternatives you've considered

Issue a log messages about which modules have been ignored. 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nf_core/modules/bump_versions.py`
Content:
```
1 """
2 Bump versions for all modules on nf-core/modules
3 or for a single module
4 """
5 
6 
7 from __future__ import print_function
8 import logging
9 import questionary
10 import os
11 import re
12 import rich
13 from rich.console import Console
14 from rich.table import Table
15 from rich.markdown import Markdown
16 import rich
17 from nf_core.utils import rich_force_colors
18 
19 import nf_core.utils
20 import nf_core.modules.module_utils
21 from nf_core.modules.nfcore_module import NFCoreModule
22 from .modules_command import ModuleCommand
23 
24 log = logging.getLogger(__name__)
25 
26 
27 class ModuleVersionBumper(ModuleCommand):
28     def __init__(self, pipeline_dir):
29         super().__init__(pipeline_dir)
30 
31         self.up_to_date = None
32         self.updated = None
33         self.failed = None
34         self.show_up_to_date = None
35         self.tools_config = {}
36 
37     def bump_versions(self, module=None, all_modules=False, show_uptodate=False):
38         """
39         Bump the container and conda version of single module or all modules
40 
41         Looks for a bioconda tool version in the `main.nf` file of the module and checks whether
42         are more recent version is available. If yes, then tries to get docker/singularity
43         container links and replace the bioconda version and the container links in the main.nf file
44         of the respective module.
45 
46         Args:
47             module: a specific module to update
48             all_modules: whether to bump versions for all modules
49         """
50         self.up_to_date = []
51         self.updated = []
52         self.failed = []
53         self.show_up_to_date = show_uptodate
54 
55         # Verify that this is not a pipeline
56         self.dir, repo_type = nf_core.modules.module_utils.get_repo_type(self.dir)
57         if not repo_type == "modules":
58             raise nf_core.modules.module_utils.ModuleException(
59                 "This command only works on the nf-core/modules repository, not on pipelines!"
60             )
61 
62         # Get list of all modules
63         _, nfcore_modules = nf_core.modules.module_utils.get_installed_modules(self.dir)
64 
65         # Load the .nf-core.yml config
66         self.tools_config = nf_core.utils.load_tools_config(self.dir)
67 
68         # Prompt for module or all
69         if module is None and not all_modules:
70             question = {
71                 "type": "list",
72                 "name": "all_modules",
73                 "message": "Bump versions for all modules or a single named module?",
74                 "choices": ["All modules", "Named module"],
75             }
76             answer = questionary.unsafe_prompt([question], style=nf_core.utils.nfcore_question_style)
77             if answer["all_modules"] == "All modules":
78                 all_modules = True
79             else:
80                 module = questionary.autocomplete(
81                     "Tool name:",
82                     choices=[m.module_name for m in nfcore_modules],
83                     style=nf_core.utils.nfcore_question_style,
84                 ).unsafe_ask()
85 
86         if module:
87             self.show_up_to_date = True
88             if all_modules:
89                 raise nf_core.modules.module_utils.ModuleException(
90                     "You cannot specify a tool and request all tools to be bumped."
91                 )
92             nfcore_modules = [m for m in nfcore_modules if m.module_name == module]
93             if len(nfcore_modules) == 0:
94                 raise nf_core.modules.module_utils.ModuleException(f"Could not find the specified module: '{module}'")
95 
96         progress_bar = rich.progress.Progress(
97             "[bold blue]{task.description}",
98             rich.progress.BarColumn(bar_width=None),
99             "[magenta]{task.completed} of {task.total}[reset] » [bold yellow]{task.fields[test_name]}",
100             transient=True,
101         )
102         with progress_bar:
103             bump_progress = progress_bar.add_task(
104                 "Bumping nf-core modules versions", total=len(nfcore_modules), test_name=nfcore_modules[0].module_name
105             )
106             for mod in nfcore_modules:
107                 progress_bar.update(bump_progress, advance=1, test_name=mod.module_name)
108                 self.bump_module_version(mod)
109 
110         self._print_results()
111 
112     def bump_module_version(self, module: NFCoreModule):
113         """
114         Bump the bioconda and container version of a single NFCoreModule
115 
116         Args:
117             module: NFCoreModule
118         """
119         config_version = None
120         # Extract bioconda version from `main.nf`
121         bioconda_packages = self.get_bioconda_version(module)
122 
123         # If multiple versions - don't update! (can't update mulled containers)
124         if not bioconda_packages or len(bioconda_packages) > 1:
125             self.failed.append((f"Ignoring mulled container", module.module_name))
126             return False
127 
128         # Don't update if blocked in blacklist
129         self.bump_versions_config = self.tools_config.get("bump-versions", {})
130         if module.module_name in self.bump_versions_config:
131             config_version = self.bump_versions_config[module.module_name]
132             if not config_version:
133                 self.up_to_date.append((f"Omitting module due to config: {module.module_name}", module.module_name))
134                 return False
135 
136         # check for correct version and newer versions
137         bioconda_tool_name = bioconda_packages[0].split("=")[0].replace("bioconda::", "").strip("'").strip('"')
138         bp = bioconda_packages[0]
139         bp = bp.strip("'").strip('"')
140         bioconda_version = bp.split("=")[1]
141 
142         if not config_version:
143             try:
144                 response = nf_core.utils.anaconda_package(bp)
145             except (LookupError, ValueError) as e:
146                 self.failed.append((f"Conda version not specified correctly: {module.main_nf}", module.module_name))
147                 return False
148 
149             # Check that required version is available at all
150             if bioconda_version not in response.get("versions"):
151                 self.failed.append((f"Conda package had unknown version: `{module.main_nf}`", module.module_name))
152                 return False
153 
154             # Check version is latest available
155             last_ver = response.get("latest_version")
156         else:
157             last_ver = config_version
158 
159         if last_ver is not None and last_ver != bioconda_version:
160             log.debug(f"Updating version for {module.module_name}")
161             # Get docker and singularity container links
162             try:
163                 docker_img, singularity_img = nf_core.utils.get_biocontainer_tag(bioconda_tool_name, last_ver)
164             except LookupError as e:
165                 self.failed.append((f"Could not download container tags: {e}", module.module_name))
166                 return False
167 
168             patterns = [
169                 (bioconda_packages[0], f"'bioconda::{bioconda_tool_name}={last_ver}'"),
170                 (r"quay.io/biocontainers/{}:[^'\"\s]+".format(bioconda_tool_name), docker_img),
171                 (
172                     r"https://depot.galaxyproject.org/singularity/{}:[^'\"\s]+".format(bioconda_tool_name),
173                     singularity_img,
174                 ),
175             ]
176 
177             with open(module.main_nf, "r") as fh:
178                 content = fh.read()
179 
180             # Go over file content of main.nf and find replacements
181             for pattern in patterns:
182                 found_match = False
183                 newcontent = []
184                 for line in content.splitlines():
185 
186                     # Match the pattern
187                     matches_pattern = re.findall("^.*{}.*$".format(pattern[0]), line)
188                     if matches_pattern:
189                         found_match = True
190 
191                         # Replace the match
192                         newline = re.sub(pattern[0], pattern[1], line)
193                         newcontent.append(newline)
194                     # No match, keep line as it is
195                     else:
196                         newcontent.append(line)
197 
198                 if found_match:
199                     content = "\n".join(newcontent) + "\n"
200                 else:
201                     self.failed.append(
202                         (f"Did not find pattern {pattern[0]} in module {module.module_name}", module.module_name)
203                     )
204                     return False
205 
206             # Write new content to the file
207             with open(module.main_nf, "w") as fh:
208                 fh.write(content)
209 
210             self.updated.append(
211                 (
212                     f"Module updated:  {bioconda_version} --> {last_ver}",
213                     module.module_name,
214                 )
215             )
216             return True
217 
218         else:
219             self.up_to_date.append((f"Module version up to date: {module.module_name}", module.module_name))
220             return True
221 
222     def get_bioconda_version(self, module):
223         """
224         Extract the bioconda version from a module
225         """
226         # Check whether file exists and load it
227         bioconda_packages = None
228         try:
229             with open(module.main_nf, "r") as fh:
230                 lines = fh.readlines()
231         except FileNotFoundError as e:
232             log.error(f"Could not read `main.nf` of {module.module_name} module.")
233             return False
234 
235         for l in lines:
236             if re.search("bioconda::", l):
237                 bioconda_packages = [b for b in l.split() if "bioconda::" in b]
238             if re.search("org/singularity", l):
239                 singularity_tag = l.split("/")[-1].replace('"', "").replace("'", "").split("--")[-1].strip()
240             if re.search("biocontainers", l):
241                 docker_tag = l.split("/")[-1].replace('"', "").replace("'", "").split("--")[-1].strip()
242 
243         if bioconda_packages:
244             return bioconda_packages
245         else:
246             return False
247 
248     def _print_results(self):
249         """
250         Print the results for the bump_versions command
251         Uses the ``rich`` library to print a set of formatted tables to the command line
252         summarising the linting results.
253         """
254 
255         log.debug("Printing bump_versions results")
256 
257         console = Console(force_terminal=rich_force_colors())
258         # Find maximum module name length
259         max_mod_name_len = 40
260         for m in [self.up_to_date, self.updated, self.failed]:
261             try:
262                 max_mod_name_len = max(len(m[2]), max_mod_name_len)
263             except:
264                 pass
265 
266         def _s(some_list):
267             if len(some_list) > 1:
268                 return "s"
269             return ""
270 
271         def format_result(module_updates, table):
272             """
273             Create rows for module updates
274             """
275             # TODO: Row styles don't work current as table-level style overrides.
276             # I'd like to make an issue about this on the rich repo so leaving here in case there is a future fix
277             last_modname = False
278             row_style = None
279             for module_update in module_updates:
280                 if last_modname and module_update[1] != last_modname:
281                     if row_style:
282                         row_style = None
283                     else:
284                         row_style = "magenta"
285                 last_modname = module_update[1]
286                 table.add_row(
287                     Markdown(f"{module_update[1]}"),
288                     Markdown(f"{module_update[0]}"),
289                     style=row_style,
290                 )
291             return table
292 
293         # Table of up to date modules
294         if len(self.up_to_date) > 0 and self.show_up_to_date:
295             console.print(
296                 rich.panel.Panel(
297                     r"[!] {} Module{} version{} up to date.".format(
298                         len(self.up_to_date), _s(self.up_to_date), _s(self.up_to_date)
299                     ),
300                     style="bold green",
301                 )
302             )
303             table = Table(style="green", box=rich.box.ROUNDED)
304             table.add_column("Module name", width=max_mod_name_len)
305             table.add_column("Update Message")
306             table = format_result(self.up_to_date, table)
307             console.print(table)
308 
309         # Table of updated modules
310         if len(self.updated) > 0:
311             console.print(
312                 rich.panel.Panel(
313                     r"[!] {} Module{} updated".format(len(self.updated), _s(self.updated)), style="bold yellow"
314                 )
315             )
316             table = Table(style="yellow", box=rich.box.ROUNDED)
317             table.add_column("Module name", width=max_mod_name_len)
318             table.add_column("Update message")
319             table = format_result(self.updated, table)
320             console.print(table)
321 
322         # Table of modules that couldn't be updated
323         if len(self.failed) > 0:
324             console.print(
325                 rich.panel.Panel(
326                     r"[!] {} Module update{} failed".format(len(self.failed), _s(self.failed)), style="bold red"
327                 )
328             )
329             table = Table(style="red", box=rich.box.ROUNDED)
330             table.add_column("Module name", width=max_mod_name_len)
331             table.add_column("Update message")
332             table = format_result(self.failed, table)
333             console.print(table)
334
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nf_core/modules/bump_versions.py b/nf_core/modules/bump_versions.py
--- a/nf_core/modules/bump_versions.py
+++ b/nf_core/modules/bump_versions.py
@@ -50,6 +50,7 @@
         self.up_to_date = []
         self.updated = []
         self.failed = []
+        self.ignored = []
         self.show_up_to_date = show_uptodate
 
         # Verify that this is not a pipeline
@@ -130,7 +131,7 @@
         if module.module_name in self.bump_versions_config:
             config_version = self.bump_versions_config[module.module_name]
             if not config_version:
-                self.up_to_date.append((f"Omitting module due to config: {module.module_name}", module.module_name))
+                self.ignored.append((f"Omitting module due to config.", module.module_name))
                 return False
 
         # check for correct version and newer versions
@@ -331,3 +332,16 @@
             table.add_column("Update message")
             table = format_result(self.failed, table)
             console.print(table)
+
+        # Table of modules ignored due to `.nf-core.yml`
+        if len(self.ignored) > 0:
+            console.print(
+                rich.panel.Panel(
+                    r"[!] {} Module update{} ignored".format(len(self.ignored), _s(self.ignored)), style="grey58"
+                )
+            )
+            table = Table(style="grey58", box=rich.box.ROUNDED)
+            table.add_column("Module name", width=max_mod_name_len)
+            table.add_column("Update message")
+            table = format_result(self.ignored, table)
+            console.print(table)

{"golden_diff": "diff --git a/nf_core/modules/bump_versions.py b/nf_core/modules/bump_versions.py\n--- a/nf_core/modules/bump_versions.py\n+++ b/nf_core/modules/bump_versions.py\n@@ -50,6 +50,7 @@\n         self.up_to_date = []\n         self.updated = []\n         self.failed = []\n+        self.ignored = []\n         self.show_up_to_date = show_uptodate\n \n         # Verify that this is not a pipeline\n@@ -130,7 +131,7 @@\n         if module.module_name in self.bump_versions_config:\n             config_version = self.bump_versions_config[module.module_name]\n             if not config_version:\n-                self.up_to_date.append((f\"Omitting module due to config: {module.module_name}\", module.module_name))\n+                self.ignored.append((f\"Omitting module due to config.\", module.module_name))\n                 return False\n \n         # check for correct version and newer versions\n@@ -331,3 +332,16 @@\n             table.add_column(\"Update message\")\n             table = format_result(self.failed, table)\n             console.print(table)\n+\n+        # Table of modules ignored due to `.nf-core.yml`\n+        if len(self.ignored) > 0:\n+            console.print(\n+                rich.panel.Panel(\n+                    r\"[!] {} Module update{} ignored\".format(len(self.ignored), _s(self.ignored)), style=\"grey58\"\n+                )\n+            )\n+            table = Table(style=\"grey58\", box=rich.box.ROUNDED)\n+            table.add_column(\"Module name\", width=max_mod_name_len)\n+            table.add_column(\"Update message\")\n+            table = format_result(self.ignored, table)\n+            console.print(table)\n", "issue": "Show ignore modules in `nf-core modules bump-versions`\nModules ignore via the `.nf-core.yml` are currently not shown at all when running the `nf-core modules bump-versions` command. \r\n\r\n## Describe the solution you'd like\r\n\r\nAdd a new `Module ignored` section to `nf-core modules bump-versions` table with modules ignored via the `.nf-core.yml`. \r\n\r\n## Describe alternatives you've considered\r\n\r\nIssue a log messages about which modules have been ignored. \r\n\n", "before_files": [{"content": "\"\"\"\nBump versions for all modules on nf-core/modules\nor for a single module\n\"\"\"\n\n\nfrom __future__ import print_function\nimport logging\nimport questionary\nimport os\nimport re\nimport rich\nfrom rich.console import Console\nfrom rich.table import Table\nfrom rich.markdown import Markdown\nimport rich\nfrom nf_core.utils import rich_force_colors\n\nimport nf_core.utils\nimport nf_core.modules.module_utils\nfrom nf_core.modules.nfcore_module import NFCoreModule\nfrom .modules_command import ModuleCommand\n\nlog = logging.getLogger(__name__)\n\n\nclass ModuleVersionBumper(ModuleCommand):\n    def __init__(self, pipeline_dir):\n        super().__init__(pipeline_dir)\n\n        self.up_to_date = None\n        self.updated = None\n        self.failed = None\n        self.show_up_to_date = None\n        self.tools_config = {}\n\n    def bump_versions(self, module=None, all_modules=False, show_uptodate=False):\n        \"\"\"\n        Bump the container and conda version of single module or all modules\n\n        Looks for a bioconda tool version in the `main.nf` file of the module and checks whether\n        are more recent version is available. If yes, then tries to get docker/singularity\n        container links and replace the bioconda version and the container links in the main.nf file\n        of the respective module.\n\n        Args:\n            module: a specific module to update\n            all_modules: whether to bump versions for all modules\n        \"\"\"\n        self.up_to_date = []\n        self.updated = []\n        self.failed = []\n        self.show_up_to_date = show_uptodate\n\n        # Verify that this is not a pipeline\n        self.dir, repo_type = nf_core.modules.module_utils.get_repo_type(self.dir)\n        if not repo_type == \"modules\":\n            raise nf_core.modules.module_utils.ModuleException(\n                \"This command only works on the nf-core/modules repository, not on pipelines!\"\n            )\n\n        # Get list of all modules\n        _, nfcore_modules = nf_core.modules.module_utils.get_installed_modules(self.dir)\n\n        # Load the .nf-core.yml config\n        self.tools_config = nf_core.utils.load_tools_config(self.dir)\n\n        # Prompt for module or all\n        if module is None and not all_modules:\n            question = {\n                \"type\": \"list\",\n                \"name\": \"all_modules\",\n                \"message\": \"Bump versions for all modules or a single named module?\",\n                \"choices\": [\"All modules\", \"Named module\"],\n            }\n            answer = questionary.unsafe_prompt([question], style=nf_core.utils.nfcore_question_style)\n            if answer[\"all_modules\"] == \"All modules\":\n                all_modules = True\n            else:\n                module = questionary.autocomplete(\n                    \"Tool name:\",\n                    choices=[m.module_name for m in nfcore_modules],\n                    style=nf_core.utils.nfcore_question_style,\n                ).unsafe_ask()\n\n        if module:\n            self.show_up_to_date = True\n            if all_modules:\n                raise nf_core.modules.module_utils.ModuleException(\n                    \"You cannot specify a tool and request all tools to be bumped.\"\n                )\n            nfcore_modules = [m for m in nfcore_modules if m.module_name == module]\n            if len(nfcore_modules) == 0:\n                raise nf_core.modules.module_utils.ModuleException(f\"Could not find the specified module: '{module}'\")\n\n        progress_bar = rich.progress.Progress(\n            \"[bold blue]{task.description}\",\n            rich.progress.BarColumn(bar_width=None),\n            \"[magenta]{task.completed} of {task.total}[reset] \u00bb [bold yellow]{task.fields[test_name]}\",\n            transient=True,\n        )\n        with progress_bar:\n            bump_progress = progress_bar.add_task(\n                \"Bumping nf-core modules versions\", total=len(nfcore_modules), test_name=nfcore_modules[0].module_name\n            )\n            for mod in nfcore_modules:\n                progress_bar.update(bump_progress, advance=1, test_name=mod.module_name)\n                self.bump_module_version(mod)\n\n        self._print_results()\n\n    def bump_module_version(self, module: NFCoreModule):\n        \"\"\"\n        Bump the bioconda and container version of a single NFCoreModule\n\n        Args:\n            module: NFCoreModule\n        \"\"\"\n        config_version = None\n        # Extract bioconda version from `main.nf`\n        bioconda_packages = self.get_bioconda_version(module)\n\n        # If multiple versions - don't update! (can't update mulled containers)\n        if not bioconda_packages or len(bioconda_packages) > 1:\n            self.failed.append((f\"Ignoring mulled container\", module.module_name))\n            return False\n\n        # Don't update if blocked in blacklist\n        self.bump_versions_config = self.tools_config.get(\"bump-versions\", {})\n        if module.module_name in self.bump_versions_config:\n            config_version = self.bump_versions_config[module.module_name]\n            if not config_version:\n                self.up_to_date.append((f\"Omitting module due to config: {module.module_name}\", module.module_name))\n                return False\n\n        # check for correct version and newer versions\n        bioconda_tool_name = bioconda_packages[0].split(\"=\")[0].replace(\"bioconda::\", \"\").strip(\"'\").strip('\"')\n        bp = bioconda_packages[0]\n        bp = bp.strip(\"'\").strip('\"')\n        bioconda_version = bp.split(\"=\")[1]\n\n        if not config_version:\n            try:\n                response = nf_core.utils.anaconda_package(bp)\n            except (LookupError, ValueError) as e:\n                self.failed.append((f\"Conda version not specified correctly: {module.main_nf}\", module.module_name))\n                return False\n\n            # Check that required version is available at all\n            if bioconda_version not in response.get(\"versions\"):\n                self.failed.append((f\"Conda package had unknown version: `{module.main_nf}`\", module.module_name))\n                return False\n\n            # Check version is latest available\n            last_ver = response.get(\"latest_version\")\n        else:\n            last_ver = config_version\n\n        if last_ver is not None and last_ver != bioconda_version:\n            log.debug(f\"Updating version for {module.module_name}\")\n            # Get docker and singularity container links\n            try:\n                docker_img, singularity_img = nf_core.utils.get_biocontainer_tag(bioconda_tool_name, last_ver)\n            except LookupError as e:\n                self.failed.append((f\"Could not download container tags: {e}\", module.module_name))\n                return False\n\n            patterns = [\n                (bioconda_packages[0], f\"'bioconda::{bioconda_tool_name}={last_ver}'\"),\n                (r\"quay.io/biocontainers/{}:[^'\\\"\\s]+\".format(bioconda_tool_name), docker_img),\n                (\n                    r\"https://depot.galaxyproject.org/singularity/{}:[^'\\\"\\s]+\".format(bioconda_tool_name),\n                    singularity_img,\n                ),\n            ]\n\n            with open(module.main_nf, \"r\") as fh:\n                content = fh.read()\n\n            # Go over file content of main.nf and find replacements\n            for pattern in patterns:\n                found_match = False\n                newcontent = []\n                for line in content.splitlines():\n\n                    # Match the pattern\n                    matches_pattern = re.findall(\"^.*{}.*$\".format(pattern[0]), line)\n                    if matches_pattern:\n                        found_match = True\n\n                        # Replace the match\n                        newline = re.sub(pattern[0], pattern[1], line)\n                        newcontent.append(newline)\n                    # No match, keep line as it is\n                    else:\n                        newcontent.append(line)\n\n                if found_match:\n                    content = \"\\n\".join(newcontent) + \"\\n\"\n                else:\n                    self.failed.append(\n                        (f\"Did not find pattern {pattern[0]} in module {module.module_name}\", module.module_name)\n                    )\n                    return False\n\n            # Write new content to the file\n            with open(module.main_nf, \"w\") as fh:\n                fh.write(content)\n\n            self.updated.append(\n                (\n                    f\"Module updated:  {bioconda_version} --> {last_ver}\",\n                    module.module_name,\n                )\n            )\n            return True\n\n        else:\n            self.up_to_date.append((f\"Module version up to date: {module.module_name}\", module.module_name))\n            return True\n\n    def get_bioconda_version(self, module):\n        \"\"\"\n        Extract the bioconda version from a module\n        \"\"\"\n        # Check whether file exists and load it\n        bioconda_packages = None\n        try:\n            with open(module.main_nf, \"r\") as fh:\n                lines = fh.readlines()\n        except FileNotFoundError as e:\n            log.error(f\"Could not read `main.nf` of {module.module_name} module.\")\n            return False\n\n        for l in lines:\n            if re.search(\"bioconda::\", l):\n                bioconda_packages = [b for b in l.split() if \"bioconda::\" in b]\n            if re.search(\"org/singularity\", l):\n                singularity_tag = l.split(\"/\")[-1].replace('\"', \"\").replace(\"'\", \"\").split(\"--\")[-1].strip()\n            if re.search(\"biocontainers\", l):\n                docker_tag = l.split(\"/\")[-1].replace('\"', \"\").replace(\"'\", \"\").split(\"--\")[-1].strip()\n\n        if bioconda_packages:\n            return bioconda_packages\n        else:\n            return False\n\n    def _print_results(self):\n        \"\"\"\n        Print the results for the bump_versions command\n        Uses the ``rich`` library to print a set of formatted tables to the command line\n        summarising the linting results.\n        \"\"\"\n\n        log.debug(\"Printing bump_versions results\")\n\n        console = Console(force_terminal=rich_force_colors())\n        # Find maximum module name length\n        max_mod_name_len = 40\n        for m in [self.up_to_date, self.updated, self.failed]:\n            try:\n                max_mod_name_len = max(len(m[2]), max_mod_name_len)\n            except:\n                pass\n\n        def _s(some_list):\n            if len(some_list) > 1:\n                return \"s\"\n            return \"\"\n\n        def format_result(module_updates, table):\n            \"\"\"\n            Create rows for module updates\n            \"\"\"\n            # TODO: Row styles don't work current as table-level style overrides.\n            # I'd like to make an issue about this on the rich repo so leaving here in case there is a future fix\n            last_modname = False\n            row_style = None\n            for module_update in module_updates:\n                if last_modname and module_update[1] != last_modname:\n                    if row_style:\n                        row_style = None\n                    else:\n                        row_style = \"magenta\"\n                last_modname = module_update[1]\n                table.add_row(\n                    Markdown(f\"{module_update[1]}\"),\n                    Markdown(f\"{module_update[0]}\"),\n                    style=row_style,\n                )\n            return table\n\n        # Table of up to date modules\n        if len(self.up_to_date) > 0 and self.show_up_to_date:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module{} version{} up to date.\".format(\n                        len(self.up_to_date), _s(self.up_to_date), _s(self.up_to_date)\n                    ),\n                    style=\"bold green\",\n                )\n            )\n            table = Table(style=\"green\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update Message\")\n            table = format_result(self.up_to_date, table)\n            console.print(table)\n\n        # Table of updated modules\n        if len(self.updated) > 0:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module{} updated\".format(len(self.updated), _s(self.updated)), style=\"bold yellow\"\n                )\n            )\n            table = Table(style=\"yellow\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update message\")\n            table = format_result(self.updated, table)\n            console.print(table)\n\n        # Table of modules that couldn't be updated\n        if len(self.failed) > 0:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module update{} failed\".format(len(self.failed), _s(self.failed)), style=\"bold red\"\n                )\n            )\n            table = Table(style=\"red\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update message\")\n            table = format_result(self.failed, table)\n            console.print(table)\n", "path": "nf_core/modules/bump_versions.py"}], "after_files": [{"content": "\"\"\"\nBump versions for all modules on nf-core/modules\nor for a single module\n\"\"\"\n\n\nfrom __future__ import print_function\nimport logging\nimport questionary\nimport os\nimport re\nimport rich\nfrom rich.console import Console\nfrom rich.table import Table\nfrom rich.markdown import Markdown\nimport rich\nfrom nf_core.utils import rich_force_colors\n\nimport nf_core.utils\nimport nf_core.modules.module_utils\nfrom nf_core.modules.nfcore_module import NFCoreModule\nfrom .modules_command import ModuleCommand\n\nlog = logging.getLogger(__name__)\n\n\nclass ModuleVersionBumper(ModuleCommand):\n    def __init__(self, pipeline_dir):\n        super().__init__(pipeline_dir)\n\n        self.up_to_date = None\n        self.updated = None\n        self.failed = None\n        self.show_up_to_date = None\n        self.tools_config = {}\n\n    def bump_versions(self, module=None, all_modules=False, show_uptodate=False):\n        \"\"\"\n        Bump the container and conda version of single module or all modules\n\n        Looks for a bioconda tool version in the `main.nf` file of the module and checks whether\n        are more recent version is available. If yes, then tries to get docker/singularity\n        container links and replace the bioconda version and the container links in the main.nf file\n        of the respective module.\n\n        Args:\n            module: a specific module to update\n            all_modules: whether to bump versions for all modules\n        \"\"\"\n        self.up_to_date = []\n        self.updated = []\n        self.failed = []\n        self.ignored = []\n        self.show_up_to_date = show_uptodate\n\n        # Verify that this is not a pipeline\n        self.dir, repo_type = nf_core.modules.module_utils.get_repo_type(self.dir)\n        if not repo_type == \"modules\":\n            raise nf_core.modules.module_utils.ModuleException(\n                \"This command only works on the nf-core/modules repository, not on pipelines!\"\n            )\n\n        # Get list of all modules\n        _, nfcore_modules = nf_core.modules.module_utils.get_installed_modules(self.dir)\n\n        # Load the .nf-core.yml config\n        self.tools_config = nf_core.utils.load_tools_config(self.dir)\n\n        # Prompt for module or all\n        if module is None and not all_modules:\n            question = {\n                \"type\": \"list\",\n                \"name\": \"all_modules\",\n                \"message\": \"Bump versions for all modules or a single named module?\",\n                \"choices\": [\"All modules\", \"Named module\"],\n            }\n            answer = questionary.unsafe_prompt([question], style=nf_core.utils.nfcore_question_style)\n            if answer[\"all_modules\"] == \"All modules\":\n                all_modules = True\n            else:\n                module = questionary.autocomplete(\n                    \"Tool name:\",\n                    choices=[m.module_name for m in nfcore_modules],\n                    style=nf_core.utils.nfcore_question_style,\n                ).unsafe_ask()\n\n        if module:\n            self.show_up_to_date = True\n            if all_modules:\n                raise nf_core.modules.module_utils.ModuleException(\n                    \"You cannot specify a tool and request all tools to be bumped.\"\n                )\n            nfcore_modules = [m for m in nfcore_modules if m.module_name == module]\n            if len(nfcore_modules) == 0:\n                raise nf_core.modules.module_utils.ModuleException(f\"Could not find the specified module: '{module}'\")\n\n        progress_bar = rich.progress.Progress(\n            \"[bold blue]{task.description}\",\n            rich.progress.BarColumn(bar_width=None),\n            \"[magenta]{task.completed} of {task.total}[reset] \u00bb [bold yellow]{task.fields[test_name]}\",\n            transient=True,\n        )\n        with progress_bar:\n            bump_progress = progress_bar.add_task(\n                \"Bumping nf-core modules versions\", total=len(nfcore_modules), test_name=nfcore_modules[0].module_name\n            )\n            for mod in nfcore_modules:\n                progress_bar.update(bump_progress, advance=1, test_name=mod.module_name)\n                self.bump_module_version(mod)\n\n        self._print_results()\n\n    def bump_module_version(self, module: NFCoreModule):\n        \"\"\"\n        Bump the bioconda and container version of a single NFCoreModule\n\n        Args:\n            module: NFCoreModule\n        \"\"\"\n        config_version = None\n        # Extract bioconda version from `main.nf`\n        bioconda_packages = self.get_bioconda_version(module)\n\n        # If multiple versions - don't update! (can't update mulled containers)\n        if not bioconda_packages or len(bioconda_packages) > 1:\n            self.failed.append((f\"Ignoring mulled container\", module.module_name))\n            return False\n\n        # Don't update if blocked in blacklist\n        self.bump_versions_config = self.tools_config.get(\"bump-versions\", {})\n        if module.module_name in self.bump_versions_config:\n            config_version = self.bump_versions_config[module.module_name]\n            if not config_version:\n                self.ignored.append((f\"Omitting module due to config.\", module.module_name))\n                return False\n\n        # check for correct version and newer versions\n        bioconda_tool_name = bioconda_packages[0].split(\"=\")[0].replace(\"bioconda::\", \"\").strip(\"'\").strip('\"')\n        bp = bioconda_packages[0]\n        bp = bp.strip(\"'\").strip('\"')\n        bioconda_version = bp.split(\"=\")[1]\n\n        if not config_version:\n            try:\n                response = nf_core.utils.anaconda_package(bp)\n            except (LookupError, ValueError) as e:\n                self.failed.append((f\"Conda version not specified correctly: {module.main_nf}\", module.module_name))\n                return False\n\n            # Check that required version is available at all\n            if bioconda_version not in response.get(\"versions\"):\n                self.failed.append((f\"Conda package had unknown version: `{module.main_nf}`\", module.module_name))\n                return False\n\n            # Check version is latest available\n            last_ver = response.get(\"latest_version\")\n        else:\n            last_ver = config_version\n\n        if last_ver is not None and last_ver != bioconda_version:\n            log.debug(f\"Updating version for {module.module_name}\")\n            # Get docker and singularity container links\n            try:\n                docker_img, singularity_img = nf_core.utils.get_biocontainer_tag(bioconda_tool_name, last_ver)\n            except LookupError as e:\n                self.failed.append((f\"Could not download container tags: {e}\", module.module_name))\n                return False\n\n            patterns = [\n                (bioconda_packages[0], f\"'bioconda::{bioconda_tool_name}={last_ver}'\"),\n                (r\"quay.io/biocontainers/{}:[^'\\\"\\s]+\".format(bioconda_tool_name), docker_img),\n                (\n                    r\"https://depot.galaxyproject.org/singularity/{}:[^'\\\"\\s]+\".format(bioconda_tool_name),\n                    singularity_img,\n                ),\n            ]\n\n            with open(module.main_nf, \"r\") as fh:\n                content = fh.read()\n\n            # Go over file content of main.nf and find replacements\n            for pattern in patterns:\n                found_match = False\n                newcontent = []\n                for line in content.splitlines():\n\n                    # Match the pattern\n                    matches_pattern = re.findall(\"^.*{}.*$\".format(pattern[0]), line)\n                    if matches_pattern:\n                        found_match = True\n\n                        # Replace the match\n                        newline = re.sub(pattern[0], pattern[1], line)\n                        newcontent.append(newline)\n                    # No match, keep line as it is\n                    else:\n                        newcontent.append(line)\n\n                if found_match:\n                    content = \"\\n\".join(newcontent) + \"\\n\"\n                else:\n                    self.failed.append(\n                        (f\"Did not find pattern {pattern[0]} in module {module.module_name}\", module.module_name)\n                    )\n                    return False\n\n            # Write new content to the file\n            with open(module.main_nf, \"w\") as fh:\n                fh.write(content)\n\n            self.updated.append(\n                (\n                    f\"Module updated:  {bioconda_version} --> {last_ver}\",\n                    module.module_name,\n                )\n            )\n            return True\n\n        else:\n            self.up_to_date.append((f\"Module version up to date: {module.module_name}\", module.module_name))\n            return True\n\n    def get_bioconda_version(self, module):\n        \"\"\"\n        Extract the bioconda version from a module\n        \"\"\"\n        # Check whether file exists and load it\n        bioconda_packages = None\n        try:\n            with open(module.main_nf, \"r\") as fh:\n                lines = fh.readlines()\n        except FileNotFoundError as e:\n            log.error(f\"Could not read `main.nf` of {module.module_name} module.\")\n            return False\n\n        for l in lines:\n            if re.search(\"bioconda::\", l):\n                bioconda_packages = [b for b in l.split() if \"bioconda::\" in b]\n            if re.search(\"org/singularity\", l):\n                singularity_tag = l.split(\"/\")[-1].replace('\"', \"\").replace(\"'\", \"\").split(\"--\")[-1].strip()\n            if re.search(\"biocontainers\", l):\n                docker_tag = l.split(\"/\")[-1].replace('\"', \"\").replace(\"'\", \"\").split(\"--\")[-1].strip()\n\n        if bioconda_packages:\n            return bioconda_packages\n        else:\n            return False\n\n    def _print_results(self):\n        \"\"\"\n        Print the results for the bump_versions command\n        Uses the ``rich`` library to print a set of formatted tables to the command line\n        summarising the linting results.\n        \"\"\"\n\n        log.debug(\"Printing bump_versions results\")\n\n        console = Console(force_terminal=rich_force_colors())\n        # Find maximum module name length\n        max_mod_name_len = 40\n        for m in [self.up_to_date, self.updated, self.failed]:\n            try:\n                max_mod_name_len = max(len(m[2]), max_mod_name_len)\n            except:\n                pass\n\n        def _s(some_list):\n            if len(some_list) > 1:\n                return \"s\"\n            return \"\"\n\n        def format_result(module_updates, table):\n            \"\"\"\n            Create rows for module updates\n            \"\"\"\n            # TODO: Row styles don't work current as table-level style overrides.\n            # I'd like to make an issue about this on the rich repo so leaving here in case there is a future fix\n            last_modname = False\n            row_style = None\n            for module_update in module_updates:\n                if last_modname and module_update[1] != last_modname:\n                    if row_style:\n                        row_style = None\n                    else:\n                        row_style = \"magenta\"\n                last_modname = module_update[1]\n                table.add_row(\n                    Markdown(f\"{module_update[1]}\"),\n                    Markdown(f\"{module_update[0]}\"),\n                    style=row_style,\n                )\n            return table\n\n        # Table of up to date modules\n        if len(self.up_to_date) > 0 and self.show_up_to_date:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module{} version{} up to date.\".format(\n                        len(self.up_to_date), _s(self.up_to_date), _s(self.up_to_date)\n                    ),\n                    style=\"bold green\",\n                )\n            )\n            table = Table(style=\"green\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update Message\")\n            table = format_result(self.up_to_date, table)\n            console.print(table)\n\n        # Table of updated modules\n        if len(self.updated) > 0:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module{} updated\".format(len(self.updated), _s(self.updated)), style=\"bold yellow\"\n                )\n            )\n            table = Table(style=\"yellow\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update message\")\n            table = format_result(self.updated, table)\n            console.print(table)\n\n        # Table of modules that couldn't be updated\n        if len(self.failed) > 0:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module update{} failed\".format(len(self.failed), _s(self.failed)), style=\"bold red\"\n                )\n            )\n            table = Table(style=\"red\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update message\")\n            table = format_result(self.failed, table)\n            console.print(table)\n\n        # Table of modules ignored due to `.nf-core.yml`\n        if len(self.ignored) > 0:\n            console.print(\n                rich.panel.Panel(\n                    r\"[!] {} Module update{} ignored\".format(len(self.ignored), _s(self.ignored)), style=\"grey58\"\n                )\n            )\n            table = Table(style=\"grey58\", box=rich.box.ROUNDED)\n            table.add_column(\"Module name\", width=max_mod_name_len)\n            table.add_column(\"Update message\")\n            table = format_result(self.ignored, table)\n            console.print(table)\n", "path": "nf_core/modules/bump_versions.py"}]}