Skip to content

Commit 2674341

Browse files
authored
Merge pull request #969 from python-cmd2/subcmd_fix
Subcmd fix
2 parents 47568c0 + a04fdb5 commit 2674341

File tree

7 files changed

+223
-180
lines changed

7 files changed

+223
-180
lines changed

CHANGELOG.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
## 1.3.2 (August 7, 2020)
2+
* Bug Fixes
3+
* Fixed `prog` value of subcommands added with `as_subcommand_to()` decorator.
4+
* Fixed missing settings in subcommand parsers created with `as_subcommand_to()` decorator. These settings
5+
include things like description and epilog text.
6+
17
## 1.3.1 (August 6, 2020)
28
* Bug Fixes
39
* Fixed issue determining whether an argparse completer function required a reference to a containing
4-
CommandSet. Also resolves issues determining the correct CommandSet instance when calling the argparse
5-
argument completer function. Manifested as a TypeError when using `cmd2.Cmd.path_complete` as a completer
6-
for an argparse-based command defined in a CommandSet
10+
CommandSet. Also resolves issues determining the correct CommandSet instance when calling the argparse
11+
argument completer function. Manifested as a TypeError when using `cmd2.Cmd.path_complete` as a completer
12+
for an argparse-based command defined in a CommandSet
713

814
## 1.3.0 (August 4, 2020)
915
* Enhancements

CODEOWNERS

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616
# cmd2 code
1717
cmd2/__init__.py @tleonhardt @kotfu
1818
cmd2/ansi.py @kmvanbrunt @tleonhardt
19-
cmd2/argparse_*.py @kmvanbrunt
19+
cmd2/argparse_*.py @kmvanbrunt @anselor
2020
cmd2/clipboard.py @tleonhardt
2121
cmd2/cmd2.py @tleonhardt @kmvanbrunt @kotfu
22+
cmd2/command_definition.py @anselor
2223
cmd2/constants.py @kotfu
24+
cmd2/decorators.py @kotfu @kmvanbrunt @anselor
25+
cmd2/exceptions.py @kmvanbrunt @anselor
26+
cmd2/history.py @kotfu @tleonhardt
2327
cmd2/parsing.py @kotfu @kmvanbrunt
2428
cmd2/plugin.py @kotfu
25-
cmd2/pyscript_bridge.py @kmvanbrunt
29+
cmd2/py_bridge.py @kmvanbrunt
2630
cmd2/rl_utils.py @kmvanbrunt
31+
cmd2/table_creator.py @kmvanbrunt
2732
cmd2/transcript.py @kotfu
2833
cmd2/utils.py @tleonhardt @kotfu @kmvanbrunt
2934

@@ -34,6 +39,11 @@ docs/* @tleonhardt @kotfu
3439
examples/async_printing.py @kmvanbrunt
3540
examples/environment.py @kotfu
3641
examples/tab_*.py @kmvanbrunt
42+
examples/modular_*.py @anselor
43+
examples/modular_commands/* @anselor
44+
45+
plugins/template/* @kotfu
46+
plugins/ext_test/* @anselor
3747

3848
# Unit Tests
3949
tests/pyscript/* @kmvanbrunt
@@ -47,6 +57,8 @@ tests/test_pars*.py @kotfu
4757
tests/test_run_pyscript.py @kmvanbrunt
4858
tests/test_transcript.py @kotfu
4959

60+
tests_isolated/test_commandset/* @anselor
61+
5062
# Top-level project stuff
5163
CONTRIBUTING.md @tleonhardt @kotfu
5264
setup.py @tleonhardt @kotfu

cmd2/cmd2.py

Lines changed: 175 additions & 155 deletions
Large diffs are not rendered by default.

cmd2/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
# subcommand attributes for the base command name and the subcommand name
5757
SUBCMD_ATTR_COMMAND = 'parent_command'
5858
SUBCMD_ATTR_NAME = 'subcommand_name'
59-
SUBCMD_ATTR_PARSER_ARGS = 'subcommand_parser_args'
59+
SUBCMD_ATTR_ADD_PARSER_KWARGS = 'subcommand_add_parser_kwargs'
6060

6161
# arpparse attribute linking to command set instance
6262
PARSER_ATTR_COMMANDSET = 'command_set'

cmd2/decorators.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -326,37 +326,40 @@ def as_subcommand_to(command: str,
326326
subcommand: str,
327327
parser: argparse.ArgumentParser,
328328
*,
329-
help_text: Optional[str] = None,
329+
help: Optional[str] = None,
330330
aliases: Iterable[str] = None) -> Callable[[argparse.Namespace], Optional[bool]]:
331331
"""
332332
Tag this method as a subcommand to an existing argparse decorated command.
333333
334334
:param command: Command Name. Space-delimited subcommands may optionally be specified
335335
:param subcommand: Subcommand name
336336
:param parser: argparse Parser for this subcommand
337-
:param help_text: Help message for this subcommand
338-
:param aliases: Alternative names for this subcommand
337+
:param help: Help message for this subcommand which displays in the list of subcommands of the command we are adding to.
338+
This is passed as the help argument to ArgumentParser.add_subparser().
339+
:param aliases: Alternative names for this subcommand. This is passed as the alias argument to
340+
ArgumentParser.add_subparser().
339341
:return: Wrapper function that can receive an argparse.Namespace
340342
"""
341343
def arg_decorator(func: Callable):
342-
_set_parser_prog(parser, subcommand)
344+
_set_parser_prog(parser, command + ' ' + subcommand)
343345

344346
# If the description has not been set, then use the method docstring if one exists
345347
if parser.description is None and func.__doc__:
346348
parser.description = func.__doc__
347349

348-
parser.set_defaults(func=func)
349-
350350
# Set some custom attributes for this command
351351
setattr(func, constants.SUBCMD_ATTR_COMMAND, command)
352352
setattr(func, constants.CMD_ATTR_ARGPARSER, parser)
353353
setattr(func, constants.SUBCMD_ATTR_NAME, subcommand)
354-
parser_args = {}
355-
if help_text is not None:
356-
parser_args['help'] = help_text
354+
355+
# Keyword arguments for ArgumentParser.add_subparser()
356+
add_parser_kwargs = dict()
357+
if help is not None:
358+
add_parser_kwargs['help'] = help
357359
if aliases is not None:
358-
parser_args['aliases'] = aliases[:]
359-
setattr(func, constants.SUBCMD_ATTR_PARSER_ARGS, parser_args)
360+
add_parser_kwargs['aliases'] = aliases[:]
361+
362+
setattr(func, constants.SUBCMD_ATTR_ADD_PARSER_KWARGS, add_parser_kwargs)
360363

361364
return func
362365

examples/modular_subcommands.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22
# coding=utf-8
3-
"""A simple example demonstracting modular subcommand loading through CommandSets
3+
"""A simple example demonstrating modular subcommand loading through CommandSets
44
55
In this example, there are loadable CommandSets defined. Each CommandSet has 1 subcommand defined that will be
66
attached to the 'cut' command.
@@ -23,10 +23,11 @@ def __init__(self):
2323
def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement):
2424
cmd.poutput('Apple')
2525

26-
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
26+
banana_description = "Cut a banana"
27+
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False, description=banana_description)
2728
banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
2829

29-
@cmd2.as_subcommand_to('cut', 'banana', banana_parser)
30+
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help=banana_description.lower())
3031
def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace):
3132
"""Cut banana"""
3233
cmd.poutput('cutting banana: ' + ns.direction)
@@ -40,10 +41,11 @@ def __init__(self):
4041
def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement):
4142
cmd.poutput('Arugula')
4243

43-
bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False)
44+
bokchoy_description = "Cut some bokchoy"
45+
bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False, description=bokchoy_description)
4446
bokchoy_parser.add_argument('style', choices=['quartered', 'diced'])
4547

46-
@cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser)
48+
@cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser, help=bokchoy_description.lower())
4749
def cut_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement):
4850
cmd.poutput('Bok Choy')
4951

@@ -95,9 +97,9 @@ def do_unload(self, ns: argparse.Namespace):
9597

9698
@with_argparser(cut_parser)
9799
def do_cut(self, ns: argparse.Namespace):
100+
# Call handler for whatever subcommand was selected
98101
handler = ns.get_handler()
99102
if handler is not None:
100-
# Call whatever subcommand function was selected
101103
handler(ns)
102104
else:
103105
# No subcommand was provided, so call help

tests_isolated/test_commandset/test_commandset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement):
330330
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
331331
banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
332332

333-
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help_text='Cut banana', aliases=['bananer'])
333+
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help='Cut banana', aliases=['bananer'])
334334
def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace):
335335
"""Cut banana"""
336336
cmd.poutput('cutting banana: ' + ns.direction)
@@ -545,7 +545,7 @@ def do_cut(self, ns: argparse.Namespace):
545545
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
546546
banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
547547

548-
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help_text='Cut banana', aliases=['bananer'])
548+
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help='Cut banana', aliases=['bananer'])
549549
def cut_banana(self, ns: argparse.Namespace):
550550
"""Cut banana"""
551551
self.poutput('cutting banana: ' + ns.direction)

0 commit comments

Comments
 (0)