Skip to content

Commit

Permalink
Moved documentation annotation stripping into utility function. Chang…
Browse files Browse the repository at this point in the history
…ed argparse decorator to automatically strip annotations.
  • Loading branch information
anselor committed Apr 25, 2022
1 parent 96acc5a commit a222470
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 21 deletions.
19 changes: 2 additions & 17 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
from .utils import (
Settable,
get_defining_class,
strip_doc_annotations,
)

# Set up readline
Expand Down Expand Up @@ -3808,23 +3809,7 @@ def _print_topics(self, header: str, cmds: List[str], verbose: bool) -> None:
doc = cmd_func.__doc__

# Attempt to locate the first documentation block
cmd_desc = ''
if doc:
found_first = False
for doc_line in doc.splitlines():
stripped_line = doc_line.strip()

# Don't include :param type lines
if stripped_line.startswith(':'):
if found_first:
break
elif stripped_line:
if found_first:
cmd_desc += "\n"
cmd_desc += stripped_line
found_first = True
elif found_first:
break
cmd_desc = strip_doc_annotations(doc) if doc else ''

# Add this command to the table
table_row = topic_table.generate_data_row([command, cmd_desc])
Expand Down
5 changes: 4 additions & 1 deletion cmd2/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
from .parsing import (
Statement,
)
from .utils import (
strip_doc_annotations,
)

if TYPE_CHECKING: # pragma: no cover
import cmd2
Expand Down Expand Up @@ -384,7 +387,7 @@ def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:

# If the description has not been set, then use the method docstring if one exists
if parser.description is None and func.__doc__:
parser.description = func.__doc__
parser.description = strip_doc_annotations(func.__doc__)

# Set the command's help text as argparser.description (which can be None)
cmd_wrapper.__doc__ = parser.description
Expand Down
26 changes: 26 additions & 0 deletions cmd2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1228,3 +1228,29 @@ def __init__(self, parser: argparse.ArgumentParser, *, preserve_quotes: bool = F
"""
self.parser = parser
self.preserve_quotes = preserve_quotes


def strip_doc_annotations(doc: str) -> str:
"""
Strip annotations from a docstring leaving only the text description
:param doc: documentation string
"""
# Attempt to locate the first documentation block
cmd_desc = ''
found_first = False
for doc_line in doc.splitlines():
stripped_line = doc_line.strip()

# Don't include :param type lines
if stripped_line.startswith(':'):
if found_first:
break
elif stripped_line:
if found_first:
cmd_desc += "\n"
cmd_desc += stripped_line
found_first = True
elif found_first:
break
return cmd_desc
6 changes: 5 additions & 1 deletion examples/arg_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ def do_fsize(self, args: argparse.Namespace) -> None:

@cmd2.with_argparser(pow_parser)
def do_pow(self, args: argparse.Namespace) -> None:
"""Raise an integer to a small integer exponent, either positive or negative"""
"""
Raise an integer to a small integer exponent, either positive or negative
:param args: argparse arguments
"""
self.poutput('{} ** {} == {}'.format(args.base, args.exponent, args.base**args.exponent))


Expand Down
13 changes: 11 additions & 2 deletions tests/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ def namespace_provider(self) -> argparse.Namespace:

@cmd2.with_argparser(say_parser)
def do_say(self, args, *, keyword_arg: Optional[str] = None):
"""Repeat what you tell me to."""
"""
Repeat what you
tell me to.
:param args: argparse namespace
:param keyword_arg: Optional keyword arguments
"""
words = []
for word in args.words:
if word is None:
Expand Down Expand Up @@ -198,7 +204,10 @@ def test_argparse_help_docstring(argparse_app):
out, err = run_cmd(argparse_app, 'help say')
assert out[0].startswith('Usage: say')
assert out[1] == ''
assert out[2] == 'Repeat what you tell me to.'
assert out[2] == 'Repeat what you'
assert out[3] == 'tell me to.'
for line in out:
assert not line.startswith(':')


def test_argparse_help_description(argparse_app):
Expand Down

0 comments on commit a222470

Please sign in to comment.