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

Substitute %(prog)s in description and epilog and in subparsers documentation. #113

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
16 changes: 12 additions & 4 deletions sphinxarg/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _try_add_parser_attribute(data, parser, attribname):
if not isinstance(attribval, str):
return
if len(attribval) > 0:
data[attribname] = attribval
data[attribname] = attribval % {'prog': data['prog']}
qha marked this conversation as resolved.
Show resolved Hide resolved


def _format_usage_without_prefix(parser):
Expand Down Expand Up @@ -86,10 +86,12 @@ def parse_parser(parser, data=None, **kwargs):
subaction.prog = '%s %s' % (parser.prog, name)
subdata = {
'name': name if not subalias else '%s (%s)' % (name, ', '.join(subalias)),
'help': helps.get(name, ''),
'usage': subaction.format_usage().strip(),
'bare_usage': _format_usage_without_prefix(subaction),
'prog': parser.prog,
}
subdata['help'] = helps.get(name, '') % {'prog': parser.prog}

if subalias:
subdata['identifier'] = name
parse_parser(subaction, subdata, **kwargs)
Expand Down Expand Up @@ -117,10 +119,16 @@ def parse_parser(parser, data=None, **kwargs):
default = action.default
if action.default not in ['', None, True, False] and action.type in [None, str] and isinstance(action.default, str):
default = '"%s"' % default
# Don't use repr of types
typename = None
if action.type is not None:
typename = action.type.__name__

# fill in any formatters, like %(default)s
formatDict = dict(vars(action), prog=data.get('prog', ''), default=default)
formatDict['default'] = default
formatDict = dict(vars(action),
prog=data.get('prog', ''),
default=default,
type=typename)
helpStr = action.help or '' # Ensure we don't print None
try:
helpStr = helpStr % formatDict
Expand Down
98 changes: 78 additions & 20 deletions test/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_parse_description():


def test_parse_nested():
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(prog='test_parse_nested')
parser.add_argument('foo', default=False, help='foo help')
parser.add_argument('bar', default=False)

