Skip to content

Subparsers are ignored when help is not defined on the subparser #190

@mpkocher

Description

@mpkocher

Issue:

  • When calling .add_parser("alpha") to add a subparser and "help" kwarg is not defined, the sub parser will be ignored/skipped.

Requirements:

  • When calling .add_parser("alpha"), the subcommand should be recognized and emitted in the autocomplete.

Workarounds:

  • Always call .add_parser with help= to have any string (even an empty string works).

Example:

#!/usr/bin/env python
import logging
import sys
from pathlib import Path
import argparse
from argparse import ArgumentParser, Namespace
from typing import Callable
import shtab

logger = logging.getLogger(__name__)


def run_alpha(input_path: Path) -> int:
    logger.info(f"Running alpha for {input_path}")
    return 0


def run_beta(src: Path, dest: Path) -> int:
    logger.info(f"Running alpha with {src=} {dest=}")
    return 0


def _to_parser_alpha(p: ArgumentParser) -> ArgumentParser:
    p.add_argument("-i", "--input", type=Path, required=True)
    return p


def _to_parser_beta(p: ArgumentParser) -> ArgumentParser:
    p.add_argument("-s", "--src", type=Path, required=True)
    p.add_argument("-d", "--dest", type=Path, required=True)
    return p


def get_parser() -> ArgumentParser:
    p = ArgumentParser(prog="shtab_test.py")
    sp = p.add_subparsers()

    def _add(
        name: str,
        add_opts: Callable[[ArgumentParser], ArgumentParser],
        func: Callable[[Namespace], int]
    ) -> argparse.ArgumentParser:
        # ******* This has to set help something, otherwise shtab will skip it.
        px = sp.add_parser(name)
        add_opts(px)
        px.set_defaults(func=func)
        return px

    _add("alpha", _to_parser_alpha, lambda ns: run_alpha(ns.input))
    _add("beta", _to_parser_beta, lambda ns: run_beta(ns.src, ns.dest))

    p.add_argument("--version", action="version", version="0.1.0")
    shtab.add_argument_to(p)
    return p


def main(argv: list[str]) -> int:
    logging.basicConfig(level=logging.DEBUG, stream=sys.stderr)
    pargs =  get_parser().parse_args(argv)
    return pargs.func(pargs)


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))

Yields.

 python shtab_test.py --print-completion zsh
DEBUG:shtab:choices:_shtab_example_py:['alpha', 'beta']
DEBUG:shtab:skip:subcommand:alpha
DEBUG:shtab:skip:subcommand:beta
DEBUG:shtab:subcommands:_shtab_example_py:['_shtab_example_py']
#compdef example.py

...

Changing px = sp.add_parser(name) to px = sp.add_parser(name, help=f"Running {name}") resolves the issue.

DEBUG:shtab:choices:_shtab_shtab_test_py:['alpha', 'beta']
DEBUG:shtab:subcommand:alpha
DEBUG:shtab:subcommands:alpha:{'cmd': 'alpha', 'help': '', 'arguments': ['"(- : *)"{-h,--help}"[show this help message and exit]"', '{-i,--input}"[]:input:"'], 'paths': ['alpha'], 'commands': {}}
DEBUG:shtab:subcommand:beta
DEBUG:shtab:subcommands:beta:{'cmd': 'beta', 'help': '', 'arguments': ['"(- : *)"{-h,--help}"[show this help message and exit]"', '{-s,--src}"[]:src:"', '{-d,--dest}"[]:dest:"'], 'paths': ['beta'], 'commands': {}}
DEBUG:shtab:subcommands:_shtab_shtab_test_py:['_shtab_shtab_test_py', '_shtab_shtab_test_py_alpha', '_shtab_shtab_test_py_beta']
#compdef shtab_test.py

This is a simple enough workaround, however the current behavior is a bit surprising.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions