Fix --help with required options
This works by adding an argparse Action that will raise an exception in order to skip the rest of the argument parsing. This prevents argparse from quitting due to missing required arguments, similar to the way that the builtin argparse --help option is implemented by raising SystemExit. Fixes: #1999
This commit is contained in:
parent
bcbad5b1af
commit
f74f14f038
1
AUTHORS
1
AUTHORS
|
@ -144,6 +144,7 @@ Ross Lawley
|
||||||
Russel Winder
|
Russel Winder
|
||||||
Ryan Wooden
|
Ryan Wooden
|
||||||
Samuele Pedroni
|
Samuele Pedroni
|
||||||
|
Segev Finer
|
||||||
Simon Gomizelj
|
Simon Gomizelj
|
||||||
Skylar Downes
|
Skylar Downes
|
||||||
Stefan Farmbauer
|
Stefan Farmbauer
|
||||||
|
|
|
@ -71,6 +71,12 @@ class UsageError(Exception):
|
||||||
""" error in pytest usage or invocation"""
|
""" error in pytest usage or invocation"""
|
||||||
|
|
||||||
|
|
||||||
|
class PrintHelp(Exception):
|
||||||
|
"""Raised when pytest should print it's help to skip the rest of the
|
||||||
|
argument parsing and validation."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def filename_arg(path, optname):
|
def filename_arg(path, optname):
|
||||||
""" Argparse type validator for filename arguments.
|
""" Argparse type validator for filename arguments.
|
||||||
|
|
||||||
|
@ -1100,14 +1106,18 @@ class Config(object):
|
||||||
self._preparse(args, addopts=addopts)
|
self._preparse(args, addopts=addopts)
|
||||||
# XXX deprecated hook:
|
# XXX deprecated hook:
|
||||||
self.hook.pytest_cmdline_preparse(config=self, args=args)
|
self.hook.pytest_cmdline_preparse(config=self, args=args)
|
||||||
args = self._parser.parse_setoption(args, self.option, namespace=self.option)
|
self._parser.after_preparse = True
|
||||||
if not args:
|
try:
|
||||||
cwd = os.getcwd()
|
args = self._parser.parse_setoption(args, self.option, namespace=self.option)
|
||||||
if cwd == self.rootdir:
|
|
||||||
args = self.getini('testpaths')
|
|
||||||
if not args:
|
if not args:
|
||||||
args = [cwd]
|
cwd = os.getcwd()
|
||||||
self.args = args
|
if cwd == self.rootdir:
|
||||||
|
args = self.getini('testpaths')
|
||||||
|
if not args:
|
||||||
|
args = [cwd]
|
||||||
|
self.args = args
|
||||||
|
except PrintHelp:
|
||||||
|
pass
|
||||||
|
|
||||||
def addinivalue_line(self, name, line):
|
def addinivalue_line(self, name, line):
|
||||||
""" add a line to an ini-file option. The option must have been
|
""" add a line to an ini-file option. The option must have been
|
||||||
|
|
|
@ -3,13 +3,38 @@ from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import pytest
|
import pytest
|
||||||
|
from _pytest.config import PrintHelp
|
||||||
import os, sys
|
import os, sys
|
||||||
|
from argparse import Action
|
||||||
|
|
||||||
|
|
||||||
|
class HelpAction(Action):
|
||||||
|
def __init__(self,
|
||||||
|
option_strings,
|
||||||
|
dest=None,
|
||||||
|
default=False,
|
||||||
|
help=None):
|
||||||
|
super(HelpAction, self).__init__(
|
||||||
|
option_strings=option_strings,
|
||||||
|
dest=dest,
|
||||||
|
const=True,
|
||||||
|
default=default,
|
||||||
|
nargs=0,
|
||||||
|
help=help)
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
setattr(namespace, self.dest, self.const)
|
||||||
|
|
||||||
|
# We should only skip the rest of the parsing after preparse is done
|
||||||
|
if getattr(parser._parser, 'after_preparse', False):
|
||||||
|
raise PrintHelp
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.getgroup('debugconfig')
|
group = parser.getgroup('debugconfig')
|
||||||
group.addoption('--version', action="store_true",
|
group.addoption('--version', action="store_true",
|
||||||
help="display pytest lib version and import information.")
|
help="display pytest lib version and import information.")
|
||||||
group._addoption("-h", "--help", action="store_true", dest="help",
|
group._addoption("-h", "--help", action=HelpAction, dest="help",
|
||||||
help="show help message and configuration info")
|
help="show help message and configuration info")
|
||||||
group._addoption('-p', action="append", dest="plugins", default = [],
|
group._addoption('-p', action="append", dest="plugins", default = [],
|
||||||
metavar="name",
|
metavar="name",
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Required options added via ``pytest_addoption`` will no longer prevent
|
||||||
|
using --help without passing them.
|
|
@ -449,3 +449,15 @@ def test_hook_proxy(testdir):
|
||||||
'*test_foo4.py*',
|
'*test_foo4.py*',
|
||||||
'*3 passed*',
|
'*3 passed*',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_required_option_help(testdir):
|
||||||
|
testdir.makeconftest("assert 0")
|
||||||
|
x = testdir.mkdir("x")
|
||||||
|
x.join("conftest.py").write(_pytest._code.Source("""
|
||||||
|
def pytest_addoption(parser):
|
||||||
|
parser.addoption("--xyz", action="store_true", required=True)
|
||||||
|
"""))
|
||||||
|
result = testdir.runpytest("-h", x)
|
||||||
|
assert 'argument --xyz is required' not in result.stdout.str()
|
||||||
|
assert 'general:' in result.stdout.str()
|
||||||
|
|
Loading…
Reference in New Issue