Package: argparse-deco
argparse-deco is basically syntatic sugar for argparse using
decorators. Although it inherited some ideas and concepts from
Kevin L. Mitchell’scli_tools(https://github.com/klmitch/cli_tools), it does not share its source
code.Its main difference is the possibility to abuse Python’s class
syntax to define complex CLI tools with nested subcommands and
the use ofinspect.signatureto autogenerate a command’s arguments
from a function’s signature.Simple CLIThe API suffices to use three imports.>>> from argparse_deco import CLI, Arg, FlagAn an example for a simple CLI, one may useCLIas decorator for a
function in order to transform it:>>> @CLI(prog="prog")
... def prog(
...         integers: Arg(metavar='N', nargs='+', type=int,
...                       help="an integerfor the accumulator"),
...         accumulate: Arg('--sum', action='store_const', const=sum,
...                         help="sum the integers (default: find the max)"
...                         )=max):
...     """Process some integers."""
...     print(accumulate(integers))The decoratorCLItransforms the functionproginto anCommandinstance. Effectivelyprogtakes some command line argument like[ “1”, “2”, “4”, “–sum” ]ascli_argskeyword, which is transformed
by theargparsemodule into argumentsintegerandaccumulatepassed down to the original functionprog:>>> prog(["1", "2", "4", "--sum"])
7
>>> prog(["1", "2", "4"])
4In order to obtain theArgumentParserinstance,proghas the class
methodsetup_parser:>>> parser = prog.setup_parser()
>>> print(parser)
ArgumentParser(prog='prog', usage=None, description='Process some integers.', formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True)
>>> parser.print_usage()
usage: prog [-h] [--sum] N [N ...]>>> parser.print_help()
usage: prog [-h] [--sum] N [N ...]
<BLANKLINE>
Process some integers.
<BLANKLINE>
positional arguments:
  N           an integerfor the accumulator
<BLANKLINE>
optional arguments:
  -h, --help  show this help message and exit
  --sum       sum the integers (default: find the max)ArgumentsIn order for a function’s arguments to be processed asArgumentParserargument, they have to annotated byArg. BasicallyArgallows a the type as keyword, and arbitrary keyword arguments
which are passed almost unchanged toArgumentParser.add_argument.ParserWhile theArgumentParserinstance’sdescriptionis usually the
function’s docstring, one may want to further customise it using theCLI.parserdecorator which accepts any argumentArgumentParserwould.GroupsArguments can be groupsed by using theGroupinstead ofArgin the
argument’s annotation, which accepts a group name as first keyword and
the type as second one. The group can be customised (title,
description) using theCLI.groupdecorator:>>> @CLI("prog")
... @CLI.group('foo', title="Foo", description="Foo group")
... def prog(
...         bar: Arg['foo'](help="Bar option"),
...         baz: Arg['foo'](help="Baz option")):
...     pass
>>> prog.setup_parser().print_help()
usage: prog [-h] bar baz
<BLANKLINE>
optional arguments:
  -h, --help  show this help message and exit
<BLANKLINE>
Foo:
  Foo group
<BLANKLINE>
  bar         Bar option
  baz         Baz optionSimilarily using theCLI.mutually_exclusivedecorator, arguments can
be turned into a mutually exclusive group.Subcommands>>> @CLI("prog")
... @CLI.subparsers(help="sub-command help")
... class prog:
...     def __call__(foo: Flag('--foo', help="foo help")):
...         pass
...     def a(bar: Arg(type=int, help="bar help")):
...         """a help"""
...     def b(baz: Arg('--baz', choices='XYZ', help="baz help")):
...         """b help"""
>>> prog.parser.print_help()
usage: prog [-h] [--foo] {a,b} ...
<BLANKLINE>
positional arguments:
  {a,b}       sub-command help
    a         a help
    b         b help
<BLANKLINE>
optional arguments:
  -h, --help  show this help message and exit
  --foo       foo help>>> prog.parser.parse_args(['a', '12'])
Namespace(_func=<function prog.a at 0x...>, _parser=..., bar=12, foo=False)
>>> prog.parser.parse_args(['--foo', 'b', '--baz', 'Z'])
Namespace(_func=<function prog.b at 0x...>, _parser=..., baz='Z', foo=True)Deeper levels of subcommands can be generated using class definitions within:>>> @CLI("prog")
... class prog:
...     class foo:
...         """foo subcommand"""
...         def bar():
...             """foo bar subsubcommand"""
...         def baz():
...             """foo baz subsubcommand"""
...     class oof:
...         def rab():
...             """oof rab subsubcommand"""
...         def zab():
...             """oof zab subsubcommand"""
>>> prog.parser.print_help()
usage: prog [-h] {foo,oof} ...
<BLANKLINE>
positional arguments:
  {foo,oof}
    foo       foo subcommand
<BLANKLINE>
optional arguments:
  -h, --help  show this help message and exit