Skip to content
Commits on Source (7)
......@@ -17,7 +17,7 @@ script:
fi
deploy:
provider: pypi
distributions: 'release sdist bdist_wheel'
distributions: 'sdist bdist_wheel'
on:
tags: true
python: 3.6
......
sphinxcontrib-autoprogram (0.1.5-1) unstable; urgency=medium
* Team upload.
* New upstream version
* Standards-Version: 4.3.0; no changes needed.
-- Michael R. Crusoe <michael.crusoe@gmail.com> Wed, 23 Jan 2019 13:36:47 -0800
sphinxcontrib-autoprogram (0.1.4-2) unstable; urgency=medium
[ Chris Lamb ]
......
......@@ -10,11 +10,13 @@ Build-Depends: debhelper (>= 11~),
dh-python,
python,
python-setuptools,
python-six,
python-sphinx,
python3,
python3-setuptools,
python3-sphinx
Standards-Version: 4.1.4
python3-sphinx,
python3-six
Standards-Version: 4.3.0
Vcs-Browser: https://salsa.debian.org/med-team/sphinxcontrib-autoprogram
Vcs-Git: https://salsa.debian.org/med-team/sphinxcontrib-autoprogram.git
Homepage: https://pythonhosted.org/sphinxcontrib-autoprogram/
......
Description: Make the build reproducible
Author: Chris Lamb <lamby@debian.org>
Last-Update: 2018-04-20
--- sphinxcontrib-autoprogram-0.1.4.orig/setup.cfg
+++ sphinxcontrib-autoprogram-0.1.4/setup.cfg
@@ -1,6 +1,6 @@
[egg_info]
tag_build = dev
-tag_date = true
+tag_date = false
[bdist_wheel]
universal = 1
reproducible-build.diff
......@@ -4,3 +4,7 @@ export PYBUILD_DESTDIR_python3=debian/python3-sphinxcontrib.autoprogram
%:
dh $@ --with=python2,python3 --buildsystem=pybuild
override_dh_auto_install:
dh_auto_install
find debian -name "*.pth" -delete
Changelog
=========
Version 0.1.5
-------------
Released on May 15, 2018.
- New ``:groups:`` option to render argument groups. [by Lukas Atkinson]
Version 0.1.4
-------------
......
import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='An integer for the accumulator.')
calculator_opts = parser.add_argument_group('Calculator Options')
calculator_opts.add_argument(
'-i', '--identity', type=int, default=0,
help='the default result for no arguments ' '(default: 0)')
calculator_opts.add_argument(
'--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='Sum the integers (default: find the max).')
if __name__ == '__main__':
args = parser.parse_args()
print(args.accumulate(args.integers))
......@@ -62,7 +62,7 @@ That's it. It will be rendered as:
:prog: cli.py
If there are subcommands (subparsers), they are rendered to subsections.
For example, givem the following Python CLI program (say it's
For example, given the following Python CLI program (say it's
:file:`subcmds.py`):
.. include:: subcmds.py
......@@ -78,6 +78,25 @@ The above reStructuredText will render:
.. autoprogram:: subcmds:parser
:prog: subcmds.py
If there are argument groups, they can optionally be rendered as subsections,
just like subcommands.
For example:
.. include:: cli_with_groups.py
:code:
.. code-block:: rst
.. autoprogram:: cli_with_groups:parser
:prog: cli_with_groups.py
:groups:
The above reStructuredText Text will render:
.. autoprogram:: cli_with_groups:parser
:prog: cli_with_groups.py
:groups:
.. rst:directive:: .. autoprogram:: module:parser
It takes an import name of the parser object. For example, if ``xyz``
......@@ -108,23 +127,34 @@ The above reStructuredText will render:
Additional Options for :rst:dir:`.. autoprogram::`
--------------------------------------------------
.. versionadded:: 0.1.3
``:groups:``
Render argument groups as subsections.
.. versionadded:: 0.1.5
``:maxdepth: ##``
Only show subcommands to a depth of ``##``.
.. versionadded:: 0.1.3
``:no_usage_codeblock:``
Don't put the usage text in a :rst:dir:`.. codeblock:: console` directive.
.. versionadded:: 0.1.3
``:start_command: subcommand``
Render document for the given subcommand. ``subcommand`` can be a space
separated list to render a sub-sub-...-command.
.. versionadded:: 0.1.3
``:strip_usage:``
Removes all but the last word in the usage string before the first option,
replaces it with '...', and removes an amount of whitespace to realign
subsequent lines.
.. versionadded:: 0.1.3
Author and license
------------------
......
[egg_info]
tag_build = dev
tag_date = true
[bdist_wheel]
universal = 1
[aliases]
release = egg_info -RDb ''
......@@ -7,7 +7,7 @@ from setuptools import setup, find_packages
# Do not change the variable name. It's parsed by doc/conf.py script.
version = '0.1.4'
version = '0.1.5'
requires = ['Sphinx >= 1.2', 'six']
......
......@@ -41,46 +41,18 @@ def get_subparser_action(parser):
return a
def scan_programs(parser, command=[], maxdepth=0, depth=0):
def scan_programs(parser, command=[], maxdepth=0, depth=0, groups=False):
if maxdepth and depth >= maxdepth:
return
options = []
for arg in parser._actions:
if not (arg.option_strings or
isinstance(arg, argparse._SubParsersAction)):
name = (arg.metavar or arg.dest).lower()
desc = (arg.help or '') % {'default': arg.default}
options.append(([name], desc))
for arg in parser._actions:
if arg.option_strings and arg.help is not argparse.SUPPRESS:
if isinstance(arg, (argparse._StoreAction,
argparse._AppendAction)):
if arg.choices is None:
metavar = arg.metavar or arg.dest
if isinstance(metavar, tuple):
names = [
'{0} <{1}>'.format(
option_string, '> <'.join(metavar).lower()
)
for option_string in arg.option_strings
]
else:
names = [
'{0} <{1}>'.format(option_string, metavar.lower())
for option_string in arg.option_strings
]
if groups:
yield command, [], parser
for group in parser._action_groups:
options = list(scan_options(group._group_actions))
if options:
yield command, options, group
else:
choices = '{0}'.format(','.join(arg.choices))
names = ['{0} {{{1}}}'.format(option_string, choices)
for option_string in arg.option_strings]
else:
names = list(arg.option_strings)
desc = (arg.help or '') % {'default': arg.default}
options.append((names, desc))
options = list(scan_options(parser._actions))
yield command, options, parser
if parser._subparsers:
......@@ -103,6 +75,45 @@ def scan_programs(parser, command=[], maxdepth=0, depth=0):
yield program
def scan_options(actions):
for arg in actions:
if not (arg.option_strings or
isinstance(arg, argparse._SubParsersAction)):
yield format_positional_argument(arg)
for arg in actions:
if arg.option_strings and arg.help is not argparse.SUPPRESS:
yield format_option(arg)
def format_positional_argument(arg):
desc = (arg.help or '') % {'default': arg.default}
name = (arg.metavar or arg.dest).lower()
return [name], desc
def format_option(arg):
desc = (arg.help or '') % {'default': arg.default}
if not isinstance(arg, (argparse._StoreAction, argparse._AppendAction)):
names = list(arg.option_strings)
return names, desc
if arg.choices is not None:
value = '{{{0}}}'.format(','.join(arg.choices))
else:
metavar = arg.metavar or arg.dest
if not isinstance(metavar, tuple):
metavar = metavar,
value = '<{0}>'.format('> <'.join(metavar).lower())
names = ['{0} {1}'.format(option_string, value)
for option_string in arg.option_strings]
return names, desc
def import_object(import_name):
module_name, expr = import_name.split(':', 1)
try:
......@@ -148,6 +159,7 @@ class AutoprogramDirective(Directive):
'start_command': unchanged,
'strip_usage': unchanged,
'no_usage_codeblock': unchanged,
'groups': unchanged,
}
def make_rst(self):
......@@ -160,6 +172,8 @@ class AutoprogramDirective(Directive):
start_command = self.options.get('start_command', '').split(' ')
strip_usage = 'strip_usage' in self.options
usage_codeblock = 'no_usage_codeblock' not in self.options
maxdepth = int(self.options.get('maxdepth', 0))
groups = 'groups' in self.options
if start_command[0] == '':
start_command.pop(0)
......@@ -183,16 +197,51 @@ class AutoprogramDirective(Directive):
if prog and parser.prog.startswith(original_prog):
parser.prog = parser.prog.replace(original_prog, prog, 1)
for commands, options, cmd_parser in scan_programs(
parser, maxdepth=int(self.options.get('maxdepth', 0))
for commands, options, group_or_parser in scan_programs(
parser, maxdepth=maxdepth, groups=groups
):
if isinstance(group_or_parser, argparse._ArgumentGroup):
title = group_or_parser.title
description = group_or_parser.description
usage = None
epilog = None
is_subgroup = True
is_program = False
else:
cmd_parser = group_or_parser
if prog and cmd_parser.prog.startswith(original_prog):
cmd_parser.prog = cmd_parser.prog.replace(
original_prog, prog, 1)
title = cmd_parser.prog.rstrip()
description = cmd_parser.description
usage = cmd_parser.format_usage()
epilog = cmd_parser.epilog
is_subgroup = bool(commands)
is_program = True
for line in render_rst(title, options,
is_program=is_program,
is_subgroup=is_subgroup,
description=description,
usage=usage,
usage_strip=strip_usage,
usage_codeblock=usage_codeblock,
epilog=epilog):
yield line
def run(self):
node = nodes.section()
node.document = self.state.document
result = ViewList()
for line in self.make_rst():
result.append(line, '<autoprogram>')
nested_parse_with_titles(self.state, result, node)
return node.children
if strip_usage:
def render_rst(title, options, is_program, is_subgroup, description,
usage, usage_strip, usage_codeblock, epilog):
if usage_strip:
to_strip = title.rsplit(' ', 1)[0]
len_to_strip = len(to_strip) - 4
usage_lines = usage.splitlines()
......@@ -204,16 +253,22 @@ class AutoprogramDirective(Directive):
])
yield ''
if is_program:
yield '.. program:: ' + title
yield ''
yield title
yield ('!' if commands else '?') * len(title)
yield ('!' if is_subgroup else '?') * len(title)
yield ''
for line in (cmd_parser.description or '').splitlines():
for line in (description or '').splitlines():
yield line
yield ''
if usage_codeblock:
if usage is None:
pass
elif usage_codeblock:
yield '.. code-block:: console'
yield ''
for usage_line in usage.splitlines():
......@@ -228,18 +283,9 @@ class AutoprogramDirective(Directive):
yield ''
yield ' ' + help_.replace('\n', ' \n')
yield ''
yield ''
for line in (cmd_parser.epilog or '').splitlines():
yield line or ''
def run(self):
node = nodes.section()
node.document = self.state.document
result = ViewList()
for line in self.make_rst():
result.append(line, '<autoprogram>')
nested_parse_with_titles(self.state, result, node)
return node.children
for line in (epilog or '').splitlines():
yield line or ''
def patch_option_role_to_allow_argument_form():
......@@ -350,6 +396,53 @@ class ScannerTestCase(unittest.TestCase):
self.assertEqual((['n'], 'An integer for the accumulator.'),
options[0])
def test_argument_groups(self):
parser = argparse.ArgumentParser(description='This is a program.')
parser.add_argument('-v', action='store_true',
help='A global argument')
plain_group = parser.add_argument_group('Plain Options',
description='This is a group.')
plain_group.add_argument('--plain', action='store_true',
help='A plain argument.')
fancy_group = parser.add_argument_group('Fancy Options',
description='Another group.')
fancy_group.add_argument('fancy', type=int, help='Set the fancyness')
sections = list(scan_programs(parser, groups=True))
self.assertEqual(4, len(sections))
# section: unnamed
program, options, cmd_parser = sections[0]
self.assertEqual([], program)
self.assertEqual('This is a program.', cmd_parser.description)
self.assertEqual(0, len(options))
# section: default optionals
program, options, group = sections[1]
self.assertEqual([], program)
self.assertEqual('optional arguments', group.title)
self.assertEqual(None, group.description)
self.assertEqual(2, len(options))
self.assertEqual((['-h', '--help'], 'show this help message and exit'),
options[0])
self.assertEqual((['-v'], 'A global argument'), options[1])
# section: Plain Options
program, options, group = sections[2]
self.assertEqual([], program)
self.assertEqual('Plain Options', group.title)
self.assertEqual('This is a group.', group.description)
self.assertEqual(1, len(options))
self.assertEqual((['--plain'], 'A plain argument.'), options[0])
# section: Fancy Options
program, options, group = sections[3]
self.assertEqual([], program)
self.assertEqual('Fancy Options', group.title)
self.assertEqual('Another group.', group.description)
self.assertEqual(1, len(options))
self.assertEqual((['fancy'], 'Set the fancyness'), options[0])
def test_choices(self):
parser = argparse.ArgumentParser()
parser.add_argument("--awesomeness", choices=["meh", "awesome"])
......