Merge pull request #2292 from nicoddemus/defer-hook-checking
Verify hooks after collection completes
This commit is contained in:
commit
80cabca21a
|
@ -53,11 +53,16 @@ Changes
|
||||||
* Change exception raised by ``capture.DontReadFromInput.fileno()`` from ``ValueError``
|
* Change exception raised by ``capture.DontReadFromInput.fileno()`` from ``ValueError``
|
||||||
to ``io.UnsupportedOperation``. Thanks `@vlad-dragos`_ for the PR.
|
to ``io.UnsupportedOperation``. Thanks `@vlad-dragos`_ for the PR.
|
||||||
|
|
||||||
* fix `#2013`_: turn RecordedWarning into namedtupe,
|
* fix `#2013`_: turn RecordedWarning into ``namedtuple``,
|
||||||
to give it a comprehensible repr while preventing unwarranted modification
|
to give it a comprehensible repr while preventing unwarranted modification.
|
||||||
|
|
||||||
* fix `#2208`_: ensure a iteration limit for _pytest.compat.get_real_func.
|
* fix `#2208`_: ensure a iteration limit for _pytest.compat.get_real_func.
|
||||||
Thanks `@RonnyPfannschmidt`_ for the Report and PR
|
Thanks `@RonnyPfannschmidt`_ for the report and PR.
|
||||||
|
|
||||||
|
* Hooks are now verified after collection is complete, rather than right after loading installed plugins. This
|
||||||
|
makes it easy to write hooks for plugins which will be loaded during collection, for example using the
|
||||||
|
``pytest_plugins`` special variable (`#1821`_).
|
||||||
|
Thanks `@nicoddemus`_ for the PR.
|
||||||
|
|
||||||
* Modify ``pytest_make_parametrize_id()`` hook to accept ``argname`` as an
|
* Modify ``pytest_make_parametrize_id()`` hook to accept ``argname`` as an
|
||||||
additional parameter.
|
additional parameter.
|
||||||
|
@ -96,6 +101,7 @@ Bug Fixes
|
||||||
|
|
||||||
.. _#1407: https://github.com/pytest-dev/pytest/issues/1407
|
.. _#1407: https://github.com/pytest-dev/pytest/issues/1407
|
||||||
.. _#1512: https://github.com/pytest-dev/pytest/issues/1512
|
.. _#1512: https://github.com/pytest-dev/pytest/issues/1512
|
||||||
|
.. _#1821: https://github.com/pytest-dev/pytest/issues/1821
|
||||||
.. _#1874: https://github.com/pytest-dev/pytest/pull/1874
|
.. _#1874: https://github.com/pytest-dev/pytest/pull/1874
|
||||||
.. _#1952: https://github.com/pytest-dev/pytest/pull/1952
|
.. _#1952: https://github.com/pytest-dev/pytest/pull/1952
|
||||||
.. _#2007: https://github.com/pytest-dev/pytest/issues/2007
|
.. _#2007: https://github.com/pytest-dev/pytest/issues/2007
|
||||||
|
|
|
@ -54,7 +54,6 @@ def main(args=None, plugins=None):
|
||||||
return 4
|
return 4
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
config.pluginmanager.check_pending()
|
|
||||||
return config.hook.pytest_cmdline_main(config=config)
|
return config.hook.pytest_cmdline_main(config=config)
|
||||||
finally:
|
finally:
|
||||||
config._ensure_unconfigure()
|
config._ensure_unconfigure()
|
||||||
|
|
|
@ -309,9 +309,6 @@ class Node(object):
|
||||||
fslocation = getattr(self, "location", None)
|
fslocation = getattr(self, "location", None)
|
||||||
if fslocation is None:
|
if fslocation is None:
|
||||||
fslocation = getattr(self, "fspath", None)
|
fslocation = getattr(self, "fspath", None)
|
||||||
else:
|
|
||||||
fslocation = "%s:%s" % (fslocation[0], fslocation[1] + 1)
|
|
||||||
|
|
||||||
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
|
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
|
||||||
code=code, message=message,
|
code=code, message=message,
|
||||||
nodeid=self.nodeid, fslocation=fslocation))
|
nodeid=self.nodeid, fslocation=fslocation))
|
||||||
|
@ -596,6 +593,7 @@ class Session(FSCollector):
|
||||||
hook = self.config.hook
|
hook = self.config.hook
|
||||||
try:
|
try:
|
||||||
items = self._perform_collect(args, genitems)
|
items = self._perform_collect(args, genitems)
|
||||||
|
self.config.pluginmanager.check_pending()
|
||||||
hook.pytest_collection_modifyitems(session=self,
|
hook.pytest_collection_modifyitems(session=self,
|
||||||
config=self.config, items=items)
|
config=self.config, items=items)
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -88,7 +88,7 @@ class LsofFdLeakChecker(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
def pytest_runtest_item(self, item):
|
def pytest_runtest_protocol(self, item):
|
||||||
lines1 = self.get_open_files()
|
lines1 = self.get_open_files()
|
||||||
yield
|
yield
|
||||||
if hasattr(sys, "pypy_version_info"):
|
if hasattr(sys, "pypy_version_info"):
|
||||||
|
@ -107,7 +107,8 @@ class LsofFdLeakChecker(object):
|
||||||
error.extend([str(f) for f in lines2])
|
error.extend([str(f) for f in lines2])
|
||||||
error.append(error[0])
|
error.append(error[0])
|
||||||
error.append("*** function %s:%s: %s " % item.location)
|
error.append("*** function %s:%s: %s " % item.location)
|
||||||
pytest.fail("\n".join(error), pytrace=False)
|
error.append("See issue #2366")
|
||||||
|
item.warn('', "\n".join(error))
|
||||||
|
|
||||||
|
|
||||||
# XXX copied from execnet's conftest.py - needs to be merged
|
# XXX copied from execnet's conftest.py - needs to be merged
|
||||||
|
|
|
@ -109,10 +109,10 @@ class WarningReport(object):
|
||||||
if self.nodeid:
|
if self.nodeid:
|
||||||
return self.nodeid
|
return self.nodeid
|
||||||
if self.fslocation:
|
if self.fslocation:
|
||||||
if isinstance(self.fslocation, tuple) and len(self.fslocation) == 2:
|
if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2:
|
||||||
filename, linenum = self.fslocation
|
filename, linenum = self.fslocation[:2]
|
||||||
relpath = py.path.local(filename).relto(config.invocation_dir)
|
relpath = py.path.local(filename).relto(config.invocation_dir)
|
||||||
return '%s:%d' % (relpath, linenum)
|
return '%s:%s' % (relpath, linenum)
|
||||||
else:
|
else:
|
||||||
return str(self.fslocation)
|
return str(self.fslocation)
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -807,3 +807,31 @@ def test_import_plugin_unicode_name(testdir):
|
||||||
""")
|
""")
|
||||||
r = testdir.runpytest()
|
r = testdir.runpytest()
|
||||||
assert r.ret == 0
|
assert r.ret == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_deferred_hook_checking(testdir):
|
||||||
|
"""
|
||||||
|
Check hooks as late as possible (#1821).
|
||||||
|
"""
|
||||||
|
testdir.syspathinsert()
|
||||||
|
testdir.makepyfile(**{
|
||||||
|
'plugin.py': """
|
||||||
|
class Hooks:
|
||||||
|
def pytest_my_hook(self, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
config.pluginmanager.add_hookspecs(Hooks)
|
||||||
|
""",
|
||||||
|
'conftest.py': """
|
||||||
|
pytest_plugins = ['plugin']
|
||||||
|
def pytest_my_hook(config):
|
||||||
|
return 40
|
||||||
|
""",
|
||||||
|
'test_foo.py': """
|
||||||
|
def test(request):
|
||||||
|
assert request.config.hook.pytest_my_hook(config=request.config) == [40]
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(['* 1 passed *'])
|
||||||
|
|
|
@ -33,7 +33,7 @@ def test_hookvalidation_unknown(testdir):
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
assert result.ret != 0
|
assert result.ret != 0
|
||||||
result.stderr.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
'*unknown hook*pytest_hello*'
|
'*unknown hook*pytest_hello*'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue