Merge pull request #2127 from malinoff/fix-2124
Use session.config.hook instead of ihook. Fixes #2124
This commit is contained in:
commit
685387a43e
|
@ -1,13 +1,15 @@
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
import attr
|
||||||
import py
|
import py
|
||||||
from py._code.code import FormattedExcinfo
|
from py._code.code import FormattedExcinfo
|
||||||
|
|
||||||
import attr
|
|
||||||
import _pytest
|
import _pytest
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
|
@ -22,9 +24,6 @@ from _pytest.compat import (
|
||||||
from _pytest.outcomes import fail, TEST_OUTCOME
|
from _pytest.outcomes import fail, TEST_OUTCOME
|
||||||
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_sessionstart(session):
|
def pytest_sessionstart(session):
|
||||||
import _pytest.python
|
import _pytest.python
|
||||||
|
|
||||||
|
@ -519,7 +518,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
val = fixturedef.execute(request=subrequest)
|
val = fixturedef.execute(request=subrequest)
|
||||||
finally:
|
finally:
|
||||||
# if fixture function failed it might have registered finalizers
|
# if fixture function failed it might have registered finalizers
|
||||||
self.session._setupstate.addfinalizer(fixturedef.finish,
|
self.session._setupstate.addfinalizer(functools.partial(fixturedef.finish, request=subrequest),
|
||||||
subrequest.node)
|
subrequest.node)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
@ -573,7 +572,6 @@ class SubRequest(FixtureRequest):
|
||||||
self.param_index = param_index
|
self.param_index = param_index
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
self._fixturedef = fixturedef
|
self._fixturedef = fixturedef
|
||||||
self.addfinalizer = fixturedef.addfinalizer
|
|
||||||
self._pyfuncitem = request._pyfuncitem
|
self._pyfuncitem = request._pyfuncitem
|
||||||
self._fixture_values = request._fixture_values
|
self._fixture_values = request._fixture_values
|
||||||
self._fixture_defs = request._fixture_defs
|
self._fixture_defs = request._fixture_defs
|
||||||
|
@ -584,6 +582,9 @@ class SubRequest(FixtureRequest):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
|
return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
|
||||||
|
|
||||||
|
def addfinalizer(self, finalizer):
|
||||||
|
self._fixturedef.addfinalizer(finalizer)
|
||||||
|
|
||||||
|
|
||||||
class ScopeMismatchError(Exception):
|
class ScopeMismatchError(Exception):
|
||||||
""" A fixture function tries to use a different fixture function which
|
""" A fixture function tries to use a different fixture function which
|
||||||
|
@ -734,17 +735,17 @@ class FixtureDef:
|
||||||
self.argnames = getfuncargnames(func, is_method=unittest)
|
self.argnames = getfuncargnames(func, is_method=unittest)
|
||||||
self.unittest = unittest
|
self.unittest = unittest
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
self._finalizer = []
|
self._finalizers = []
|
||||||
|
|
||||||
def addfinalizer(self, finalizer):
|
def addfinalizer(self, finalizer):
|
||||||
self._finalizer.append(finalizer)
|
self._finalizers.append(finalizer)
|
||||||
|
|
||||||
def finish(self):
|
def finish(self, request):
|
||||||
exceptions = []
|
exceptions = []
|
||||||
try:
|
try:
|
||||||
while self._finalizer:
|
while self._finalizers:
|
||||||
try:
|
try:
|
||||||
func = self._finalizer.pop()
|
func = self._finalizers.pop()
|
||||||
func()
|
func()
|
||||||
except: # noqa
|
except: # noqa
|
||||||
exceptions.append(sys.exc_info())
|
exceptions.append(sys.exc_info())
|
||||||
|
@ -754,12 +755,15 @@ class FixtureDef:
|
||||||
py.builtin._reraise(*e)
|
py.builtin._reraise(*e)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
ihook = self._fixturemanager.session.ihook
|
hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
|
||||||
ihook.pytest_fixture_post_finalizer(fixturedef=self)
|
hook.pytest_fixture_post_finalizer(fixturedef=self, request=request)
|
||||||
# even if finalization fails, we invalidate
|
# even if finalization fails, we invalidate
|
||||||
# the cached fixture value
|
# the cached fixture value and remove
|
||||||
|
# all finalizers because they may be bound methods which will
|
||||||
|
# keep instances alive
|
||||||
if hasattr(self, "cached_result"):
|
if hasattr(self, "cached_result"):
|
||||||
del self.cached_result
|
del self.cached_result
|
||||||
|
self._finalizers = []
|
||||||
|
|
||||||
def execute(self, request):
|
def execute(self, request):
|
||||||
# get required arguments and register our own finish()
|
# get required arguments and register our own finish()
|
||||||
|
@ -767,7 +771,7 @@ class FixtureDef:
|
||||||
for argname in self.argnames:
|
for argname in self.argnames:
|
||||||
fixturedef = request._get_active_fixturedef(argname)
|
fixturedef = request._get_active_fixturedef(argname)
|
||||||
if argname != "request":
|
if argname != "request":
|
||||||
fixturedef.addfinalizer(self.finish)
|
fixturedef.addfinalizer(functools.partial(self.finish, request=request))
|
||||||
|
|
||||||
my_cache_key = request.param_index
|
my_cache_key = request.param_index
|
||||||
cached_result = getattr(self, "cached_result", None)
|
cached_result = getattr(self, "cached_result", None)
|
||||||
|
@ -780,11 +784,11 @@ class FixtureDef:
|
||||||
return result
|
return result
|
||||||
# we have a previous but differently parametrized fixture instance
|
# we have a previous but differently parametrized fixture instance
|
||||||
# so we need to tear it down before creating a new one
|
# so we need to tear it down before creating a new one
|
||||||
self.finish()
|
self.finish(request)
|
||||||
assert not hasattr(self, "cached_result")
|
assert not hasattr(self, "cached_result")
|
||||||
|
|
||||||
ihook = self._fixturemanager.session.ihook
|
hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
|
||||||
return ihook.pytest_fixture_setup(fixturedef=self, request=request)
|
return hook.pytest_fixture_setup(fixturedef=self, request=request)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
|
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
|
||||||
|
|
|
@ -296,7 +296,7 @@ def pytest_fixture_setup(fixturedef, request):
|
||||||
Stops at first non-None result, see :ref:`firstresult` """
|
Stops at first non-None result, see :ref:`firstresult` """
|
||||||
|
|
||||||
|
|
||||||
def pytest_fixture_post_finalizer(fixturedef):
|
def pytest_fixture_post_finalizer(fixturedef, request):
|
||||||
""" called after fixture teardown, but before the cache is cleared so
|
""" called after fixture teardown, but before the cache is cleared so
|
||||||
the fixture result cache ``fixturedef.cached_result`` can
|
the fixture result cache ``fixturedef.cached_result`` can
|
||||||
still be accessed."""
|
still be accessed."""
|
||||||
|
|
|
@ -499,8 +499,16 @@ class FSCollector(Collector):
|
||||||
super(FSCollector, self).__init__(name, parent, config, session)
|
super(FSCollector, self).__init__(name, parent, config, session)
|
||||||
self.fspath = fspath
|
self.fspath = fspath
|
||||||
|
|
||||||
|
def _check_initialpaths_for_relpath(self):
|
||||||
|
for initialpath in self.session._initialpaths:
|
||||||
|
if self.fspath.common(initialpath) == initialpath:
|
||||||
|
return self.fspath.relto(initialpath.dirname)
|
||||||
|
|
||||||
def _makeid(self):
|
def _makeid(self):
|
||||||
relpath = self.fspath.relto(self.config.rootdir)
|
relpath = self.fspath.relto(self.config.rootdir)
|
||||||
|
|
||||||
|
if not relpath:
|
||||||
|
relpath = self._check_initialpaths_for_relpath()
|
||||||
if os.sep != nodes.SEP:
|
if os.sep != nodes.SEP:
|
||||||
relpath = relpath.replace(os.sep, nodes.SEP)
|
relpath = relpath.replace(os.sep, nodes.SEP)
|
||||||
return relpath
|
return relpath
|
||||||
|
|
|
@ -56,11 +56,6 @@ def pytest_sessionfinish(session):
|
||||||
session._setupstate.teardown_all()
|
session._setupstate.teardown_all()
|
||||||
|
|
||||||
|
|
||||||
class NodeInfo:
|
|
||||||
def __init__(self, location):
|
|
||||||
self.location = location
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_runtest_protocol(item, nextitem):
|
def pytest_runtest_protocol(item, nextitem):
|
||||||
item.ihook.pytest_runtest_logstart(
|
item.ihook.pytest_runtest_logstart(
|
||||||
nodeid=item.nodeid, location=item.location,
|
nodeid=item.nodeid, location=item.location,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now called for all ``conftest.py`` files.
|
|
@ -0,0 +1 @@
|
||||||
|
``pytest_fixture_post_finalizer`` hook can now receive a ``request`` argument.
|
|
@ -0,0 +1 @@
|
||||||
|
Fix the bug where running pytest with "--pyargs" will result in Items with empty "parent.nodeid" if run from a different root directory.
|
|
@ -624,8 +624,10 @@ class TestInvocationVariants(object):
|
||||||
for p in search_path:
|
for p in search_path:
|
||||||
monkeypatch.syspath_prepend(p)
|
monkeypatch.syspath_prepend(p)
|
||||||
|
|
||||||
|
os.chdir('world')
|
||||||
# mixed module and filenames:
|
# mixed module and filenames:
|
||||||
result = testdir.runpytest("--pyargs", "-v", "ns_pkg.hello", "world/ns_pkg")
|
result = testdir.runpytest("--pyargs", "-v", "ns_pkg.hello", "ns_pkg/world")
|
||||||
|
testdir.chdir()
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*test_hello.py::test_hello*PASSED",
|
"*test_hello.py::test_hello*PASSED",
|
||||||
|
|
|
@ -3121,3 +3121,43 @@ class TestParameterizedSubRequest(object):
|
||||||
E*{1}:5
|
E*{1}:5
|
||||||
*1 failed*
|
*1 failed*
|
||||||
""".format(fixfile.strpath, testfile.basename))
|
""".format(fixfile.strpath, testfile.basename))
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_fixture_setup_and_post_finalizer_hook(testdir):
|
||||||
|
testdir.makeconftest("""
|
||||||
|
from __future__ import print_function
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
print('ROOT setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name))
|
||||||
|
def pytest_fixture_post_finalizer(fixturedef, request):
|
||||||
|
print('ROOT finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name))
|
||||||
|
""")
|
||||||
|
testdir.makepyfile(**{
|
||||||
|
'tests/conftest.py': """
|
||||||
|
from __future__ import print_function
|
||||||
|
def pytest_fixture_setup(fixturedef, request):
|
||||||
|
print('TESTS setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name))
|
||||||
|
def pytest_fixture_post_finalizer(fixturedef, request):
|
||||||
|
print('TESTS finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name))
|
||||||
|
""",
|
||||||
|
'tests/test_hooks.py': """
|
||||||
|
from __future__ import print_function
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def my_fixture():
|
||||||
|
return 'some'
|
||||||
|
|
||||||
|
def test_func(my_fixture):
|
||||||
|
print('TEST test_func')
|
||||||
|
assert my_fixture == 'some'
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
result = testdir.runpytest("-s")
|
||||||
|
assert result.ret == 0
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*TESTS setup hook called for my_fixture from test_func*",
|
||||||
|
"*ROOT setup hook called for my_fixture from test_func*",
|
||||||
|
"*TEST test_func*",
|
||||||
|
"*TESTS finalizer hook called for my_fixture from test_func*",
|
||||||
|
"*ROOT finalizer hook called for my_fixture from test_func*",
|
||||||
|
])
|
||||||
|
|
Loading…
Reference in New Issue