Expand All @@ -157,9 +157,10 @@ def test_parse_nested():
assert data['children'] == [
{
'name': 'install',
'prog': 'test_parse_nested',
'help': 'install help',
'usage': 'usage: py.test install [-h] [--upgrade] ref',
'bare_usage': 'py.test install [-h] [--upgrade] ref',
'usage': 'usage: test_parse_nested install [-h] [--upgrade] ref',
'bare_usage': 'test_parse_nested install [-h] [--upgrade] ref',
'action_groups': [
{
'title': 'Positional Arguments',
Expand Down Expand Up @@ -190,7 +191,7 @@ def test_parse_nested():

if six.PY3:
def test_parse_nested_with_alias():
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(prog='test_parse_nested_with_alias')
parser.add_argument('foo', default=False, help='foo help')
parser.add_argument('bar', default=False)

Expand All @@ -217,10 +218,11 @@ def test_parse_nested_with_alias():
assert data['children'] == [
{
'name': 'install (i)',
'prog': 'test_parse_nested_with_alias',
'identifier': 'install',
'help': 'install help',
'usage': 'usage: py.test install [-h] [--upgrade] ref',
'bare_usage': 'py.test install [-h] [--upgrade] ref',
'usage': 'usage: test_parse_nested_with_alias install [-h] [--upgrade] ref',
'bare_usage': 'test_parse_nested_with_alias install [-h] [--upgrade] ref',
'action_groups': [
{
'title': 'Positional Arguments',
Expand Down Expand Up @@ -249,7 +251,7 @@ def test_parse_nested_with_alias():
]

def test_aliased_traversal():
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(prog='test_aliased_traversal')

subparsers1 = parser.add_subparsers()
subparsers1.add_parser('level1', aliases=['l1'])
Expand All @@ -259,15 +261,16 @@ def test_aliased_traversal():
data2 = parser_navigate(data, 'level1')

assert(data2 == {
'bare_usage': 'py.test level1 [-h]',
'bare_usage': 'test_aliased_traversal level1 [-h]',
'help': '',
'usage': 'usage: py.test level1 [-h]',
'usage': 'usage: test_aliased_traversal level1 [-h]',
'name': 'level1 (l1)',
'prog': 'test_aliased_traversal',
'identifier': 'level1'})


def test_parse_nested_traversal():
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(prog='test_parse_nested_traversal')

subparsers1 = parser.add_subparsers()
subparser1 = subparsers1.add_parser('level1')
Expand Down Expand Up @@ -301,9 +304,10 @@ def test_parse_nested_traversal():
assert data2['children'] == [
{
'name': 'level3',
'prog': 'test_parse_nested_traversal level1 level2',
'help': '',
'usage': 'usage: py.test level1 level2 level3 [-h] foo bar',
'bare_usage': 'py.test level1 level2 level3 [-h] foo bar',
'usage': 'usage: test_parse_nested_traversal level1 level2 level3 [-h] foo bar',
'bare_usage': 'test_parse_nested_traversal level1 level2 level3 [-h] foo bar',
'action_groups': [
{
'title': 'Positional Arguments',
Expand All @@ -327,23 +331,51 @@ def test_parse_nested_traversal():
assert data == parser_navigate(data, '')


def test_fill_in_default_prog():
def test_fill_in_help_specifiers_incl_prog():
"""
Ensure that %(default)s and %(prog)s are getting properly filled in inside help=''
Ensure that format specifiers get filled in inside help.

Specifiers are %(prog)s and most keyword arguments to add_argument().
"""
parser = argparse.ArgumentParser(prog='test_fill_in_default_prog')
parser = argparse.ArgumentParser(prog='test_fill_in_help_specifiers_incl_prog')
parser.add_argument('bar', default='foo', help='%(prog)s (default: %(default)s)')
parser.add_argument('-p', type=int, metavar='passes',
help='number of %(metavar)s (%(type)s)')
data = parse_parser(parser)

assert data['action_groups'][0]['options'] == [
{
'default': '"foo"',
'name': ['bar'],
'help': 'test_fill_in_default_prog (default: "foo")'
'help': 'test_fill_in_help_specifiers_incl_prog (default: "foo")'
}
]
assert data['action_groups'][1]['options'] == [
{
'default': None,
'name': ['-p'],
'help': 'number of passes (int)'
}
]


def test_fill_in_usage_description_epilog():
"""
Ensure that %(prog)s gets filled in inside usage, description and epilog.
"""
parser = argparse.ArgumentParser(
prog='test_fill_in_usage_description_epilog',
usage='%(prog)s [options]',
description='Welcome to %(prog)s',
epilog='%(prog)s salutes you')
data = parse_parser(parser)

assert data['usage'] == 'usage: test_fill_in_usage_description_epilog [options]'
assert data['bare_usage'] == 'test_fill_in_usage_description_epilog [options]'
assert data['description'] == 'Welcome to test_fill_in_usage_description_epilog'
assert data['epilog'] == 'test_fill_in_usage_description_epilog salutes you'


def test_string_quoting():
"""
If an optional argument has a string type and a default, then the default should be in quotes.
Expand Down Expand Up @@ -396,9 +428,14 @@ def test_action_groups_with_subcommands():
"""
parser = argparse.ArgumentParser('foo')
subparsers = parser.add_subparsers()
parserA = subparsers.add_parser('A', help='A subparser')
parserA = subparsers.add_parser('A', help='A subparser for %(prog)s',
usage='%(prog)s [options] baz',
description='Perform action a from'
' within %(prog)s.')
parserA.add_argument('baz', type=int, help='An integer')
parserB = subparsers.add_parser('B', help='B subparser')
parserB = subparsers.add_parser('B', help='B subparser',
epilog='Action b is expensive when'
' performed by %(prog)s.')
parserB.add_argument('--barg', choices='XYZ', help='A list of choices')

parser.add_argument('--foo', help='foo help')
Expand All @@ -420,6 +457,27 @@ def test_action_groups_with_subcommands():
]

assert data['children'] == [
{'usage': 'usage: foo A [-h] baz', 'action_groups': [{'options': [{'default': None, 'name': ['baz'], 'help': 'An integer'}], 'description': None, 'title': 'Positional Arguments'}], 'bare_usage': 'foo A [-h] baz', 'name': 'A', 'help': 'A subparser'},
{'usage': 'usage: foo B [-h] [--barg {X,Y,Z}]', 'action_groups': [{'options': [{'default': None, 'choices': 'XYZ', 'name': ['--barg'], 'help': 'A list of choices'}], 'description': None, 'title': 'Named Arguments'}], 'bare_usage': 'foo B [-h] [--barg {X,Y,Z}]', 'name': 'B', 'help': 'B subparser'}
{'usage': 'usage: foo A [options] baz',
'action_groups': [{'options': [{'default': None,
'name': ['baz'],
'help': 'An integer'}],
'description': None,
'title': 'Positional Arguments'}],
'bare_usage': 'foo A [options] baz',
'description': 'Perform action a from within foo.',
'name': 'A',
'prog': 'foo',
'help': 'A subparser for foo'},
{'usage': 'usage: foo B [-h] [--barg {X,Y,Z}]',
'action_groups': [{'options': [{'default': None,
'choices': 'XYZ',
'name': ['--barg'],
'help': 'A list of choices'}],
'description': None,
'title': 'Named Arguments'}],
'bare_usage': 'foo B [-h] [--barg {X,Y,Z}]',
'epilog': 'Action b is expensive when performed by foo.',
'name': 'B',
'prog': 'foo',
'help': 'B subparser'}
]