From 0ef4efb946a168f2212393a227000898b0a99287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Sun, 23 Aug 2020 12:50:06 +0200 Subject: [PATCH 1/3] Cleanup project --- .travis.yml | 32 ++++++---- MANIFEST.in | 1 + README.md | 7 +-- docs/conf.py | 6 +- docs/contrib.rst | 2 +- docs/markdown.rst | 2 - requirements_dev.txt | 4 -- setup.py | 39 ++++++++---- sphinxarg/ext.py | 115 ++++++++++++++++++++++-------------- sphinxarg/markdown.py | 48 +++++++++------ sphinxarg/parser.py | 25 +++++--- test/sample.py | 57 ++++++++++++------ test/test_parser.py | 134 ++++++++++++++++++++++++++++++++++-------- tox.ini | 26 +++++++- 14 files changed, 348 insertions(+), 150 deletions(-) create mode 100644 MANIFEST.in delete mode 100644 requirements_dev.txt diff --git a/.travis.yml b/.travis.yml index 8dd9def..93d4c25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,24 @@ language: python -python: - - "2.7" - - "3.5" - - "3.6" +os: linux +dist: focal install: - - pip install . - - pip install flake8 - -script: - - py.test - - flake8 . --ignore=E501,E722,E741,W605 --exclude=docs/conf.py + - travis_retry pip install -U tox-travis +matrix: + include: + - python: 2.7 + env: TOXENV=py27 + - python: 3.3 + env: TOXENV=py33 + - python: 3.4 + env: TOXENV=py34 + - python: 3.5 + env: TOXENV=py35 + - python: 3.6 + env: TOXENV=py36 + - python: 3.7 + env: TOXENV=py36 + - python: 3.8 + env: TOXENV=py38 + - python: 3.7 + env: TOXENV=flake8 +script: tox diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..4cc50bb --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +exclude test \ No newline at end of file diff --git a/README.md b/README.md index 70883d0..031e783 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ -[![Build Status](https://travis-ci.org/ribozz/sphinx-argparse.svg?branch=master)](https://travis-ci.org/ribozz/sphinx-argparse) +# sphinx-argparse + +[![Build Status](https://travis-ci.org/alex-rudakov/sphinx-argparse.svg?branch=master)](https://travis-ci.org/alex-rudakov/sphinx-argparse) [![Documentation Status](https://readthedocs.org/projects/sphinx-argparse/badge/?version=stable)](http://sphinx-argparse.readthedocs.org/) [![PyPI version](https://badge.fury.io/py/sphinx-argparse.svg)](https://badge.fury.io/py/sphinx-argparse) [![Install with conda](https://anaconda.org/conda-forge/sphinx-argparse/badges/installer/conda.svg)](https://github.com/conda-forge/sphinx-argparse-feedstock) ![Conda downloads](https://anaconda.org/conda-forge/sphinx-argparse/badges/downloads.svg) -sphinx-argparse -=============== - A sphinx extension that automatically documents argparse commands and options. For installation and usage details see the [documentation](http://sphinx-argparse.readthedocs.org/en/latest/). The changelog is also [found there](http://sphinx-argparse.readthedocs.org/en/latest/changelog.html). diff --git a/docs/conf.py b/docs/conf.py index 30a85a6..b0ab5d3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import datetime +import os # If extensions (or extra_modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -52,7 +53,8 @@ # General information about the project. project = u'sphinx-argparse' -copyright = u'2017, Alex Rudakov, Devon Ryan and contributors' +copyright = u'2017-%d, Alex Rudakov, Devon Ryan and contributors' % ( + datetime.datetime.now().year) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/contrib.rst b/docs/contrib.rst index 4f72987..37a3c72 100644 --- a/docs/contrib.rst +++ b/docs/contrib.rst @@ -13,4 +13,4 @@ Contributions are gratefully accepted through `github =1.2.0 -CommonMark>=0.5.6 diff --git a/setup.py b/setup.py index 0e2e305..88fe70f 100644 --- a/setup.py +++ b/setup.py @@ -1,28 +1,42 @@ from setuptools import setup +MARKDOWN_REQUIREMENTS = ['CommonMark>=0.5.6'] +LINT_REQUIREMENTS = ['flake8'] +TEST_REQUIREMENTS = ['pytest', 'tox'] +DEV_REQUIREMENTS = ['sphinx_rtd_theme==0.4.3'] + \ + TEST_REQUIREMENTS + \ + LINT_REQUIREMENTS + \ + MARKDOWN_REQUIREMENTS -def getVersion(): - f = open("sphinxarg/__init__.py") + +def get_version(): + f = open('sphinxarg/__init__.py') _ = f.read() - ver = _.split("'")[1] + ver = _.split('\'')[1] f.close() return ver +def get_long_description(): + f = open('README.md') + long_desc = f.read() + f.close() + return long_desc + + setup( name='sphinx-argparse', - version=getVersion(), + version=get_version(), packages=[ 'sphinxarg', ], - url='https://github.com/ribozz/sphinx-argparse', + url='https://github.com/alex-rudakov/sphinx-argparse', license='MIT', author='Aleksandr Rudakov and Devon Ryan', author_email='ribozz@gmail.com', - description='A sphinx extension that automatically documents argparse commands and options', - long_description="""A sphinx extension that automatically documents argparse commands and options. - -For installation and usage details, see the `documentation `_.""", + description='A sphinx extension that automatically documents' + + ' argparse commands and options', + long_description=get_long_description(), classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', @@ -31,6 +45,7 @@ def getVersion(): 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Topic :: Documentation :: Sphinx', 'Topic :: Software Development :: Documentation' ], @@ -38,7 +53,9 @@ def getVersion(): 'sphinx>=1.2.0' ], extras_require={ - 'dev': ['pytest', 'sphinx_rtd_theme'], - 'markdown': ['CommonMark>=0.5.6'] + 'dev': DEV_REQUIREMENTS, + 'lint': LINT_REQUIREMENTS, + 'test': TEST_REQUIREMENTS, + 'markdown': MARKDOWN_REQUIREMENTS } ) diff --git a/sphinxarg/ext.py b/sphinxarg/ext.py index acd4eb5..e674d77 100644 --- a/sphinxarg/ext.py +++ b/sphinxarg/ext.py @@ -46,26 +46,29 @@ def map_nested_definitions(nested_content): for _ in subitem[idx]: if isinstance(_, nodes.definition_list): subContent.append(_) - definitions[term] = (classifier, subitem[idx], subContent) + definitions[term] = (classifier, subitem[idx], + subContent) return definitions -def renderList(l, markDownHelp, settings=None): +def renderList(sections, markDownHelp, settings=None): """ - Given a list of reStructuredText or MarkDown sections, return a docutils node list + Given a list of reStructuredText or MarkDown sections, + return a docutils node list """ - if len(l) == 0: + if len(sections) == 0: return [] if markDownHelp: from sphinxarg.markdown import parseMarkDownBlock - return parseMarkDownBlock('\n\n'.join(l) + '\n') + return parseMarkDownBlock('\n\n'.join(sections) + '\n') else: all_children = [] - for element in l: + for element in sections: if isinstance(element, str): if settings is None: - settings = OptionParser(components=(Parser,)).get_default_values() + settings = OptionParser( + components=(Parser,)).get_default_values() document = new_document(None, settings) Parser().parse(element + '\n', document) all_children += document.children @@ -75,23 +78,27 @@ def renderList(l, markDownHelp, settings=None): return all_children -def print_action_groups(data, nested_content, markDownHelp=False, settings=None): +def print_action_groups(data, nested_content, + markDownHelp=False, settings=None): """ - Process all 'action groups', which are also include 'Options' and 'Required - arguments'. A list of nodes is returned. + Process all 'action groups', which are also include + 'Options' and 'Required arguments'. A list of nodes is returned. """ definitions = map_nested_definitions(nested_content) nodes_list = [] if 'action_groups' in data: for action_group in data['action_groups']: - # Every action group is comprised of a section, holding a title, the description, and the option group (members) + # Every action group is comprised of a section, holding a title, + # the description, and the option group (members) section = nodes.section(ids=[action_group['title']]) - section += nodes.title(action_group['title'], action_group['title']) + section += nodes.title(action_group['title'], + action_group['title']) desc = [] if action_group['description']: desc.append(action_group['description']) - # Replace/append/prepend content to the description according to nested content + # Replace/append/prepend content to the description + # according to nested content subContent = [] if action_group['title'] in definitions: classifier, s, subContent = definitions[action_group['title']] @@ -129,16 +136,19 @@ def print_action_groups(data, nested_content, markDownHelp=False, settings=None) # Build the help text arg = [] if 'choices' in entry: - arg.append('Possible choices: {}\n'.format(", ".join([str(c) for c in entry['choices']]))) + arg.append('Possible choices: {}\n'.format( + ", ".join([str(c) for c in entry['choices']]))) if 'help' in entry: arg.append(entry['help']) - if entry['default'] is not None and entry['default'] not in ['"==SUPPRESS=="', '==SUPPRESS==']: + if entry['default'] is not None and entry['default'] \ + not in ['"==SUPPRESS=="', '==SUPPRESS==']: if entry['default'] == '': arg.append('Default: ""') else: arg.append('Default: {}'.format(entry['default'])) - # Handle nested content, the term used in the dict has the comma removed for simplicity + # Handle nested content, the term used in the dict + # has the comma removed for simplicity desc = arg term = ' '.join(entry['name']) if term in localDefinitions: @@ -151,9 +161,13 @@ def print_action_groups(data, nested_content, markDownHelp=False, settings=None) desc.insert(0, s) term = ', '.join(entry['name']) - n = nodes.option_list_item('', - nodes.option_group('', nodes.option_string(text=term)), - nodes.description('', *renderList(desc, markDownHelp, settings))) + n = nodes.option_list_item( + '', + nodes.option_group('', nodes.option_string(text=term)), + nodes.description('', + *renderList(desc, markDownHelp, + settings)) + ) items.append(n) section += nodes.option_list('', *items) @@ -203,11 +217,15 @@ def print_subcommands(data, nested_content, markDownHelp=False, settings=None): for element in renderList(desc, markDownHelp): sec += element sec += nodes.literal_block(text=child['bare_usage']) - for x in print_action_groups(child, nested_content + subContent, markDownHelp, + for x in print_action_groups(child, + nested_content + subContent, + markDownHelp, settings=settings): sec += x - for x in print_subcommands(child, nested_content + subContent, markDownHelp, + for x in print_subcommands(child, + nested_content + subContent, + markDownHelp, settings=settings): sec += x @@ -224,10 +242,11 @@ def print_subcommands(data, nested_content, markDownHelp=False, settings=None): def ensureUniqueIDs(items): """ If action groups are repeated, then links in the table of contents will - just go to the first of the repeats. This may not be desirable, particularly - in the case of subcommands where the option groups have different members. - This function updates the title IDs by adding _repeatX, where X is a number - so that the links are then unique. + just go to the first of the repeats. This may not be desirable, + particularly in the case of subcommands where the option groups have + different members. + This function updates the title IDs by adding _repeatX, where X is + a number so that the links are then unique. """ s = set() for item in items: @@ -251,9 +270,10 @@ class ArgParseDirective(Directive): option_spec = dict(module=unchanged, func=unchanged, ref=unchanged, prog=unchanged, path=unchanged, nodefault=flag, nodefaultconst=flag, filename=unchanged, - manpage=unchanged, nosubcommands=unchanged, passparser=flag, - noepilog=unchanged, nodescription=unchanged, - markdown=flag, markdownhelp=flag) + manpage=unchanged, nosubcommands=unchanged, + passparser=flag, noepilog=unchanged, + nodescription=unchanged, markdown=flag, + markdownhelp=flag) def _construct_manpage_specific_structure(self, parser_info): """ @@ -311,7 +331,8 @@ def _construct_manpage_specific_structure(self, parser_info): if 'options' in parser_info: options_section += nodes.paragraph() options_section += nodes.subtitle(text=action_group['title']) - options_section += self._format_optional_arguments(action_group) + options_section += self._format_optional_arguments( + action_group) # NOTE: we cannot generate NAME ourselves. It is generated by # docutils.writers.manpage @@ -374,8 +395,8 @@ def _format_optional_arguments(self, parser_info): opt_items = [] for name in opt['name']: option_declaration = [nodes.option_string(text=name)] - if opt['default'] is not None \ - and opt['default'] not in ['"==SUPPRESS=="', '==SUPPRESS==']: + if opt['default'] is not None and opt['default'] not in \ + ['"==SUPPRESS=="', '==SUPPRESS==']: option_declaration += nodes.option_argument( '', text='=' + str(opt['default'])) names.append(nodes.option('', *option_declaration)) @@ -435,15 +456,17 @@ def run(self): attr_name = self.options['func'] func = mod[attr_name] else: - raise self.error( - ':module: and :func: should be specified, or :ref:, or :filename: and :func:') + raise self.error(':module: and :func: should be specified' + ', or :ref:, or :filename: and :func:') - # Skip this if we're dealing with a local file, since it obviously can't be imported + # Skip this if we're dealing with a local file, + # since it obviously can't be imported if 'filename' not in self.options: try: mod = __import__(module_name, globals(), locals(), [attr_name]) - except: - raise self.error('Failed to import "%s" from "%s".\n%s' % (attr_name, module_name, sys.exc_info()[1])) + except Exception: + raise self.error('Failed to import "%s" from "%s".\n%s' % ( + attr_name, module_name, sys.exc_info()[1])) if not hasattr(mod, attr_name): raise self.error(( @@ -465,7 +488,9 @@ def run(self): if 'prog' in self.options: parser.prog = self.options['prog'] result = parse_parser( - parser, skip_default_values='nodefault' in self.options, skip_default_const_values='nodefaultconst' in self.options) + parser, + skip_default_values='nodefault' in self.options, + skip_default_const_values='nodefaultconst' in self.options) result = parser_navigate(result, path) if 'manpage' in self.options: return self._construct_manpage_specific_structure(result) @@ -492,17 +517,21 @@ def run(self): if markDownHelp: items.extend(renderList([result['description']], True)) else: - items.append(self._nested_parse_paragraph(result['description'])) + items.append( + self._nested_parse_paragraph(result['description'])) items.append(nodes.literal_block(text=result['usage'])) - items.extend(print_action_groups(result, nested_content, markDownHelp, - settings=self.state.document.settings)) + items.extend( + print_action_groups(result, nested_content, markDownHelp, + settings=self.state.document.settings)) if 'nosubcommands' not in self.options: - items.extend(print_subcommands(result, nested_content, markDownHelp, - settings=self.state.document.settings)) + items.extend( + print_subcommands(result, nested_content, markDownHelp, + settings=self.state.document.settings)) if 'epilog' in result and 'noepilog' not in self.options: items.append(self._nested_parse_paragraph(result['epilog'])) - # Traverse the returned nodes, modifying the title IDs as necessary to avoid repeats + # Traverse the returned nodes, modifying the title IDs + # as necessary to avoid repeats ensureUniqueIDs(items) return items diff --git a/sphinxarg/markdown.py b/sphinxarg/markdown.py index 4e5be42..56ce355 100644 --- a/sphinxarg/markdown.py +++ b/sphinxarg/markdown.py @@ -1,3 +1,5 @@ +import sys + try: from commonmark import Parser except ImportError: @@ -12,11 +14,13 @@ def customWalker(node, space=''): """ - A convenience function to ease debugging. It will print the node structure that's returned from CommonMark + A convenience function to ease debugging. + It will print the node structure that's returned from CommonMark. The usage would be something like: - >>> content = Parser().parse('Some big text block\n===================\n\nwith content\n') + >>> content = Parser().parse( + ... 'Some big text block\n===================\n\nwith content\n') >>> customWalker(content) document heading @@ -29,13 +33,13 @@ def customWalker(node, space=''): txt = '' try: txt = node.literal - except: + except Exception: pass if txt is None or txt == '': - print('{}{}'.format(space, node.t)) + sys.stdout.write('{}{}\n'.format(space, node.t)) else: - print('{}{}\t{}'.format(space, node.t, txt)) + sys.stdout.write('{}{}\t{}\n'.format(space, node.t, txt)) cur = node.first_child if cur: @@ -82,7 +86,8 @@ def softbreak(node): def reference(node): """ - A hyperlink. Note that alt text doesn't work, since there's no apparent way to do that in docutils + A hyperlink. Note that alt text doesn't work, since there's + no apparent way to do that in docutils """ o = nodes.reference() o['refuri'] = node.destination @@ -120,10 +125,10 @@ def literal(node): rendered = [] try: if node.info is not None: - l = Lexer(node.literal, node.info, tokennames="long") - for _ in l: + lexer = Lexer(node.literal, node.info, tokennames="long") + for _ in lexer: rendered.append(node.inline(classes=_[0], text=_[1])) - except: + except Exception: pass classes = ['code'] @@ -148,10 +153,10 @@ def literal_block(node): rendered = [] try: if node.info is not None: - l = Lexer(node.literal, node.info, tokennames="long") - for _ in l: + lexer = Lexer(node.literal, node.info, tokennames="long") + for _ in lexer: rendered.append(node.inline(classes=_[0], text=_[1])) - except: + except Exception: pass classes = ['code'] @@ -252,7 +257,9 @@ def listNode(node): if node.list_data['type'] == u'bullet': o = nodes.bullet_list(bullet=node.list_data['bullet_char']) else: - o = nodes.enumerated_list(suffix=node.list_data['delimiter'], enumtype='arabic', start=node.list_data['start']) + o = nodes.enumerated_list(suffix=node.list_data['delimiter'], + enumtype='arabic', + start=node.list_data['start']) for n in MarkDown(node): o += n return o @@ -260,7 +267,8 @@ def listNode(node): def MarkDown(node): """ - Returns a list of nodes, containing CommonMark nodes converted to docutils nodes + Returns a list of nodes, containing CommonMark nodes + converted to docutils nodes. """ cur = node.first_child @@ -303,7 +311,8 @@ def MarkDown(node): elif t == 'MDsection': output.append(section(cur)) else: - print('Received unhandled type: {}. Full print of node:'.format(t)) + msg_schema = 'Received unhandled type: {}. Full print of node:\n' + sys.stdout.write(msg_schema.format(t)) cur.pretty() cur = cur.nxt @@ -329,8 +338,10 @@ def nestSections(block, level=1): """ Sections aren't handled by CommonMark at the moment. This function adds sections to a block of nodes. - 'title' nodes with an assigned level below 'level' will be put in a child section. - If there are no child nodes with titles of level 'level' then nothing is done + 'title' nodes with an assigned level below 'level' + will be put in a child section. + If there are no child nodes with titles of level 'level' + then nothing is done. """ cur = block.first_child if cur is not None: @@ -394,7 +405,8 @@ def parseMarkDownBlock(text): """ Parses a block of text, returning a list of docutils nodes - >>> parseMarkdownBlock("Some\n====\n\nblock of text\n\nHeader\n======\n\nblah\n") + >>> parseMarkdownBlock( + ... "Some\n====\n\nblock of text\n\nHeader\n======\n\nblah\n") [] """ block = Parser().parse(text) diff --git a/sphinxarg/parser.py b/sphinxarg/parser.py index 2b2c79f..537d95d 100644 --- a/sphinxarg/parser.py +++ b/sphinxarg/parser.py @@ -21,7 +21,8 @@ def parser_navigate(parser_result, path, current_path=None): next_hop = path.pop(0) for child in parser_result['children']: # identifer is only used for aliased subcommands - identifier = child['identifier'] if 'identifier' in child else child['name'] + identifier = child['identifier'] if 'identifier' in child \ + else child['name'] if identifier == next_hop: current_path.append(next_hop) return parser_navigate(child, path, current_path) @@ -85,7 +86,8 @@ def parse_parser(parser, data=None, **kwargs): subalias = subsection_alias[subaction] subaction.prog = '%s %s' % (parser.prog, name) subdata = { - 'name': name if not subalias else '%s (%s)' % (name, ', '.join(subalias)), + '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), @@ -96,10 +98,12 @@ def parse_parser(parser, data=None, **kwargs): data.setdefault('children', []).append(subdata) show_defaults = True - if 'skip_default_values' in kwargs and kwargs['skip_default_values'] is True: + if 'skip_default_values' in kwargs and \ + kwargs['skip_default_values'] is True: show_defaults = False show_defaults_const = show_defaults - if 'skip_default_const_values' in kwargs and kwargs['skip_default_const_values'] is True: + if 'skip_default_const_values' in kwargs and \ + kwargs['skip_default_const_values'] is True: show_defaults_const = False # argparse stores the different groups as a list in parser._action_groups @@ -115,16 +119,20 @@ def parse_parser(parser, data=None, **kwargs): # Quote default values for string/None types default = action.default - if action.default not in ['', None, True, False] and action.type in [None, str] and isinstance(action.default, str): + if action.default not in ['', None, True, False] and \ + action.type in [None, str] and \ + isinstance(action.default, str): default = '"%s"' % default # fill in any formatters, like %(default)s - formatDict = dict(vars(action), prog=data.get('prog', ''), default=default) + formatDict = dict(vars(action), + prog=data.get('prog', ''), + default=default) formatDict['default'] = default helpStr = action.help or '' # Ensure we don't print None try: helpStr = helpStr % formatDict - except: + except Exception: pass # Options have the option_strings set, positional arguments don't @@ -139,9 +147,10 @@ def parse_parser(parser, data=None, **kwargs): continue if isinstance(action, _StoreConstAction): + _default = default if show_defaults_const else '==SUPPRESS==' option = { 'name': name, - 'default': default if show_defaults_const else '==SUPPRESS==', + 'default': _default, 'help': helpStr } else: diff --git a/test/sample.py b/test/sample.py index 1b41fb5..ed9447a 100644 --- a/test/sample.py +++ b/test/sample.py @@ -4,28 +4,47 @@ subparsers = parser.add_subparsers() -my_command1 = subparsers.add_parser('apply', help='Execute provision script, collect all resources and apply them.') +my_command1 = subparsers.add_parser( + 'apply', help='Execute provision script, collect all resources' + ' and apply them.') -my_command1.add_argument('path', help='Specify path to provision script. provision.py in current' - 'directory by default. Also may include url.', default='provision.py') -my_command1.add_argument('-r', '--rollback', action='store_true', default=False, help='If specified will rollback all' - 'resources applied.') -my_command1.add_argument('--tree', action='store_true', default=False, help='Print resource tree') -my_command1.add_argument('--dry', action='store_true', default=False, help='Just print changes list') -my_command1.add_argument('--force', action='store_true', default=False, help='Apply without confirmation') -my_command1.add_argument('default_string', default='I am a default', help='Ensure variables are filled in %(prog)s (default %(default)s)') +my_command1.add_argument( + 'path', default='provision.py', + help='Specify path to provision script. provision.py in current' + 'directory by default. Also may include url.') +my_command1.add_argument( + '-r', '--rollback', action='store_true', default=False, + help='If specified will rollback all resources applied.') +my_command1.add_argument( + '--tree', action='store_true', default=False, + help='Print resource tree') +my_command1.add_argument( + '--dry', action='store_true', default=False, + help='Just print changes list') +my_command1.add_argument( + '--force', action='store_true', default=False, + help='Apply without confirmation') +my_command1.add_argument( + 'default_string', default='I am a default', + help='Ensure variables are filled in %(prog)s (default %(default)s)') my_command2 = subparsers.add_parser('game', help='Decision games') -my_command2.add_argument('move', choices=['rock', 'paper', 'scissors'], help='Choices for argument example') -my_command2.add_argument('--opt', choices=['rock', 'paper', 'scissors'], help='Choices for option example') +my_command2.add_argument('move', choices=['rock', 'paper', 'scissors'], + help='Choices for argument example') +my_command2.add_argument('--opt', choices=['rock', 'paper', 'scissors'], + help='Choices for option example') optional = my_command2.add_argument_group('Group 1') -optional.add_argument('--addition', choices=['Spock', 'lizard'], help='Extra choices for additional group.') -optional.add_argument('--lorem_ipsum', - help='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ' - 'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, ' - 'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo ' - 'consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse ' - 'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat ' - 'non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.') +optional.add_argument('--addition', choices=['Spock', 'lizard'], + help='Extra choices for additional group.') +optional.add_argument( + '--lorem_ipsum', + help='Lorem ipsum dolor sit amet, consectetur adipiscing elit,' + ' sed do eiusmod tempor incididunt ut labore et dolore magna' + ' aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + ' ullamco laboris nisi ut aliquip ex ea commodo consequat.' + ' Duis aute irure dolor in reprehenderit in voluptate velit esse' + ' cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat' + ' cupidatat non proident, sunt in culpa qui officia deserunt' + ' mollit anim id est laborum.') diff --git a/test/test_parser.py b/test/test_parser.py index 26a7481..a222882 100755 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -5,7 +5,8 @@ def test_parse_options(): parser = argparse.ArgumentParser() - parser.add_argument('--foo', action='store_true', default=False, help='foo help') + parser.add_argument('--foo', action='store_true', + default=False, help='foo help') parser.add_argument('--bar', action='store_true', default=False) data = parse_parser(parser) @@ -106,7 +107,8 @@ def test_parse_positional(): def test_parse_description(): - parser = argparse.ArgumentParser(description='described', epilog='epilogged') + parser = argparse.ArgumentParser(description='described', + epilog='epilogged') parser.add_argument('foo', default=False, help='foo help') parser.add_argument('bar', default=False) @@ -138,7 +140,8 @@ def test_parse_nested(): subparser = subparsers.add_parser('install', help='install help') subparser.add_argument('ref', type=str, help='foo1 help') - subparser.add_argument('--upgrade', action='store_true', default=False, help='foo2 help') + subparser.add_argument('--upgrade', action='store_true', + default=False, help='foo2 help') data = parse_parser(parser) @@ -158,8 +161,8 @@ def test_parse_nested(): { 'name': 'install', 'help': 'install help', - 'usage': 'usage: py.test install [-h] [--upgrade] ref', - 'bare_usage': 'py.test install [-h] [--upgrade] ref', + 'usage': 'usage: %s install [-h] [--upgrade] ref' % parser.prog, + 'bare_usage': '%s install [-h] [--upgrade] ref' % parser.prog, 'action_groups': [ { 'title': 'Positional Arguments', @@ -196,9 +199,11 @@ def test_parse_nested_with_alias(): subparsers = parser.add_subparsers() - subparser = subparsers.add_parser('install', aliases=['i'], help='install help') + subparser = subparsers.add_parser('install', aliases=['i'], + help='install help') subparser.add_argument('ref', type=str, help='foo1 help') - subparser.add_argument('--upgrade', action='store_true', default=False, help='foo2 help') + subparser.add_argument('--upgrade', action='store_true', + default=False, help='foo2 help') data = parse_parser(parser) @@ -219,8 +224,10 @@ def test_parse_nested_with_alias(): 'name': 'install (i)', 'identifier': 'install', 'help': 'install help', - 'usage': 'usage: py.test install [-h] [--upgrade] ref', - 'bare_usage': 'py.test install [-h] [--upgrade] ref', + 'usage': 'usage: %s install [-h] [--upgrade] ref' % + parser.prog, + 'bare_usage': '%s install [-h] [--upgrade] ref' % + parser.prog, 'action_groups': [ { 'title': 'Positional Arguments', @@ -259,9 +266,9 @@ def test_aliased_traversal(): data2 = parser_navigate(data, 'level1') assert(data2 == { - 'bare_usage': 'py.test level1 [-h]', + 'bare_usage': '%s level1 [-h]' % parser.prog, 'help': '', - 'usage': 'usage: py.test level1 [-h]', + 'usage': 'usage: %s level1 [-h]' % parser.prog, 'name': 'level1 (l1)', 'identifier': 'level1'}) @@ -302,8 +309,10 @@ def test_parse_nested_traversal(): { 'name': 'level3', 'help': '', - 'usage': 'usage: py.test level1 level2 level3 [-h] foo bar', - 'bare_usage': 'py.test level1 level2 level3 [-h] foo bar', + 'usage': 'usage: %s level1 level2 level3 [-h] foo bar' % + parser.prog, + 'bare_usage': '%s level1 level2 level3 [-h] foo bar' % + parser.prog, 'action_groups': [ { 'title': 'Positional Arguments', @@ -329,10 +338,12 @@ def test_parse_nested_traversal(): def test_fill_in_default_prog(): """ - Ensure that %(default)s and %(prog)s are getting properly filled in inside help='' + Ensure that %(default)s and %(prog)s are getting + properly filled in inside help='' """ parser = argparse.ArgumentParser(prog='test_fill_in_default_prog') - parser.add_argument('bar', default='foo', help='%(prog)s (default: %(default)s)') + parser.add_argument('bar', default='foo', + help='%(prog)s (default: %(default)s)') data = parse_parser(parser) assert data['action_groups'][0]['options'] == [ @@ -346,11 +357,13 @@ def test_fill_in_default_prog(): def test_string_quoting(): """ - If an optional argument has a string type and a default, then the default should be in quotes. - This prevents things like '--optLSFConf=-q short' when '--optLSFConf="-q short"' is correct. + If an optional argument has a string type and a default, + then the default should be in quotes. This prevents things like + '--optLSFConf=-q short' when '--optLSFConf="-q short"' is correct. """ parser = argparse.ArgumentParser(prog='test_string_quoting_prog') - parser.add_argument('--bar', default='foo bar', help='%(prog)s (default: %(default)s)') + parser.add_argument('--bar', default='foo bar', + help='%(prog)s (default: %(default)s)') data = parse_parser(parser) assert data['action_groups'][0]['options'] == [ @@ -364,7 +377,8 @@ def test_string_quoting(): def test_parse_groups(): parser = argparse.ArgumentParser() - parser.add_argument('--foo', action='store_true', default=False, help='foo help') + parser.add_argument('--foo', action='store_true', + default=False, help='foo help') parser.add_argument('--bar', action='store_true', default=False) optional = parser.add_argument_group('Group 1') optional.add_argument("--option1", help='option #1') @@ -413,13 +427,83 @@ def test_action_groups_with_subcommands(): data = parse_parser(parser) assert data['action_groups'] == [ - {'options': [{'default': None, 'name': ['foo2 metavar'], 'help': 'foo2 help'}], 'description': None, 'title': 'Positional Arguments'}, - {'options': [{'default': None, 'name': ['--foo'], 'help': 'foo help'}], 'description': None, 'title': 'Named Arguments'}, - {'options': [{'default': None, 'name': ['--bar'], 'help': 'bar help'}, {'default': None, 'name': ['quux'], 'help': 'quux help'}], 'description': None, 'title': 'bar options'}, - {'options': [{'default': None, 'name': ['--blah'], 'help': 'blah help'}, {'default': None, 'name': ['sniggly'], 'help': 'sniggly help'}], 'description': None, 'title': 'bla options'} + { + 'options': [ + {'default': None, + 'name': ['foo2 metavar'], + 'help': 'foo2 help'} + ], + 'description': None, + 'title': 'Positional Arguments' + }, + { + 'options': [ + {'default': None, + 'name': ['--foo'], + 'help': 'foo help'} + ], + 'description': None, + 'title': 'Named Arguments' + }, + { + 'options': [ + {'default': None, + 'name': ['--bar'], + 'help': 'bar help'}, + {'default': None, + 'name': ['quux'], + 'help': 'quux help'} + ], + 'description': None, + 'title': 'bar options' + }, + { + 'options': [ + {'default': None, + 'name': ['--blah'], + 'help': 'blah help'}, + {'default': None, + 'name': ['sniggly'], + 'help': 'sniggly help'} + ], + 'description': None, + 'title': 'bla options' + } ] 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 [-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' + } ] diff --git a/tox.ini b/tox.ini index abe7ba8..bff51d1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,25 @@ [tox] -envlist = py26,py27,py33,py34,py35,py36 +envlist = + py27 + py33 + py34 + py35 + py36 + py37 + py38 + py39 + flake8 + [testenv] -deps=pytest -commands=py.test +extras = test +commands = + pip list + pytest -svv + +[testenv:flake8] +extras = lint +description = + Run style checks. +commands = + flake8 setup.py test/ sphinxarg/ + From d0cce8127c039a639a76b8a15c7c858ab267cf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Sun, 23 Aug 2020 12:57:35 +0200 Subject: [PATCH 2/3] Remove MANIFEST.in --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) delete mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 4cc50bb..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -exclude test \ No newline at end of file From 5d3399da45bd08f64d02423ff57a9970e138e67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Sun, 23 Aug 2020 13:23:51 +0200 Subject: [PATCH 3/3] Update supported Python versions --- .travis.yml | 6 +----- tox.ini | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 93d4c25..c557e21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,16 +7,12 @@ matrix: include: - python: 2.7 env: TOXENV=py27 - - python: 3.3 - env: TOXENV=py33 - - python: 3.4 - env: TOXENV=py34 - python: 3.5 env: TOXENV=py35 - python: 3.6 env: TOXENV=py36 - python: 3.7 - env: TOXENV=py36 + env: TOXENV=py37 - python: 3.8 env: TOXENV=py38 - python: 3.7 diff --git a/tox.ini b/tox.ini index bff51d1..ad360a3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,6 @@ [tox] envlist = py27 - py33 - py34 py35 py36 py37