diff --git a/_pytest/config.py b/_pytest/config.py index 5b17d7327..e1bc474cf 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -9,7 +9,10 @@ import py # DON't import pytest here because it causes import cycle troubles import sys, os from _pytest import hookspec # the extension point definitions -from pluggy import PluginManager, hookimpl_opts, varnames +from pluggy import PluginManager, Hookimpl, Hookspec + +hookimpl_opts = Hookimpl("pytest") +hookspec_opts = Hookspec("pytest") # pytest startup # @@ -106,10 +109,10 @@ def exclude_pytest_names(name): name.startswith("pytest_funcarg__") + class PytestPluginManager(PluginManager): def __init__(self): - super(PytestPluginManager, self).__init__(prefix="pytest_", - excludefunc=exclude_pytest_names) + super(PytestPluginManager, self).__init__("pytest") self._warnings = [] self._conftest_plugins = set() @@ -130,12 +133,31 @@ class PytestPluginManager(PluginManager): self.trace.root.setwriter(err.write) self.enable_tracing() + def get_hookimpl_opts(self, plugin, name): + method = getattr(plugin, name) + opts = super(PytestPluginManager, self).get_hookimpl_opts(plugin, name) + if opts is None: + if name.startswith("pytest_") and not exclude_pytest_names(name): + opts = {} + opts["tryfirst"] = hasattr(method, "tryfirst") + opts["trylast"] = hasattr(method, "trylast") + opts["optionalhook"] = hasattr(method, "optionalhook") + opts["hookwrapper"] = hasattr(method, "hookwrapper") + return opts - def _verify_hook(self, hook, plugin): - super(PytestPluginManager, self)._verify_hook(hook, plugin) - method = getattr(plugin, hook.name) - if "__multicall__" in varnames(method): - fslineno = py.code.getfslineno(method) + def get_hookspec_opts(self, module_or_class, name): + opts = super(PytestPluginManager, self).get_hookspec_opts(module_or_class, name) + if opts is None: + if name.startswith("pytest_"): + meth = getattr(module_or_class, name) + opts = {"firstresult": hasattr(meth, "firstresult"), + "historic": hasattr(meth, "historic")} + return opts + + def _verify_hook(self, hook, hookmethod): + super(PytestPluginManager, self)._verify_hook(hook, hookmethod) + if "__multicall__" in hookmethod.argnames: + fslineno = py.code.getfslineno(hookmethod.function) warning = dict(code="I1", fslocation=fslineno, message="%r hook uses deprecated __multicall__ " diff --git a/_pytest/genscript.py b/_pytest/genscript.py index 32186cc10..15b6841b1 100755 --- a/_pytest/genscript.py +++ b/_pytest/genscript.py @@ -70,7 +70,7 @@ def pytest_cmdline_main(config): genscript = config.getvalue("genscript") if genscript: tw = py.io.TerminalWriter() - deps = ['py', '_pytest', 'pytest', 'pluggy'] + deps = ['py', 'pluggy', '_pytest', 'pytest'] if sys.version_info < (2,7): deps.append("argparse") tw.line("generated script will run on python2.6-python3.3++") diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py index 0438b9072..938a8bb7f 100644 --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -1,6 +1,8 @@ """ hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ -from pluggy import hookspec_opts +from pluggy import Hookspec + +hookspec_opts = Hookspec("pytest") # ------------------------------------------------------------------------- # Initialization hooks called for every plugin diff --git a/_pytest/main.py b/_pytest/main.py index 737b7f20a..55ba78b5f 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -501,13 +501,13 @@ class Session(FSCollector): def __init__(self, config): FSCollector.__init__(self, config.rootdir, parent=None, config=config, session=self) - self.config.pluginmanager.register(self, name="session") + self._fs2hookproxy = {} self._testsfailed = 0 self.shouldstop = False self.trace = config.trace.root.get("collection") self._norecursepatterns = config.getini("norecursedirs") self.startdir = py.path.local() - self._fs2hookproxy = {} + self.config.pluginmanager.register(self, name="session") def _makeid(self): return "" diff --git a/pytest.py b/pytest.py index 9ea6d63ed..b72563dfb 100644 --- a/pytest.py +++ b/pytest.py @@ -11,8 +11,10 @@ if __name__ == '__main__': # if run as a script or by 'python -m pytest' # else we are imported -from _pytest.config import main, UsageError, _preloadplugins, cmdline -from pluggy import hookspec_opts, hookimpl_opts +from _pytest.config import ( + main, UsageError, _preloadplugins, cmdline, + hookspec_opts, hookimpl_opts +) from _pytest import __version__ _preloadplugins() # to populate pytest.* namespace so help(pytest) works diff --git a/testing/test_config.py b/testing/test_config.py index c79de8480..73dd6412d 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -357,9 +357,9 @@ def test_load_initial_conftest_last_ordering(testdir): pm.register(m) hc = pm.hook.pytest_load_initial_conftests l = hc._nonwrappers + hc._wrappers - assert l[-1].__module__ == "_pytest.capture" - assert l[-2] == m.pytest_load_initial_conftests - assert l[-3].__module__ == "_pytest.config" + assert l[-1].function.__module__ == "_pytest.capture" + assert l[-2].function == m.pytest_load_initial_conftests + assert l[-3].function.__module__ == "_pytest.config" class TestWarning: def test_warn_config(self, testdir):