Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: improve help info format for subcommands #2103

Merged
merged 1 commit into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pdm/cli/commands/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion src/pdm/cli/commands/self_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/pdm/cli/commands/venv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
21 changes: 20 additions & 1 deletion src/pdm/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")]

Expand All @@ -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)
Expand All @@ -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):
Expand Down
3 changes: 1 addition & 2 deletions src/pdm/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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="")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commands is the default title?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

In previous revision, the 81L self.parser._positionals.title was set to Commands, force argparse displays "Commands:" as title instead of "Positional Arguments:". But it can be done by setting subparsers title to "commands", as same as other venv/self/cache subparsers, without touching the internal members.

for _, name, _ in pkgutil.iter_modules(COMMANDS_MODULE_PATH):
module = importlib.import_module(f"pdm.cli.commands.{name}", __name__)
try:
Expand Down
6 changes: 3 additions & 3 deletions tests/cli/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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