3 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/8c92bc4c65aa/
Changeset: 8c92bc4c65aa
Branch: argcomplete
User: Anthon van der Neut
Date: 2013-07-30 11:26:15
Summary: Fixes for argcomplete
- separate out most argcomplete related stuff in new file _argcomplete.py
(could probably be in the py library)
- allow positional arguments to be interspaced with optional arguments
( + test in test_parseopt.py )
- removed double argument in tox.ini
- add documentation on installing argcomplete (>=0.5.7 as needed for
Python 3), might need improving/incorporation in index.
This does not work on 2.5 yet. I have patches for argcomplete
(with/print()/"".format) but I am not sure they will be accepted.
Agreed with hpk not to push for that.
Removing argcomplete and leaving completion code active now works by early
exit, so <TAB> no longer re-runs the programs without parameters
(which took long for py.test)
test calls bash with a script that redirects filedescriptor 8 (as used by
argcomplete), so the result can be tested.
Affected #: 5 files
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
8c92bc4c65aa426cf9e795dbf4a2654cef71b46c _pytest/_argcomplete.py
--- /dev/null
+++ b/_pytest/_argcomplete.py
@@ -0,0 +1,68 @@
+
+"""allow bash-completion for argparse with argcomplete if installed
+needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
+to find the magic string, so _ARGCOMPLETE env. var is never set, and
+this does not need special code.
+
+argcomplete does not support python 2.5 (although the changes for that
+are minor).
+
+Function try_argcomplete(parser) should be called directly before
+the call to ArgumentParser.parse_args().
+
+The filescompleter is what you normally would use on the positional
+arguments specification, in order to get "dirname/" after "dirn<TAB>"
+instead of the default "dirname ":
+
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
+
+Other, application specific, completers should go in the file
+doing the add_argument calls as they need to be specified as .completer
+attributes as well. (If argcomplete is not installed, the function the
+attribute points to will not be used).
+
+---
+To include this support in another application that has setup.py generated
+scripts:
+- add the line:
+ # PYTHON_ARGCOMPLETE_OK
+ near the top of the main python entry point
+- include in the file calling parse_args():
+ from _argcomplete import try_argcomplete, filescompleter
+ , call try_argcomplete just before parse_args(), and optionally add
+ filescompleter to the positional arguments' add_argument()
+If things do not work right away:
+- switch on argcomplete debugging with (also helpful when doing custom
+ completers):
+ export _ARC_DEBUG=1
+- run:
+ python-argcomplete-check-easy-install-script $(which appname)
+ echo $?
+ will echo 0 if the magic line has been found, 1 if not
+- sometimes it helps to find early on errors using:
+ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname
+ which should throw a KeyError: 'COMPLINE' (which is properly set by the
+ global argcomplete script).
+
+"""
+
+import sys
+import os
+
+if os.environ.get('_ARGCOMPLETE'):
+ # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
+ if sys.version_info[:2] < (2, 6):
+ sys.exit(1)
+ try:
+ import argcomplete
+ import argcomplete.completers
+ except ImportError:
+ sys.exit(-1)
+ filescompleter = argcomplete.completers.FilesCompleter()
+
+ def try_argcomplete(parser):
+ argcomplete.autocomplete(parser)
+else:
+ def try_argcomplete(parser): pass
+ filescompleter = None
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
8c92bc4c65aa426cf9e795dbf4a2654cef71b46c _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -4,6 +4,7 @@
import sys, os
from _pytest.core import PluginManager
import pytest
+from _argcomplete import try_argcomplete, filescompleter
# enable after some grace period for plugin writers
TYPE_WARN = False
@@ -91,7 +92,9 @@
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
- optparser.add_argument(Config._file_or_dir, nargs='*')
+ # bash like autocompletion for dirs (appending '/')
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
@@ -115,13 +118,6 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
-def try_argcomplete(parser):
- try:
- import argcomplete
- except ImportError:
- pass
- else:
- argcomplete.autocomplete(parser)
class ArgumentError(Exception):
"""
@@ -304,6 +300,7 @@
self._parser = parser
py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
add_help=False)
+
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -312,6 +309,18 @@
return s
return ""
+ def parse_args(self, args=None, namespace=None):
+ """allow splitting of positional arguments"""
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ for arg in argv:
+ if arg and arg[0] == '-':
+ msg = py.std.argparse._('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ getattr(args, Config._file_or_dir).extend(argv)
+ return args
+
+
class Conftest(object):
""" the single place for accessing values and interacting
towards conftest modules from py.test objects.
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
8c92bc4c65aa426cf9e795dbf4a2654cef71b46c doc/en/bash-completion.txt
--- /dev/null
+++ b/doc/en/bash-completion.txt
@@ -0,0 +1,28 @@
+
+.. _bash_completion:
+
+Setting up bash completion
+==========================
+
+When using bash as your shell, ``py.test`` can use argcomplete
+(https://argcomplete.readthedocs.org/) for auto-completion.
+For this ``argcomplete`` needs to be installed **and** enabled.
+
+Install argcomplete using::
+
+ sudo pip install 'argcomplete>=0.5.7'
+
+For global activation of all argcomplete enabled python applications run::
+
+ sudo activate-global-python-argcomplete
+
+For permanent (but not global) ``py.test`` activation, use::
+
+ register-python-argcomplete py.test >> ~/.bashrc
+
+For one-time activation of argcomplete for ``py.test`` only, use::
+
+ eval "$(register-python-argcomplete py.test)"
+
+
+
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
8c92bc4c65aa426cf9e795dbf4a2654cef71b46c testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -130,6 +130,21 @@
args = parser.parse(['--ultimate-answer', '42'])
assert args.ultimate_answer == 42
+ def test_parse_split_positional_arguments(self):
+ parser = parseopt.Parser()
+ parser.addoption("-R", action='store_true')
+ parser.addoption("-S", action='store_false')
+ args = parser.parse(['-R', '4', '2', '-S'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ args = parser.parse(['-R', '-S', '4', '2', '-R'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+ args = parser.parse(['-R', '4', '-S', '2'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+
def test_parse_defaultgetter(self):
def defaultget(option):
if not hasattr(option, 'type'):
@@ -158,3 +173,28 @@
#assert result.ret != 0
result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
[email protected]("sys.version_info < (2,5)")
+def test_argcomplete(testdir):
+ import os
+ p = py.path.local.make_numbered_dir(prefix="test_argcomplete-",
+ keep=None, rootdir=testdir.tmpdir)
+ script = p._fastjoin('test_argcomplete')
+ with open(str(script), 'w') as fp:
+ # redirect output from argcomplete to stdin and stderr is not trivial
+ # http://stackoverflow.com/q/12589419/1307905
+ # so we use bash
+ fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) '
+ '8>&1 9>&2')
+ os.environ['_ARGCOMPLETE'] = "1"
+ os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
+ os.environ['COMP_LINE'] = "py.test --fu"
+ os.environ['COMP_POINT'] = "12"
+ os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
+
+ result = testdir.run('bash', str(script), '--fu')
+ print dir(result), result.ret
+ if result.ret == 255:
+ # argcomplete not found
+ assert True
+ else:
+ result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
8c92bc4c65aa426cf9e795dbf4a2654cef71b46c tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -43,7 +43,7 @@
deps=twisted
pexpect
commands=
- py.test -rsxf testing/test_unittest.py \
+ py.test -rsxf \
--junitxml={envlogdir}/junit-{envname}.xml
{posargs:testing/test_unittest.py}
[testenv:doctest]
changedir=.
https://bitbucket.org/hpk42/pytest/commits/f44d44a4142b/
Changeset: f44d44a4142b
Branch: argcomplete
User: Anthon van der Neut
Date: 2013-07-30 12:33:38
Summary: minor adjustment, added test for positional argument completion
Affected #: 2 files
diff -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c -r
f44d44a4142b72a260007e413e6419549b3c1dc1 _pytest/_argcomplete.py
--- a/_pytest/_argcomplete.py
+++ b/_pytest/_argcomplete.py
@@ -55,7 +55,6 @@
if sys.version_info[:2] < (2, 6):
sys.exit(1)
try:
- import argcomplete
import argcomplete.completers
except ImportError:
sys.exit(-1)
diff -r 8c92bc4c65aa426cf9e795dbf4a2654cef71b46c -r
f44d44a4142b72a260007e413e6419549b3c1dc1 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -175,10 +175,10 @@
@pytest.mark.skipif("sys.version_info < (2,5)")
def test_argcomplete(testdir):
+ if not py.path.local.sysfind('bash'):
+ pytest.skip("bash not available")
import os
- p = py.path.local.make_numbered_dir(prefix="test_argcomplete-",
- keep=None, rootdir=testdir.tmpdir)
- script = p._fastjoin('test_argcomplete')
+ script = os.path.join(os.getcwd(), 'test_argcomplete')
with open(str(script), 'w') as fp:
# redirect output from argcomplete to stdin and stderr is not trivial
# http://stackoverflow.com/q/12589419/1307905
@@ -187,14 +187,22 @@
'8>&1 9>&2')
os.environ['_ARGCOMPLETE'] = "1"
os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
- os.environ['COMP_LINE'] = "py.test --fu"
- os.environ['COMP_POINT'] = "12"
os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
- result = testdir.run('bash', str(script), '--fu')
+ arg = '--fu'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
print dir(result), result.ret
if result.ret == 255:
# argcomplete not found
- assert True
+ pytest.skip("argcomplete not available")
else:
result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
+
+ os.mkdir('test_argcomplete.d')
+ arg = 'test_argc'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"])
https://bitbucket.org/hpk42/pytest/commits/73015defd88f/
Changeset: 73015defd88f
User: hpk42
Date: 2013-07-31 07:51:07
Summary: Merged in anthon_van_der_neut/pytest/argcomplete (pull request #50)
Fixes for argcomplete
Affected #: 5 files
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
73015defd88f6a45ba44fd6e109b03bc8b3e82e9 _pytest/_argcomplete.py
--- /dev/null
+++ b/_pytest/_argcomplete.py
@@ -0,0 +1,67 @@
+
+"""allow bash-completion for argparse with argcomplete if installed
+needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
+to find the magic string, so _ARGCOMPLETE env. var is never set, and
+this does not need special code.
+
+argcomplete does not support python 2.5 (although the changes for that
+are minor).
+
+Function try_argcomplete(parser) should be called directly before
+the call to ArgumentParser.parse_args().
+
+The filescompleter is what you normally would use on the positional
+arguments specification, in order to get "dirname/" after "dirn<TAB>"
+instead of the default "dirname ":
+
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
+
+Other, application specific, completers should go in the file
+doing the add_argument calls as they need to be specified as .completer
+attributes as well. (If argcomplete is not installed, the function the
+attribute points to will not be used).
+
+---
+To include this support in another application that has setup.py generated
+scripts:
+- add the line:
+ # PYTHON_ARGCOMPLETE_OK
+ near the top of the main python entry point
+- include in the file calling parse_args():
+ from _argcomplete import try_argcomplete, filescompleter
+ , call try_argcomplete just before parse_args(), and optionally add
+ filescompleter to the positional arguments' add_argument()
+If things do not work right away:
+- switch on argcomplete debugging with (also helpful when doing custom
+ completers):
+ export _ARC_DEBUG=1
+- run:
+ python-argcomplete-check-easy-install-script $(which appname)
+ echo $?
+ will echo 0 if the magic line has been found, 1 if not
+- sometimes it helps to find early on errors using:
+ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname
+ which should throw a KeyError: 'COMPLINE' (which is properly set by the
+ global argcomplete script).
+
+"""
+
+import sys
+import os
+
+if os.environ.get('_ARGCOMPLETE'):
+ # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
+ if sys.version_info[:2] < (2, 6):
+ sys.exit(1)
+ try:
+ import argcomplete.completers
+ except ImportError:
+ sys.exit(-1)
+ filescompleter = argcomplete.completers.FilesCompleter()
+
+ def try_argcomplete(parser):
+ argcomplete.autocomplete(parser)
+else:
+ def try_argcomplete(parser): pass
+ filescompleter = None
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
73015defd88f6a45ba44fd6e109b03bc8b3e82e9 _pytest/config.py
--- a/_pytest/config.py
+++ b/_pytest/config.py
@@ -4,6 +4,7 @@
import sys, os
from _pytest.core import PluginManager
import pytest
+from _argcomplete import try_argcomplete, filescompleter
# enable after some grace period for plugin writers
TYPE_WARN = False
@@ -91,7 +92,9 @@
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
- optparser.add_argument(Config._file_or_dir, nargs='*')
+ # bash like autocompletion for dirs (appending '/')
+ optparser.add_argument(Config._file_or_dir, nargs='*'
+ ).completer=filescompleter
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args])
@@ -115,13 +118,6 @@
self._inidict[name] = (help, type, default)
self._ininames.append(name)
-def try_argcomplete(parser):
- try:
- import argcomplete
- except ImportError:
- pass
- else:
- argcomplete.autocomplete(parser)
class ArgumentError(Exception):
"""
@@ -304,6 +300,7 @@
self._parser = parser
py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
add_help=False)
+
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
@@ -312,6 +309,18 @@
return s
return ""
+ def parse_args(self, args=None, namespace=None):
+ """allow splitting of positional arguments"""
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ for arg in argv:
+ if arg and arg[0] == '-':
+ msg = py.std.argparse._('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ getattr(args, Config._file_or_dir).extend(argv)
+ return args
+
+
class Conftest(object):
""" the single place for accessing values and interacting
towards conftest modules from py.test objects.
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
73015defd88f6a45ba44fd6e109b03bc8b3e82e9 doc/en/bash-completion.txt
--- /dev/null
+++ b/doc/en/bash-completion.txt
@@ -0,0 +1,28 @@
+
+.. _bash_completion:
+
+Setting up bash completion
+==========================
+
+When using bash as your shell, ``py.test`` can use argcomplete
+(https://argcomplete.readthedocs.org/) for auto-completion.
+For this ``argcomplete`` needs to be installed **and** enabled.
+
+Install argcomplete using::
+
+ sudo pip install 'argcomplete>=0.5.7'
+
+For global activation of all argcomplete enabled python applications run::
+
+ sudo activate-global-python-argcomplete
+
+For permanent (but not global) ``py.test`` activation, use::
+
+ register-python-argcomplete py.test >> ~/.bashrc
+
+For one-time activation of argcomplete for ``py.test`` only, use::
+
+ eval "$(register-python-argcomplete py.test)"
+
+
+
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
73015defd88f6a45ba44fd6e109b03bc8b3e82e9 testing/test_parseopt.py
--- a/testing/test_parseopt.py
+++ b/testing/test_parseopt.py
@@ -130,6 +130,21 @@
args = parser.parse(['--ultimate-answer', '42'])
assert args.ultimate_answer == 42
+ def test_parse_split_positional_arguments(self):
+ parser = parseopt.Parser()
+ parser.addoption("-R", action='store_true')
+ parser.addoption("-S", action='store_false')
+ args = parser.parse(['-R', '4', '2', '-S'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ args = parser.parse(['-R', '-S', '4', '2', '-R'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+ args = parser.parse(['-R', '4', '-S', '2'])
+ assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2']
+ assert args.R == True
+ assert args.S == False
+
def test_parse_defaultgetter(self):
def defaultget(option):
if not hasattr(option, 'type'):
@@ -158,3 +173,36 @@
#assert result.ret != 0
result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"])
[email protected]("sys.version_info < (2,5)")
+def test_argcomplete(testdir):
+ if not py.path.local.sysfind('bash'):
+ pytest.skip("bash not available")
+ import os
+ script = os.path.join(os.getcwd(), 'test_argcomplete')
+ with open(str(script), 'w') as fp:
+ # redirect output from argcomplete to stdin and stderr is not trivial
+ # http://stackoverflow.com/q/12589419/1307905
+ # so we use bash
+ fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) '
+ '8>&1 9>&2')
+ os.environ['_ARGCOMPLETE'] = "1"
+ os.environ['_ARGCOMPLETE_IFS'] = "\x0b"
+ os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:'
+
+ arg = '--fu'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ print dir(result), result.ret
+ if result.ret == 255:
+ # argcomplete not found
+ pytest.skip("argcomplete not available")
+ else:
+ result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"])
+
+ os.mkdir('test_argcomplete.d')
+ arg = 'test_argc'
+ os.environ['COMP_LINE'] = "py.test " + arg
+ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE']))
+ result = testdir.run('bash', str(script), arg)
+ result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"])
diff -r 1530d0e3abf3e60a37cfc91aac47a5545a11628c -r
73015defd88f6a45ba44fd6e109b03bc8b3e82e9 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -43,7 +43,7 @@
deps=twisted
pexpect
commands=
- py.test -rsxf testing/test_unittest.py \
+ py.test -rsxf \
--junitxml={envlogdir}/junit-{envname}.xml
{posargs:testing/test_unittest.py}
[testenv:doctest]
changedir=.
Repository URL: https://bitbucket.org/hpk42/pytest/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
pytest-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pytest-commit