Switch setuponly and setupplan options to a hook-based implementation.
This commit is contained in:
parent
c6af737d4e
commit
032ce8baf6
|
@ -65,7 +65,7 @@ _preinit = []
|
||||||
default_plugins = (
|
default_plugins = (
|
||||||
"mark main terminal runner python pdb unittest capture skipping "
|
"mark main terminal runner python pdb unittest capture skipping "
|
||||||
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
||||||
"junitxml resultlog doctest cacheprovider").split()
|
"junitxml resultlog doctest cacheprovider setuponly setupplan").split()
|
||||||
|
|
||||||
builtin_plugins = set(default_plugins)
|
builtin_plugins = set(default_plugins)
|
||||||
builtin_plugins.add("pytester")
|
builtin_plugins.add("pytester")
|
||||||
|
|
|
@ -218,6 +218,19 @@ def pytest_runtest_logreport(report):
|
||||||
""" process a test setup/call/teardown report relating to
|
""" process a test setup/call/teardown report relating to
|
||||||
the respective phase of executing a test. """
|
the respective phase of executing a test. """
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Fixture related hooks
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@hookspec(firstresult=True)
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
""" performs fixture setup execution. """
|
||||||
|
|
||||||
|
def pytest_fixture_post_finalizer(fixturedef):
|
||||||
|
""" called after fixture teardown, but before the cache is cleared so
|
||||||
|
the fixture result cache ``fixturedef.cached_result`` can
|
||||||
|
still be accessed."""
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# test session related hooks
|
# test session related hooks
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
|
@ -2475,25 +2475,18 @@ class FixtureDef:
|
||||||
func = self._finalizer.pop()
|
func = self._finalizer.pop()
|
||||||
func()
|
func()
|
||||||
finally:
|
finally:
|
||||||
|
ihook = self._fixturemanager.session.ihook
|
||||||
|
ihook.pytest_fixture_post_finalizer(fixturedef=self)
|
||||||
# even if finalization fails, we invalidate
|
# even if finalization fails, we invalidate
|
||||||
# the cached fixture value
|
# the cached fixture value
|
||||||
if hasattr(self, "cached_result"):
|
if hasattr(self, "cached_result"):
|
||||||
config = self._fixturemanager.config
|
|
||||||
if config.option.setuponly or config.option.setupplan:
|
|
||||||
self._show_fixture_action('TEARDOWN')
|
|
||||||
if hasattr(self, "cached_param"):
|
|
||||||
del self.cached_param
|
|
||||||
del self.cached_result
|
del self.cached_result
|
||||||
|
|
||||||
def execute(self, request):
|
def execute(self, request):
|
||||||
# get required arguments and register our own finish()
|
# get required arguments and register our own finish()
|
||||||
# with their finalization
|
# with their finalization
|
||||||
kwargs = {}
|
|
||||||
for argname in self.argnames:
|
for argname in self.argnames:
|
||||||
fixturedef = request._get_active_fixturedef(argname)
|
fixturedef = request._get_active_fixturedef(argname)
|
||||||
result, arg_cache_key, exc = fixturedef.cached_result
|
|
||||||
request._check_scope(argname, request.scope, fixturedef.scope)
|
|
||||||
kwargs[argname] = result
|
|
||||||
if argname != "request":
|
if argname != "request":
|
||||||
fixturedef.addfinalizer(self.finish)
|
fixturedef.addfinalizer(self.finish)
|
||||||
|
|
||||||
|
@ -2511,76 +2504,44 @@ class FixtureDef:
|
||||||
self.finish()
|
self.finish()
|
||||||
assert not hasattr(self, "cached_result")
|
assert not hasattr(self, "cached_result")
|
||||||
|
|
||||||
fixturefunc = self.func
|
ihook = self._fixturemanager.session.ihook
|
||||||
|
ihook.pytest_fixture_setup(fixturedef=self, request=request)
|
||||||
if self.unittest:
|
|
||||||
if request.instance is not None:
|
|
||||||
# bind the unbound method to the TestCase instance
|
|
||||||
fixturefunc = self.func.__get__(request.instance)
|
|
||||||
else:
|
|
||||||
# the fixture function needs to be bound to the actual
|
|
||||||
# request.instance so that code working with "self" behaves
|
|
||||||
# as expected.
|
|
||||||
if request.instance is not None:
|
|
||||||
fixturefunc = getimfunc(self.func)
|
|
||||||
if fixturefunc != self.func:
|
|
||||||
fixturefunc = fixturefunc.__get__(request.instance)
|
|
||||||
|
|
||||||
try:
|
|
||||||
config = request.config
|
|
||||||
if config.option.setupplan:
|
|
||||||
result = None
|
|
||||||
else:
|
|
||||||
result = call_fixture_func(fixturefunc, request, kwargs)
|
|
||||||
if config.option.setuponly or config.option.setupplan:
|
|
||||||
if hasattr(request, 'param'):
|
|
||||||
# Save the fixture parameter so ._show_fixture_action() can
|
|
||||||
# display it now and during the teardown (in .finish()).
|
|
||||||
if self.ids:
|
|
||||||
if callable(self.ids):
|
|
||||||
self.cached_param = self.ids(request.param)
|
|
||||||
else:
|
|
||||||
self.cached_param = self.ids[request.param_index]
|
|
||||||
else:
|
|
||||||
self.cached_param = request.param
|
|
||||||
self._show_fixture_action('SETUP')
|
|
||||||
except Exception:
|
|
||||||
self.cached_result = (None, my_cache_key, sys.exc_info())
|
|
||||||
raise
|
|
||||||
self.cached_result = (result, my_cache_key, None)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _show_fixture_action(self, what):
|
|
||||||
config = self._fixturemanager.config
|
|
||||||
capman = config.pluginmanager.getplugin('capturemanager')
|
|
||||||
if capman:
|
|
||||||
out, err = capman.suspendcapture()
|
|
||||||
|
|
||||||
tw = config.get_terminal_writer()
|
|
||||||
tw.line()
|
|
||||||
tw.write(' ' * 2 * self.scopenum)
|
|
||||||
tw.write('{step} {scope} {fixture}'.format(
|
|
||||||
step=what.ljust(8), # align the output to TEARDOWN
|
|
||||||
scope=self.scope[0].upper(),
|
|
||||||
fixture=self.argname))
|
|
||||||
|
|
||||||
if what == 'SETUP':
|
|
||||||
deps = sorted(arg for arg in self.argnames if arg != 'request')
|
|
||||||
if deps:
|
|
||||||
tw.write(' (fixtures used: {0})'.format(', '.join(deps)))
|
|
||||||
|
|
||||||
if hasattr(self, 'cached_param'):
|
|
||||||
tw.write('[{0}]'.format(self.cached_param))
|
|
||||||
|
|
||||||
if capman:
|
|
||||||
capman.resumecapture()
|
|
||||||
sys.stdout.write(out)
|
|
||||||
sys.stderr.write(err)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
|
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
|
||||||
(self.argname, self.scope, self.baseid))
|
(self.argname, self.scope, self.baseid))
|
||||||
|
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
""" Execution of fixture setup. """
|
||||||
|
kwargs = {}
|
||||||
|
for argname in fixturedef.argnames:
|
||||||
|
fixdef = request._get_active_fixturedef(argname)
|
||||||
|
result, arg_cache_key, exc = fixdef.cached_result
|
||||||
|
request._check_scope(argname, request.scope, fixdef.scope)
|
||||||
|
kwargs[argname] = result
|
||||||
|
|
||||||
|
fixturefunc = fixturedef.func
|
||||||
|
if fixturedef.unittest:
|
||||||
|
if request.instance is not None:
|
||||||
|
# bind the unbound method to the TestCase instance
|
||||||
|
fixturefunc = fixturedef.func.__get__(request.instance)
|
||||||
|
else:
|
||||||
|
# the fixture function needs to be bound to the actual
|
||||||
|
# request.instance so that code working with "fixturedef" behaves
|
||||||
|
# as expected.
|
||||||
|
if request.instance is not None:
|
||||||
|
fixturefunc = getimfunc(fixturedef.func)
|
||||||
|
if fixturefunc != fixturedef.func:
|
||||||
|
fixturefunc = fixturefunc.__get__(request.instance)
|
||||||
|
my_cache_key = request.param_index
|
||||||
|
try:
|
||||||
|
result = call_fixture_func(fixturefunc, request, kwargs)
|
||||||
|
except Exception:
|
||||||
|
fixturedef.cached_result = (None, my_cache_key, sys.exc_info())
|
||||||
|
raise
|
||||||
|
fixturedef.cached_result = (result, my_cache_key, None)
|
||||||
|
return result
|
||||||
|
|
||||||
def num_mock_patch_args(function):
|
def num_mock_patch_args(function):
|
||||||
""" return number of arguments used up by mock arguments (if any) """
|
""" return number of arguments used up by mock arguments (if any) """
|
||||||
patchings = getattr(function, "patchings", None)
|
patchings = getattr(function, "patchings", None)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import pytest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
yield
|
||||||
|
config = request.config
|
||||||
|
if config.option.setuponly:
|
||||||
|
if hasattr(request, 'param'):
|
||||||
|
# Save the fixture parameter so ._show_fixture_action() can
|
||||||
|
# display it now and during the teardown (in .finish()).
|
||||||
|
if fixturedef.ids:
|
||||||
|
if callable(fixturedef.ids):
|
||||||
|
fixturedef.cached_param = fixturedef.ids(request.param)
|
||||||
|
else:
|
||||||
|
fixturedef.cached_param = fixturedef.ids[request.param_index]
|
||||||
|
else:
|
||||||
|
fixturedef.cached_param = request.param
|
||||||
|
_show_fixture_action(fixturedef, 'SETUP')
|
||||||
|
|
||||||
|
def pytest_fixture_post_finalizer(fixturedef):
|
||||||
|
if hasattr(fixturedef, "cached_result"):
|
||||||
|
config = fixturedef._fixturemanager.config
|
||||||
|
if config.option.setuponly:
|
||||||
|
_show_fixture_action(fixturedef, 'TEARDOWN')
|
||||||
|
if hasattr(fixturedef, "cached_param"):
|
||||||
|
del fixturedef.cached_param
|
||||||
|
|
||||||
|
def _show_fixture_action(fixturedef, msg):
|
||||||
|
config = fixturedef._fixturemanager.config
|
||||||
|
capman = config.pluginmanager.getplugin('capturemanager')
|
||||||
|
if capman:
|
||||||
|
out, err = capman.suspendcapture()
|
||||||
|
|
||||||
|
tw = config.get_terminal_writer()
|
||||||
|
tw.line()
|
||||||
|
tw.write(' ' * 2 * fixturedef.scopenum)
|
||||||
|
tw.write('{step} {scope} {fixture}'.format(
|
||||||
|
step=msg.ljust(8), # align the output to TEARDOWN
|
||||||
|
scope=fixturedef.scope[0].upper(),
|
||||||
|
fixture=fixturedef.argname))
|
||||||
|
|
||||||
|
if msg == 'SETUP':
|
||||||
|
deps = sorted(arg for arg in fixturedef.argnames if arg != 'request')
|
||||||
|
if deps:
|
||||||
|
tw.write(' (fixtures used: {0})'.format(', '.join(deps)))
|
||||||
|
|
||||||
|
if hasattr(fixturedef, 'cached_param'):
|
||||||
|
tw.write('[{0}]'.format(fixturedef.cached_param))
|
||||||
|
|
||||||
|
if capman:
|
||||||
|
capman.resumecapture()
|
||||||
|
sys.stdout.write(out)
|
||||||
|
sys.stderr.write(err)
|
|
@ -0,0 +1,14 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.hookimpl(tryfirst=True)
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
# Will return a dummy fixture if the setuponly option is provided.
|
||||||
|
if request.config.option.setupplan:
|
||||||
|
fixturedef.cached_result = (None, None, None)
|
||||||
|
return fixturedef.cached_result
|
||||||
|
|
||||||
|
@pytest.hookimpl(tryfirst=True)
|
||||||
|
def pytest_cmdline_main(config):
|
||||||
|
if config.option.setupplan:
|
||||||
|
config.option.setuponly = True
|
Loading…
Reference in New Issue