From d59634824e0ffeb82965f71da8e7623b89e1113f Mon Sep 17 00:00:00 2001 From: Jun Huang Date: Fri, 14 Jul 2023 18:36:19 +0800 Subject: [PATCH] doc: improve help info format for subcommands --- src/pdm/cli/commands/cache.py | 2 +- src/pdm/cli/commands/self_cmd.py | 2 +- src/pdm/cli/commands/venv/__init__.py | 2 +- src/pdm/cli/utils.py | 21 ++++++++++++++++++++- src/pdm/core.py | 3 +-- tests/cli/test_run.py | 6 +++--- 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/pdm/cli/commands/cache.py b/src/pdm/cli/commands/cache.py index 64b9c179bc..09d1f2172e 100644 --- a/src/pdm/cli/commands/cache.py +++ b/src/pdm/cli/commands/cache.py @@ -16,7 +16,7 @@ class Command(BaseCommand): arguments = (verbose_option,) def add_arguments(self, parser: argparse.ArgumentParser) -> None: - subparsers = parser.add_subparsers(title="commands", metavar="cache") + subparsers = parser.add_subparsers(title="commands", metavar="") ClearCommand.register_to(subparsers, "clear") RemoveCommand.register_to(subparsers, "remove") ListCommand.register_to(subparsers, "list") diff --git a/src/pdm/cli/commands/self_cmd.py b/src/pdm/cli/commands/self_cmd.py index 1aac59ef52..fface0c290 100644 --- a/src/pdm/cli/commands/self_cmd.py +++ b/src/pdm/cli/commands/self_cmd.py @@ -65,7 +65,7 @@ def register_to( return super().register_to(subparsers, name, aliases=["plugin"], **kwargs) def add_arguments(self, parser: argparse.ArgumentParser) -> None: - subparsers = parser.add_subparsers(title="commands", metavar="self") + subparsers = parser.add_subparsers(title="commands", metavar="") ListCommand.register_to(subparsers) if not is_in_zipapp(): AddCommand.register_to(subparsers) diff --git a/src/pdm/cli/commands/venv/__init__.py b/src/pdm/cli/commands/venv/__init__.py index 5d9dfd3633..0e6229b339 100644 --- a/src/pdm/cli/commands/venv/__init__.py +++ b/src/pdm/cli/commands/venv/__init__.py @@ -23,7 +23,7 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: group = parser.add_mutually_exclusive_group() group.add_argument("--path", help="Show the path to the given virtualenv") group.add_argument("--python", help="Show the python interpreter path for the given virtualenv") - subparser = parser.add_subparsers(metavar="venv", title="commands") + subparser = parser.add_subparsers(title="commands", metavar="") CreateCommand.register_to(subparser, "create") ListCommand.register_to(subparser, "list") RemoveCommand.register_to(subparser, "remove") diff --git a/src/pdm/cli/utils.py b/src/pdm/cli/utils.py index f42f05387f..98305d63ec 100644 --- a/src/pdm/cli/utils.py +++ b/src/pdm/cli/utils.py @@ -4,6 +4,7 @@ import dataclasses as dc import json import os +import re import sys from collections import ChainMap, OrderedDict from concurrent.futures import ThreadPoolExecutor @@ -68,6 +69,8 @@ def _format_usage( if prefix is None: prefix = "Usage: " result = super()._format_usage(usage, actions, groups, prefix) # type: ignore[arg-type] + # Remove continuous spaces + result = re.sub(r" +", " ", result) if prefix: return result.replace(prefix, termui.style(prefix, style="warning")) return result @@ -96,6 +99,14 @@ def _format_action(self, action: Action) -> str: action_header = "%*s%s\n" % tup indent_first = help_position + # Special format for empty action_header + # - No extra indent block + # - Help info in the same indent level as subactions + if not action_header.strip(): + action_header = "" + help_position = self._current_indent + indent_first = self._current_indent + # collect the pieces of the action help parts = [termui.style(action_header, style="primary")] @@ -109,11 +120,18 @@ def _format_action(self, action: Action) -> str: # or add a newline if the description doesn't end with one elif not action_header.endswith("\n"): - parts.append("\n") + if action_header: + parts.append("\n") + # cancel out extra indent when action_header is empty + if not action_header: + self._dedent() # if there are any sub-actions, add their help as well for subaction in self._iter_indented_subactions(action): parts.append(self._format_action(subaction)) + # cancel out extra dedent when action_header is empty + if not action_header: + self._indent() # return a single string return self._join_parts(parts) @@ -129,6 +147,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.add_argument( "-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit." ) + self._optionals.title = "options" class ErrorArgumentParser(ArgumentParser): diff --git a/src/pdm/core.py b/src/pdm/core.py index 594f3564f2..e7ae5e65ab 100644 --- a/src/pdm/core.py +++ b/src/pdm/core.py @@ -78,12 +78,11 @@ def init_parser(self) -> None: "--config", help="Specify another config file path [env var: PDM_CONFIG_FILE] ", ) - self.parser._positionals.title = "Commands" verbose_option.add_to_parser(self.parser) ignore_python_option.add_to_parser(self.parser) pep582_option.add_to_parser(self.parser) - self.subparsers = self.parser.add_subparsers(parser_class=ArgumentParser, dest="fooo") + self.subparsers = self.parser.add_subparsers(parser_class=ArgumentParser, title="commands", metavar="") for _, name, _ in pkgutil.iter_modules(COMMANDS_MODULE_PATH): module = importlib.import_module(f"pdm.cli.commands.{name}", __name__) try: diff --git a/tests/cli/test_run.py b/tests/cli/test_run.py index 97639fcf1a..497a07dd58 100644 --- a/tests/cli/test_run.py +++ b/tests/cli/test_run.py @@ -819,6 +819,6 @@ def test_empty_positionnal_args_still_display_usage(project, pdm, args): def test_empty_positional_args_display_help(project, pdm): result = pdm([], obj=project) assert result.exit_code == 0 - assert "Usage" in result.output - assert "Commands" in result.output - assert "Option" in result.output + assert "Usage:" in result.output + assert "Commands:" in result.output + assert "Options:" in result.output