Merge pull request #5082 from blueyed/pytester-raise_on_kwargs

pytester: improve/fix kwargs validation
This commit is contained in:
Daniel Hahler 2019-04-11 00:46:18 +02:00 committed by GitHub
commit b3759372ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 12 deletions

View File

@ -0,0 +1 @@
Improved validation of kwargs for various methods in the pytester plugin.

View File

@ -76,8 +76,11 @@ def pytest_configure(config):
def raise_on_kwargs(kwargs): def raise_on_kwargs(kwargs):
__tracebackhide__ = True
if kwargs: if kwargs:
raise TypeError("Unexpected arguments: {}".format(", ".join(sorted(kwargs)))) raise TypeError(
"Unexpected keyword arguments: {}".format(", ".join(sorted(kwargs)))
)
class LsofFdLeakChecker(object): class LsofFdLeakChecker(object):
@ -803,12 +806,15 @@ class Testdir(object):
:param args: command line arguments to pass to :py:func:`pytest.main` :param args: command line arguments to pass to :py:func:`pytest.main`
:param plugin: (keyword-only) extra plugin instances the :param plugins: (keyword-only) extra plugin instances the
``pytest.main()`` instance should use ``pytest.main()`` instance should use
:return: a :py:class:`HookRecorder` instance :return: a :py:class:`HookRecorder` instance
""" """
plugins = kwargs.pop("plugins", [])
no_reraise_ctrlc = kwargs.pop("no_reraise_ctrlc", None)
raise_on_kwargs(kwargs)
finalizers = [] finalizers = []
try: try:
# Do not load user config (during runs only). # Do not load user config (during runs only).
@ -848,7 +854,6 @@ class Testdir(object):
def pytest_configure(x, config): def pytest_configure(x, config):
rec.append(self.make_hook_recorder(config.pluginmanager)) rec.append(self.make_hook_recorder(config.pluginmanager))
plugins = kwargs.get("plugins") or []
plugins.append(Collect()) plugins.append(Collect())
ret = pytest.main(list(args), plugins=plugins) ret = pytest.main(list(args), plugins=plugins)
if len(rec) == 1: if len(rec) == 1:
@ -862,7 +867,7 @@ class Testdir(object):
# typically we reraise keyboard interrupts from the child run # typically we reraise keyboard interrupts from the child run
# because it's our user requesting interruption of the testing # because it's our user requesting interruption of the testing
if ret == EXIT_INTERRUPTED and not kwargs.get("no_reraise_ctrlc"): if ret == EXIT_INTERRUPTED and not no_reraise_ctrlc:
calls = reprec.getcalls("pytest_keyboard_interrupt") calls = reprec.getcalls("pytest_keyboard_interrupt")
if calls and calls[-1].excinfo.type == KeyboardInterrupt: if calls and calls[-1].excinfo.type == KeyboardInterrupt:
raise KeyboardInterrupt() raise KeyboardInterrupt()
@ -874,9 +879,10 @@ class Testdir(object):
def runpytest_inprocess(self, *args, **kwargs): def runpytest_inprocess(self, *args, **kwargs):
"""Return result of running pytest in-process, providing a similar """Return result of running pytest in-process, providing a similar
interface to what self.runpytest() provides. interface to what self.runpytest() provides.
""" """
if kwargs.get("syspathinsert"): syspathinsert = kwargs.pop("syspathinsert", False)
if syspathinsert:
self.syspathinsert() self.syspathinsert()
now = time.time() now = time.time()
capture = MultiCapture(Capture=SysCapture) capture = MultiCapture(Capture=SysCapture)
@ -1201,9 +1207,10 @@ class Testdir(object):
:py:class:`Testdir.TimeoutExpired` :py:class:`Testdir.TimeoutExpired`
Returns a :py:class:`RunResult`. Returns a :py:class:`RunResult`.
""" """
__tracebackhide__ = True __tracebackhide__ = True
timeout = kwargs.pop("timeout", None)
raise_on_kwargs(kwargs)
p = py.path.local.make_numbered_dir( p = py.path.local.make_numbered_dir(
prefix="runpytest-", keep=None, rootdir=self.tmpdir prefix="runpytest-", keep=None, rootdir=self.tmpdir
@ -1213,7 +1220,7 @@ class Testdir(object):
if plugins: if plugins:
args = ("-p", plugins[0]) + args args = ("-p", plugins[0]) + args
args = self._getpytestargs() + args args = self._getpytestargs() + args
return self.run(*args, timeout=kwargs.get("timeout")) return self.run(*args, timeout=timeout)
def spawn_pytest(self, string, expect_timeout=10.0): def spawn_pytest(self, string, expect_timeout=10.0):
"""Run pytest using pexpect. """Run pytest using pexpect.

View File

@ -819,15 +819,15 @@ def test_error_during_readouterr(testdir):
testdir.makepyfile( testdir.makepyfile(
pytest_xyz=""" pytest_xyz="""
from _pytest.capture import FDCapture from _pytest.capture import FDCapture
def bad_snap(self): def bad_snap(self):
raise Exception('boom') raise Exception('boom')
assert FDCapture.snap assert FDCapture.snap
FDCapture.snap = bad_snap FDCapture.snap = bad_snap
""" """
) )
result = testdir.runpytest_subprocess( result = testdir.runpytest_subprocess("-p", "pytest_xyz", "--version")
"-p", "pytest_xyz", "--version", syspathinsert=True
)
result.stderr.fnmatch_lines( result.stderr.fnmatch_lines(
["*in bad_snap", " raise Exception('boom')", "Exception: boom"] ["*in bad_snap", " raise Exception('boom')", "Exception: boom"]
) )