Repository: miurahr/aqtinstall
Pull request #325 (2021-07-18 09:25:05)

Refactor `suggested_follow_up`
This PR splits `aqt.metadata.suggested_follow_up` into:
1. a function that returns a list of strings, and
2. a function that formats and prints those strings

This PR also adds test code for both functions.

Here is an example of what the formatter prints:
```
==============================Suggested follow-up:==============================
* Please use 'aqt list tools mac desktop --extensions <QT_VERSION>' to list valid extensions.
* Please use 'aqt list tools mac desktop' to check what tools are available.
```


Patch:
diff --git a/aqt/metadata.py b/aqt/metadata.py
index ffe5404..22ad916 100644
--- a/aqt/metadata.py
+++ b/aqt/metadata.py
@@ -26,17 +26,7 @@ import random
 import re
 import shutil
 from logging import getLogger
-from typing import (
-    Callable,
-    Dict,
-    Generator,
-    Iterable,
-    Iterator,
-    List,
-    Optional,
-    Tuple,
-    Union,
-)
+from typing import Dict, Generator, Iterable, Iterator, List, Optional, Tuple, Union
 from xml.etree import ElementTree as ElementTree
 
 import bs4
@@ -695,26 +685,34 @@ class MetadataFactory:
         return "{} with minor version {}".format(self.archive_id, self.filter_minor)
 
 
-def suggested_follow_up(meta: MetadataFactory, printer: Callable[[str], None]) -> None:
+def suggested_follow_up(meta: MetadataFactory) -> List[str]:
     """Makes an informed guess at what the user got wrong, in the event of an error."""
-    base_cmd = "aqt {0.category} {0.host} {0.target}".format(meta.archive_id)
+    msg = []
+    base_cmd = "aqt list {0.category} {0.host} {0.target}".format(meta.archive_id)
     if meta.archive_id.extension:
