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

Determine whether to add a subparser to completion by its presence in _get_subactions() #47

Merged
merged 3 commits into from
Aug 24, 2021
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
12 changes: 10 additions & 2 deletions shtab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ def wordify(string):
return string.replace("-", "_").replace(".", " ").replace(" ", "_")


def get_public_subcommands(sub):
"""Get all the publicly-visible subcommands for a given subparser."""
public_parsers = {id(sub.choices[i.dest]) for i in sub._get_subactions()}
return {k for k, v in sub.choices.items() if id(v) in public_parsers}


def get_bash_commands(root_parser, root_prefix, choice_functions=None):
"""
Recursive subcommand parser traversal, returning lists of information on
Expand Down Expand Up @@ -222,7 +228,8 @@ def recurse(parser, prefix):
elif isinstance(positional.choices, dict):
# subparser, so append to list of subparsers & recurse
log.debug("subcommand:%s", choice)
if positional.choices[choice].add_help:
public_cmds = get_public_subcommands(positional)
if choice in public_cmds:
casperdcl marked this conversation as resolved.
Show resolved Hide resolved
discovered_subparsers.append(str(choice))
this_positional_choices.append(str(choice))
(
Expand Down Expand Up @@ -577,8 +584,9 @@ def format_positional(opt):
root_arguments.append(format_positional(opt))
else: # subparser
log.debug("choices:{}:{}".format(root_prefix, sorted(sub.choices)))
public_cmds = get_public_subcommands(sub)
for cmd, subparser in sub.choices.items():
if not subparser.add_help:
if cmd not in public_cmds:
log.debug("skip:subcommand:%s", cmd)
continue
log.debug("subcommand:%s", cmd)
Expand Down
31 changes: 29 additions & 2 deletions tests/test_shtab.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import logging
import subprocess
import sys
from argparse import ArgumentParser

import pytest
Expand Down Expand Up @@ -177,7 +178,7 @@ def test_custom_complete(shell, caplog):
def test_subparser_custom_complete(shell, caplog):
parser = ArgumentParser(prog="test")
subparsers = parser.add_subparsers()
sub = subparsers.add_parser("sub")
sub = subparsers.add_parser("sub", help="help message")
sub.add_argument("posA").complete = {"bash": "_shtab_test_some_func"}
preamble = {"bash": "_shtab_test_some_func() { compgen -W 'one two' -- $1 ;}"}
with caplog.at_level(logging.INFO):
Expand All @@ -194,6 +195,32 @@ def test_subparser_custom_complete(shell, caplog):
assert not caplog.record_tuples


@fix_shell
@pytest.mark.skipif(sys.version_info[0] == 2, reason="requires Python 3.x")
def test_subparser_aliases(shell, caplog):
parser = ArgumentParser(prog="test")
subparsers = parser.add_subparsers()
sub = subparsers.add_parser("sub", aliases=["xsub", "ysub"], help="help message")
sub.add_argument("posA").complete = {"bash": "_shtab_test_some_func"}
preamble = {"bash": "_shtab_test_some_func() { compgen -W 'one two' -- $1 ;}"}
with caplog.at_level(logging.INFO):
completion = shtab.complete(parser, shell=shell, preamble=preamble)
print(completion)

if shell == "bash":
shell = Bash(completion)
shell.compgen('-W "${_shtab_test_subparsers[*]}"', "s", "sub")
shell.compgen('-W "$_shtab_test_pos_0_choices"', "s", "sub")
shell.compgen('-W "${_shtab_test_subparsers[*]}"', "x", "xsub")
shell.compgen('-W "$_shtab_test_pos_0_choices"', "x", "xsub")
shell.compgen('-W "${_shtab_test_subparsers[*]}"', "y", "ysub")
shell.compgen('-W "$_shtab_test_pos_0_choices"', "y", "ysub")
shell.test('"$($_shtab_test_sub_pos_0_COMPGEN o)" = "one"')
shell.test('-z "$_shtab_test_COMPGEN"')

assert not caplog.record_tuples


@fix_shell
def test_add_argument_to_optional(shell, caplog):
parser = ArgumentParser(prog="test")
Expand All @@ -213,7 +240,7 @@ def test_add_argument_to_optional(shell, caplog):
def test_add_argument_to_positional(shell, caplog, capsys):
parser = ArgumentParser(prog="test")
subparsers = parser.add_subparsers()
sub = subparsers.add_parser("completion")
sub = subparsers.add_parser("completion", help="help message")
shtab.add_argument_to(sub, "shell", parent=parser)
from argparse import Namespace

Expand Down