summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2014-03-03 21:18:44 +0100
committerAnthon van der Neut <anthon@mnt.org>2014-03-03 21:18:44 +0100
commitd569ebeb9870331d739ab434dd9a99dfc4529a09 (patch)
tree6536c95d5089ea3e90eb6e2e3406d5787ca3538e
parent30dbd5babf56398c16efd82f513935d98e36a81d (diff)
downloadruamel.std.argparse-d569ebeb9870331d739ab434dd9a99dfc4529a09.tar.gz
add SmartFormatter and tests
-rw-r--r--.hgignore1
-rw-r--r--Makefile10
-rw-r--r--__init__.py68
-rw-r--r--[-rwxr-xr-x]setup.py101
-rw-r--r--test/test_argparse.py101
-rw-r--r--tox.ini7
6 files changed, 256 insertions, 32 deletions
diff --git a/.hgignore b/.hgignore
index f668120..d496f4b 100644
--- a/.hgignore
+++ b/.hgignore
@@ -5,6 +5,7 @@ syntax: glob
*~
*.bak
*.o
+*.orig
dist
build
*.egg-info
diff --git a/Makefile b/Makefile
index 3b26679..34bfaaa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,9 @@
+UTILNAME:=argparse
+PKGNAME:=ruamel.std.argparse
VERSION:=$$(python setup.py --version)
-DIST:=dist/ruamel.std.argparse-$(VERSION).tar.gz
-REGEN:=/usr/local/bin/ruamel_util_new util --std argparse --skip-hg --skip-util
+DIST:=dist/$(PKGNAME)-$(VERSION).tar.gz
+REGEN:=/usr/local/bin/ruamel_util_new util --std argparse --skip-util --skip-hg
sdist:
python setup.py sdist
@@ -10,7 +12,7 @@ wheel:
python setup.py bdist_wheel
clean:
- rm -rf build *.egg-info/
+ rm -rf build .tox $(PKGNAME).egg-info/
find . -name "*.pyc" -exec rm {} +
tar:
@@ -25,6 +27,6 @@ regen_setup:
pep8 setup.py
regen_makefile:
- rm -f ../argparse/Makefile
+ rm -f ../$(UTILNAME)/Makefile
$(REGEN)
diff --git a/__init__.py b/__init__.py
index 27847d1..0796ac7 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,8 +1,32 @@
# coding: utf-8
+
+def _convert_version(tup):
+ """create a PEP 386 pseudo-format conformant string from tuple tup"""
+ ret_val = str(tup[0]) # first is always digit
+ next_sep = "." # separator for next extension, can be "" or "."
+ for x in tup[1:]:
+ if isinstance(x, int):
+ ret_val += next_sep + str(x)
+ next_sep = '.'
+ continue
+ first_letter = x[0].lower()
+ next_sep = ''
+ if first_letter in 'abcr':
+ ret_val += 'rc' if first_letter == 'r' else first_letter
+ elif first_letter in 'pd':
+ ret_val += '.post' if first_letter == 'p' else '.dev'
+ return ret_val
+
+version_info = (0, 2, "alpha", 1)
+__version__ = _convert_version(version_info)
+
+del _convert_version
+
import argparse
from argparse import ArgumentParser
+
class SubParsersAction(argparse._SubParsersAction):
"""support aliases, based on differences of 3.3 and 2.7
"""
@@ -17,13 +41,15 @@ class SubParsersAction(argparse._SubParsersAction):
metavar=metavar)
def add_parser(self, name, **kwargs):
- # remove aliases and help kwargs so orginal add_parser does not get them
+ # remove aliases and help kwargs so the orginal add_parser
+ # does not get them
aliases = kwargs.pop('aliases', ())
help = kwargs.pop('help', None)
parser = argparse._SubParsersAction.add_parser(self, name, **kwargs)
if help is not None:
- choice_action = self._AliasesChoicesPseudoAction(name, aliases, help)
+ choice_action = self._AliasesChoicesPseudoAction(name, aliases,
+ help)
self._choices_actions.append(choice_action)
if aliases is not None:
for alias in aliases:
@@ -34,3 +60,41 @@ class SubParsersAction(argparse._SubParsersAction):
from _action.checksinglestore import CheckSingleStoreAction
from _action.count import CountAction
from _action.splitappend import SplitAppendAction
+
+
+class SmartFormatter(argparse.HelpFormatter):
+ """
+ you can only specify one formatter in standard argparse, so you cannot
+ both have pre-formatted description (RawDescriptionHelpFormatter)
+ and ArgumentDefaultsHelpFormatter.
+ The SmartFormatter has sensible defaults (RawDescriptionFormatter) and
+ the individual help text can be marked ( help="R|" ) for
+ variations in formatting.
+ """
+ def __init__(self, *args, **kw):
+ self._add_defaults = False
+ super(SmartFormatter, self).__init__(*args, **kw)
+
+ def _fill_text(self, text, width, indent):
+ return ''.join([indent + line for line in text.splitlines(True)])
+
+
+ def _split_lines(self, text, width):
+ #print 'TEXT', text
+ if text.startswith('D|'):
+ self._add_defaults = True
+ text = text[2:]
+ if text.startswith('R|'):
+ return text[2:].splitlines()
+ return argparse.HelpFormatter._split_lines(self, text, width)
+
+ def _get_help_string(self, action):
+ if not self._add_defaults:
+ return argparse.HelpFormatter._get_help_string(self, action)
+ help = action.help
+ if '%(default)' not in action.help:
+ if action.default is not argparse.SUPPRESS:
+ defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
+ if action.option_strings or action.nargs in defaulting_nargs:
+ help += ' (default: %(default)s)'
+ return help
diff --git a/setup.py b/setup.py
index ca18752..8f83608 100755..100644
--- a/setup.py
+++ b/setup.py
@@ -1,26 +1,77 @@
#! /usr/bin/env python
# coding: utf-8
+from __future__ import print_function
+
import sys
import os
-from setuptools import setup, find_packages
-from setuptools.command import install_lib
from textwrap import dedent
name_space = 'ruamel'
-full_package_name = name_space + '.std.argparse'
+package_name = 'argparse'
+full_package_name = name_space + '.std.' + package_name
exclude_files = [
- 'setup.py'
+ 'setup.py',
]
+
+def get_version():
+ v_i = 'version_info = '
+ for line in open('__init__.py'):
+ if not line.startswith(v_i):
+ continue
+ s_e = line[len(v_i):].strip()[1:-1].split(', ')
+ els = [x.strip()[1:-1] if x[0] in '\'"' else int(x) for x in s_e]
+ return els
+
+
+def _check_convert_version(tup):
+ """create a PEP 386 pseudo-format conformant string from tuple tup"""
+ ret_val = str(tup[0]) # first is always digit
+ next_sep = "." # separator for next extension, can be "" or "."
+ nr_digits = 0 # nr of adjacent digits in rest, to verify
+ post_dev = False # are we processig post/dev
+ for x in tup[1:]:
+ if isinstance(x, int):
+ nr_digits += 1
+ if nr_digits > 2:
+ raise ValueError("to many consecutive digits " + ret_val)
+ ret_val += next_sep + str(x)
+ next_sep = '.'
+ continue
+ first_letter = x[0].lower()
+ next_sep = ''
+ if first_letter in 'abcr':
+ if post_dev:
+ raise ValueError("release level specified after "
+ "post/dev:" + x)
+ nr_digits = 0
+ ret_val += 'rc' if first_letter == 'r' else first_letter
+ elif first_letter in 'pd':
+ nr_digits = 1 # only one can follow
+ post_dev = True
+ ret_val += '.post' if first_letter == 'p' else '.dev'
+ else:
+ raise ValueError('First letter of "' + x + '" not recognised')
+ return ret_val
+
+version_info = get_version()
+version_str = _check_convert_version(version_info)
+
+if __name__ == '__main__':
+ # put here so setup.py can be imported more easily
+ from setuptools import setup, find_packages, Extension
+ from setuptools.command import install_lib
+
+
class MyInstallLib(install_lib.install_lib):
"create __init__.py on the fly"
def run(self):
install_lib.install_lib.run(self)
init_txt = dedent('''\
# coding: utf-8
- # Copyright © 2013 Anthon van der Neut, RUAMEL bvba
+ # Copyright © 2013-2014 Anthon van der Neut, RUAMEL bvba
"generated __init__.py "
try:
__import__('pkg_resources').declare_namespace(__name__)
@@ -30,8 +81,8 @@ class MyInstallLib(install_lib.install_lib):
init_path = full_package_name.split('.')[:-1]
for product_init in [
os.path.join(
- *([self.install_dir] + init_path[:p+1] + ['__init__.py'])) for p
- in range(len(init_path))
+ *([self.install_dir] + init_path[:p+1] + ['__init__.py']))
+ for p in range(len(init_path))
]:
if not os.path.exists(product_init):
print('creating %s' % product_init)
@@ -41,7 +92,8 @@ class MyInstallLib(install_lib.install_lib):
def install(self):
fpp = full_package_name.split('.') # full package path
- full_exclude_files = [os.path.join(*(fpp + [x])) for x in exclude_files]
+ full_exclude_files = [os.path.join(*(fpp + [x]))
+ for x in exclude_files]
alt_files = []
outfiles = install_lib.install_lib.install(self)
for x in outfiles:
@@ -51,35 +103,32 @@ class MyInstallLib(install_lib.install_lib):
break
else:
alt_files.append(x)
- for x in alt_files:
- print ' ', x.split('site-packages/')[-1]
-
return alt_files
def main():
install_requires = [
- ]
- packages = [full_package_name] + [(full_package_name + '.' + x) for x \
- in find_packages(exclude=['tests'])]
+ ]
+ #if sys.version_info < (3, 4):
+ # install_requires.append("")
+ packages = [full_package_name] + [(full_package_name + '.' + x) for x
+ in find_packages(exclude=['tests'])]
setup(
name=full_package_name,
- version="0.1.1",
+ version=version_str,
description="Documentation for " + full_package_name,
- install_requires=[
- # 'configobj >=4.7.2',
- ],
- #install_requires=install_requires,
- long_description="Long Description",
- url='https://bitbucket.org/anthon_van_der_neut/' + full_package_name,
+ install_requires=install_requires,
+ long_description=open('README.rst').read(),
+ url='https://bitbucket.org/ruamel/' + package_name,
author='Anthon van der Neut',
author_email='a.van.der.neut@ruamel.eu',
- license='Copyright Ruamel bvba 2007-2013',
+ license="Copyright Ruamel bvba 2007-2014",
package_dir={full_package_name: '.'},
- namespace_packages = [name_space],
+ namespace_packages=[name_space],
packages=packages,
cmdclass={'install_lib': MyInstallLib},
- classifiers=['Development Status :: 4 - Beta',
+ classifiers=[
+ 'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: Copyrighted',
'Operating System :: OS Independent',
@@ -89,7 +138,7 @@ def main():
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'sdist':
- assert full_package_name == os.path.abspath(os.path.dirname(
+ assert full_package_name == os.path.abspath(os.path.dirname(
__file__)).split('site-packages' + os.path.sep)[1].replace(
- os.path.sep, '.')
+ os.path.sep, '.')
main()
diff --git a/test/test_argparse.py b/test/test_argparse.py
new file mode 100644
index 0000000..1fab404
--- /dev/null
+++ b/test/test_argparse.py
@@ -0,0 +1,101 @@
+
+import pytest
+
+from ruamel.std.argparse import argparse, CountAction, SmartFormatter
+from textwrap import dedent
+
+def exit(self=None, status=None, message=None):
+ pass
+
+# default for tox stub is to Fail
+def test_argparse(capsys):
+ desc = dedent("""\
+ Please do not mess up this text!
+ --------------------------------
+ I have indented it
+ exactly the way
+ I want it
+ """)
+ help_verbose = "add some verbosity to the output"
+ help_list = """\
+ choose one:
+ 1) red
+ 2) green
+ 3) blue
+ """
+ help_one = """one
+ line
+ help
+ """
+ parser = argparse.ArgumentParser(
+ description=desc,
+ formatter_class=SmartFormatter,
+ )
+ parser.exit = exit
+ parser.add_argument('--verbose', action='store_true',
+ help=help_verbose)
+ parser.add_argument('--list', help='R|' + dedent(help_list))
+ parser.add_argument('--oneline', action='store_true', help=help_one)
+ parser.parse_args(['--help'])
+ out, err = capsys.readouterr()
+ full_help = dedent("""\
+ usage: py.test [-h] [--verbose] [--list LIST] [--oneline]
+
+ {}
+ optional arguments:
+ -h, --help show this help message and exit
+ --verbose {}
+ --list LIST {}
+ --oneline one line help
+ """).format(
+ desc, help_verbose,
+ help_list.lstrip().replace('\n ', '\n ').rstrip(),
+ )
+ assert full_help == out
+
+def test_argparse_default(capsys):
+ desc = dedent("""\
+ Please do not mess up this text!
+ --------------------------------
+ I have indented it
+ exactly the way
+ I want it
+ """)
+ help_verbose = "add some verbosity to the output"
+ help_list = """\
+ choose one:
+ 1) red
+ 2) green
+ 3) blue
+ """
+ help_one = """one
+ line
+ help
+ """
+ parser = argparse.ArgumentParser(
+ description=desc,
+ formatter_class=SmartFormatter,
+ )
+ parser.exit = exit
+ # add "D|" to the first option
+ parser.add_argument('--verbose', action='store_true',
+ help='D|' + help_verbose)
+ parser.add_argument('--list', help='R|' + dedent(help_list))
+ parser.add_argument('--oneline', action='store_true', help=help_one)
+ parser.parse_args(['--help'])
+ out, err = capsys.readouterr()
+ full_help = dedent("""\
+ usage: py.test [-h] [--verbose] [--list LIST] [--oneline]
+
+ {}
+ optional arguments:
+ -h, --help show this help message and exit
+ --verbose {} (default: False)
+ --list LIST {}
+ (default: None)
+ --oneline one line help (default: False)
+ """).format(
+ desc, help_verbose,
+ help_list.lstrip().replace('\n ', '\n ').rstrip(),
+ )
+ assert full_help == out
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..72827a8
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,7 @@
+[tox]
+envlist = py27
+
+[testenv]
+commands = py.test test
+deps =
+ pytest