-        msg = "Please use '{} --extensions <QT_VERSION>' to list valid extensions.\n".format(
-            base_cmd
+        msg.append(
+            f"Please use '{base_cmd} --extensions <QT_VERSION>' to list valid extensions."
         )
-        printer(msg)
 
     if meta.archive_id.is_tools() and meta.request_type == "tool variant names":
-        msg = "Please use '{}' to check what tools are available.".format(base_cmd)
-        printer(msg)
+        msg.append(f"Please use '{base_cmd}' to check what tools are available.")
     elif meta.filter_minor is not None:
-        msg = "Please use '{}' to check that versions of {} exist with the minor version '{}'".format(
-            base_cmd, meta.archive_id.category, meta.filter_minor
+        msg.append(
+            f"Please use '{base_cmd}' to check that versions of {meta.archive_id.category} "
+            f"exist with the minor version '{meta.filter_minor}'."
         )
-        printer(msg)
     elif meta.request_type in ("architectures", "modules", "extensions"):
-        msg = "Please use '{}' to show versions of Qt available".format(base_cmd)
-        printer(msg)
+        msg.append(f"Please use '{base_cmd}' to show versions of Qt available.")
+
+    return msg
+
+
+def format_suggested_follow_up(suggestions: Iterable[str]) -> str:
+    if not suggestions:
+        return ""
+    return ("=" * 30 + "Suggested follow-up:" + "=" * 30 + "\n") + "\n".join(
+        ["* " + suggestion for suggestion in suggestions]
+    )
 
 
 def show_list(meta: MetadataFactory) -> int:
@@ -723,7 +721,9 @@ def show_list(meta: MetadataFactory) -> int:
         output = meta.getList()
         if not output:
             logger.info("No {} available for this request.".format(meta.request_type))
-            suggested_follow_up(meta, logger.info)
+            suggestions = suggested_follow_up(meta)
+            if suggestions:
+                logger.info(format_suggested_follow_up(suggestions))
             return 1
         if isinstance(output, Versions):
             print(format(output))
@@ -745,5 +745,7 @@ def show_list(meta: MetadataFactory) -> int:
         return 1
     except (ArchiveConnectionError, ArchiveDownloadError) as e:
         logger.error("{}".format(e))
-        suggested_follow_up(meta, logger.error)
+        suggestions = suggested_follow_up(meta)
+        if suggestions:
+            logger.error(format_suggested_follow_up(suggestions))
         return 1


Test patch:
diff --git a/tests/test_list.py b/tests/test_list.py
index 2014c0c..092116b 100644
--- a/tests/test_list.py
+++ b/tests/test_list.py
@@ -7,7 +7,15 @@ from typing import Generator
 import pytest
 
 from aqt.installer import Cli
-from aqt.metadata import ArchiveId, MetadataFactory, SimpleSpec, Version, Versions
+from aqt.metadata import (
+    ArchiveId,
+    MetadataFactory,
+    SimpleSpec,
+    Version,
+    Versions,
+    format_suggested_follow_up,
+    suggested_follow_up,
+)
 
 
 def test_versions():
@@ -368,3 +376,96 @@ def test_list_invalid_extensions(
     sys.stdout.write(out)
     sys.stderr.write(err)
     assert expected_msg in err
+
+
+mac_qt5 = ArchiveId("qt5", "mac", "desktop")
+mac_wasm = ArchiveId("qt5", "mac", "desktop", "wasm")
+wrong_qt_version_msg = [
+    "Please use 'aqt list qt5 mac desktop' to show versions of Qt available."
+]
+wrong_ext_and_version_msg = [
+    "Please use 'aqt list qt5 mac desktop --extensions <QT_VERSION>' to list valid extensions.",
+    "Please use 'aqt list qt5 mac desktop' to show versions of Qt available.",
+]
+
+
+@pytest.mark.parametrize(
+    "meta, expected_message",
+    (
+        (MetadataFactory(mac_qt5), []),
+        (
+            MetadataFactory(mac_qt5, filter_minor=0),
+            [
+                "Please use 'aqt list qt5 mac desktop' to check that versions of qt5 exist with the minor version '0'."
+            ],
+        ),
+        (
+            MetadataFactory(ArchiveId("tools", "mac", "desktop"), tool_name="ifw"),
+            [
+                "Please use 'aqt list tools mac desktop' to check what tools are available."
+            ],
+        ),
+        (
+            MetadataFactory(mac_qt5, architectures_ver="1.2.3"),
+            wrong_qt_version_msg,
+        ),
+        (
+            MetadataFactory(mac_qt5, modules_ver="1.2.3"),
+            wrong_qt_version_msg,
+        ),
+        (
+            MetadataFactory(mac_qt5, extensions_ver="1.2.3"),
+            wrong_qt_version_msg,
+        ),
+        (
+            MetadataFactory(mac_wasm),
+            [
+                "Please use 'aqt list qt5 mac desktop --extensions <QT_VERSION>' to list valid extensions."
+            ],
+        ),
+        (
+            MetadataFactory(mac_wasm, filter_minor=0),
+            [
+                "Please use 'aqt list qt5 mac desktop --extensions <QT_VERSION>' to list valid extensions.",
+                "Please use 'aqt list qt5 mac desktop' to check that versions of qt5 exist with the minor version '0'.",
+            ],
+        ),
+        (
+            MetadataFactory(
+                ArchiveId("tools", "mac", "desktop", "wasm"), tool_name="ifw"
+            ),
+            [
+                "Please use 'aqt list tools mac desktop --extensions <QT_VERSION>' to list valid extensions.",
+                "Please use 'aqt list tools mac desktop' to check what tools are available.",
+            ],
+        ),
+        (
+            MetadataFactory(mac_wasm, architectures_ver="1.2.3"),
+            wrong_ext_and_version_msg,
+        ),
+        (
+            MetadataFactory(mac_wasm, modules_ver="1.2.3"),
+            wrong_ext_and_version_msg,
+        ),
+        (
+            MetadataFactory(mac_wasm, extensions_ver="1.2.3"),
+            wrong_ext_and_version_msg,
+        ),
+    ),
+)
+def test_suggested_follow_up(meta: MetadataFactory, expected_message: str):
+    assert suggested_follow_up(meta) == expected_message
+
+
+def test_format_suggested_follow_up():
+    suggestions = [
+        "Please use 'aqt list tools mac desktop --extensions <QT_VERSION>' to list valid extensions.",
+        "Please use 'aqt list tools mac desktop' to check what tools are available.",
+    ]
+    expected = (
+        "==============================Suggested follow-up:==============================\n"
+        "* Please use 'aqt list tools mac desktop --extensions <QT_VERSION>' to list valid extensions.\n"
+        "* Please use 'aqt list tools mac desktop' to check what tools are available."
+    )
+
+    assert format_suggested_follow_up(suggestions) == expected