shift pytest_configure/unconfigure/addoption/namespace hook calling to config object.
The _pytest.config module itself is no longer a plugin but the actual config instance is plugin-registered as ``pytestconfig``. This allows to put most pytest specific logic to _pytest.config instead of in the core pluginmanager.
This commit is contained in:
parent
694c6fd0e7
commit
d946299b0a
|
@ -2,20 +2,6 @@
|
|||
|
||||
import py
|
||||
import sys, os
|
||||
import pytest
|
||||
|
||||
def pytest_cmdline_parse(pluginmanager, args):
|
||||
config = Config(pluginmanager)
|
||||
config.parse(args)
|
||||
return config
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
while 1:
|
||||
try:
|
||||
fin = config._cleanup.pop()
|
||||
except IndexError:
|
||||
break
|
||||
fin()
|
||||
|
||||
class Parser:
|
||||
""" Parser for command line arguments and ini-file values. """
|
||||
|
@ -507,13 +493,46 @@ class Config(object):
|
|||
self._inicache = {}
|
||||
self._opt2dest = {}
|
||||
self._cleanup = []
|
||||
self.pluginmanager.register(self, "pytestconfig")
|
||||
self._configured = False
|
||||
|
||||
def pytest_plugin_registered(self, plugin):
|
||||
call_plugin = self.pluginmanager.call_plugin
|
||||
dic = call_plugin(plugin, "pytest_namespace", {}) or {}
|
||||
if dic:
|
||||
import pytest
|
||||
setns(pytest, dic)
|
||||
call_plugin(plugin, "pytest_addoption", {'parser': self._parser})
|
||||
if self._configured:
|
||||
call_plugin(plugin, "pytest_configure", {'config': self})
|
||||
|
||||
def do_configure(self):
|
||||
assert not self._configured
|
||||
self._configured = True
|
||||
self.hook.pytest_configure(config=self)
|
||||
|
||||
def do_unconfigure(self):
|
||||
assert self._configured
|
||||
self._configured = False
|
||||
self.hook.pytest_unconfigure(config=self)
|
||||
self.pluginmanager.ensure_shutdown()
|
||||
|
||||
def pytest_cmdline_parse(self, pluginmanager, args):
|
||||
assert self == pluginmanager.config, (self, pluginmanager.config)
|
||||
self.parse(args)
|
||||
return self
|
||||
|
||||
def pytest_unconfigure(config):
|
||||
while config._cleanup:
|
||||
fin = config._cleanup.pop()
|
||||
fin()
|
||||
|
||||
@classmethod
|
||||
def fromdictargs(cls, option_dict, args):
|
||||
""" constructor useable for subprocesses. """
|
||||
from _pytest.core import get_plugin_manager
|
||||
pluginmanager = get_plugin_manager()
|
||||
config = cls(pluginmanager)
|
||||
config = pluginmanager.config
|
||||
# XXX slightly crude way to initialize capturing
|
||||
import _pytest.capture
|
||||
_pytest.capture.pytest_cmdline_parse(config.pluginmanager, args)
|
||||
|
@ -572,11 +591,11 @@ class Config(object):
|
|||
self.pluginmanager.consider_setuptools_entrypoints()
|
||||
self.pluginmanager.consider_env()
|
||||
self._setinitialconftest(args)
|
||||
self.pluginmanager.do_addoption(self._parser)
|
||||
if addopts:
|
||||
self.hook.pytest_cmdline_preparse(config=self, args=args)
|
||||
|
||||
def _checkversion(self):
|
||||
import pytest
|
||||
minver = self.inicfg.get('minversion', None)
|
||||
if minver:
|
||||
ver = minver.split(".")
|
||||
|
@ -723,3 +742,23 @@ def getcfg(args, inibasenames):
|
|||
return iniconfig['pytest']
|
||||
return {}
|
||||
|
||||
|
||||
def setns(obj, dic):
|
||||
import pytest
|
||||
for name, value in dic.items():
|
||||
if isinstance(value, dict):
|
||||
mod = getattr(obj, name, None)
|
||||
if mod is None:
|
||||
modname = "pytest.%s" % name
|
||||
mod = py.std.types.ModuleType(modname)
|
||||
sys.modules[modname] = mod
|
||||
mod.__all__ = []
|
||||
setattr(obj, name, mod)
|
||||
obj.__all__.append(name)
|
||||
setns(mod, value)
|
||||
else:
|
||||
setattr(obj, name, value)
|
||||
obj.__all__.append(name)
|
||||
#if obj != pytest:
|
||||
# pytest.__all__.append(name)
|
||||
setattr(pytest, name, value)
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
"""
|
||||
pytest PluginManager, basic initialization and tracing.
|
||||
(c) Holger Krekel 2004-2010
|
||||
"""
|
||||
import sys, os
|
||||
import inspect
|
||||
import py
|
||||
from _pytest import hookspec # the extension point definitions
|
||||
from _pytest.config import Config
|
||||
|
||||
assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: "
|
||||
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
||||
|
||||
default_plugins = (
|
||||
"config 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 "
|
||||
"junitxml resultlog doctest").split()
|
||||
|
||||
|
@ -91,6 +91,7 @@ class PluginManager(object):
|
|||
self.trace.root.setwriter(err.write)
|
||||
self.hook = HookRelay([hookspec], pm=self)
|
||||
self.register(self)
|
||||
self.config = Config(self) # XXX unclear if the attr is needed
|
||||
if load:
|
||||
for spec in default_plugins:
|
||||
self.import_plugin(spec)
|
||||
|
@ -100,7 +101,8 @@ class PluginManager(object):
|
|||
return
|
||||
name = name or getattr(plugin, '__name__', str(id(plugin)))
|
||||
if self.isregistered(plugin, name):
|
||||
raise ValueError("Plugin already registered: %s=%s" %(name, plugin))
|
||||
raise ValueError("Plugin already registered: %s=%s\n%s" %(
|
||||
name, plugin, self._name2plugin))
|
||||
#self.trace("registering", name, plugin)
|
||||
self._name2plugin[name] = plugin
|
||||
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
||||
|
@ -220,7 +222,6 @@ class PluginManager(object):
|
|||
if self.getplugin(modname) is not None:
|
||||
return
|
||||
try:
|
||||
#self.trace("importing", modname)
|
||||
mod = importplugin(modname)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
|
@ -247,59 +248,12 @@ class PluginManager(object):
|
|||
"trylast: mark a hook implementation function such that the "
|
||||
"plugin machinery will try to call it last/as late as possible.")
|
||||
|
||||
def pytest_plugin_registered(self, plugin):
|
||||
import pytest
|
||||
dic = self.call_plugin(plugin, "pytest_namespace", {}) or {}
|
||||
if dic:
|
||||
self._setns(pytest, dic)
|
||||
if hasattr(self, '_config'):
|
||||
self.call_plugin(plugin, "pytest_addoption",
|
||||
{'parser': self._config._parser})
|
||||
self.call_plugin(plugin, "pytest_configure",
|
||||
{'config': self._config})
|
||||
|
||||
def _setns(self, obj, dic):
|
||||
import pytest
|
||||
for name, value in dic.items():
|
||||
if isinstance(value, dict):
|
||||
mod = getattr(obj, name, None)
|
||||
if mod is None:
|
||||
modname = "pytest.%s" % name
|
||||
mod = py.std.types.ModuleType(modname)
|
||||
sys.modules[modname] = mod
|
||||
mod.__all__ = []
|
||||
setattr(obj, name, mod)
|
||||
obj.__all__.append(name)
|
||||
self._setns(mod, value)
|
||||
else:
|
||||
setattr(obj, name, value)
|
||||
obj.__all__.append(name)
|
||||
#if obj != pytest:
|
||||
# pytest.__all__.append(name)
|
||||
setattr(pytest, name, value)
|
||||
|
||||
def pytest_terminal_summary(self, terminalreporter):
|
||||
tw = terminalreporter._tw
|
||||
if terminalreporter.config.option.traceconfig:
|
||||
for hint in self._hints:
|
||||
tw.line("hint: %s" % hint)
|
||||
|
||||
def do_addoption(self, parser):
|
||||
mname = "pytest_addoption"
|
||||
methods = reversed(self.listattr(mname))
|
||||
MultiCall(methods, {'parser': parser}).execute()
|
||||
|
||||
def do_configure(self, config):
|
||||
assert not hasattr(self, '_config')
|
||||
self._config = config
|
||||
config.hook.pytest_configure(config=self._config)
|
||||
|
||||
def do_unconfigure(self, config):
|
||||
config = self._config
|
||||
del self._config
|
||||
config.hook.pytest_unconfigure(config=config)
|
||||
config.pluginmanager.ensure_shutdown()
|
||||
|
||||
def notify_exception(self, excinfo, option=None):
|
||||
if option and option.fulltrace:
|
||||
style = "long"
|
||||
|
@ -350,6 +304,7 @@ def importplugin(importspec):
|
|||
name = importspec
|
||||
try:
|
||||
mod = "_pytest." + name
|
||||
#print >>sys.stderr, "tryimport", mod
|
||||
__import__(mod)
|
||||
return sys.modules[mod]
|
||||
except ImportError:
|
||||
|
@ -358,6 +313,7 @@ def importplugin(importspec):
|
|||
# raise
|
||||
pass #
|
||||
try:
|
||||
#print >>sys.stderr, "tryimport", importspec
|
||||
__import__(importspec)
|
||||
except ImportError:
|
||||
raise ImportError(importspec)
|
||||
|
|
|
@ -54,9 +54,9 @@ def pytest_cmdline_main(config):
|
|||
sys.stderr.write(line + "\n")
|
||||
return 0
|
||||
elif config.option.help:
|
||||
config.pluginmanager.do_configure(config)
|
||||
config.do_configure()
|
||||
showhelp(config)
|
||||
config.pluginmanager.do_unconfigure(config)
|
||||
config.do_unconfigure()
|
||||
return 0
|
||||
|
||||
def showhelp(config):
|
||||
|
|
|
@ -76,7 +76,7 @@ def wrap_session(config, doit):
|
|||
initstate = 0
|
||||
try:
|
||||
try:
|
||||
config.pluginmanager.do_configure(config)
|
||||
config.do_configure()
|
||||
initstate = 1
|
||||
config.hook.pytest_sessionstart(session=session)
|
||||
initstate = 2
|
||||
|
@ -105,7 +105,7 @@ def wrap_session(config, doit):
|
|||
session=session,
|
||||
exitstatus=session.exitstatus)
|
||||
if initstate >= 1:
|
||||
config.pluginmanager.do_unconfigure(config)
|
||||
config.do_unconfigure()
|
||||
config.pluginmanager.ensure_shutdown()
|
||||
return session.exitstatus
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
""" generic mechanism for marking and selecting python functions. """
|
||||
import pytest, py
|
||||
import py
|
||||
|
||||
|
||||
def pytest_namespace():
|
||||
|
@ -39,14 +39,14 @@ def pytest_addoption(parser):
|
|||
|
||||
def pytest_cmdline_main(config):
|
||||
if config.option.markers:
|
||||
config.pluginmanager.do_configure(config)
|
||||
config.do_configure()
|
||||
tw = py.io.TerminalWriter()
|
||||
for line in config.getini("markers"):
|
||||
name, rest = line.split(":", 1)
|
||||
tw.write("@pytest.mark.%s:" % name, bold=True)
|
||||
tw.line(rest)
|
||||
tw.line()
|
||||
config.pluginmanager.do_unconfigure(config)
|
||||
config.do_unconfigure()
|
||||
return 0
|
||||
pytest_cmdline_main.tryfirst = True
|
||||
|
||||
|
@ -129,6 +129,7 @@ def matchkeyword(colitem, keywordexpr):
|
|||
mapped_names = set()
|
||||
|
||||
# Add the names of the current item and any parent items
|
||||
import pytest
|
||||
for item in colitem.listchain():
|
||||
if not isinstance(item, pytest.Instance):
|
||||
mapped_names.add(item.name)
|
||||
|
@ -145,6 +146,7 @@ def matchkeyword(colitem, keywordexpr):
|
|||
|
||||
|
||||
def pytest_configure(config):
|
||||
import pytest
|
||||
if config.option.strict:
|
||||
pytest.mark._config = config
|
||||
|
||||
|
|
|
@ -390,9 +390,9 @@ class TmpTestdir:
|
|||
|
||||
def parseconfigure(self, *args):
|
||||
config = self.parseconfig(*args)
|
||||
config.pluginmanager.do_configure(config)
|
||||
config.do_configure()
|
||||
self.request.addfinalizer(lambda:
|
||||
config.pluginmanager.do_unconfigure(config))
|
||||
config.do_unconfigure())
|
||||
return config
|
||||
|
||||
def getitem(self, source, funcname="test_func"):
|
||||
|
|
|
@ -261,13 +261,13 @@ class TestBootstrapping:
|
|||
assert pm.getplugins()
|
||||
my2 = MyPlugin()
|
||||
pm.register(my2)
|
||||
assert pm.getplugins()[1:] == [my, my2]
|
||||
assert pm.getplugins()[2:] == [my, my2]
|
||||
|
||||
assert pm.isregistered(my)
|
||||
assert pm.isregistered(my2)
|
||||
pm.unregister(my)
|
||||
assert not pm.isregistered(my)
|
||||
assert pm.getplugins()[1:] == [my2]
|
||||
assert pm.getplugins()[2:] == [my2]
|
||||
|
||||
def test_listattr(self):
|
||||
plugins = PluginManager()
|
||||
|
@ -319,7 +319,7 @@ class TestPytestPluginInteractions:
|
|||
def pytest_myhook(xyz):
|
||||
return xyz + 1
|
||||
""")
|
||||
config = testdir.Config(PluginManager(load=True))
|
||||
config = PluginManager(load=True).config
|
||||
config._conftest.importconftest(conf)
|
||||
print(config.pluginmanager.getplugins())
|
||||
res = config.hook.pytest_myhook(xyz=10)
|
||||
|
@ -383,13 +383,13 @@ class TestPytestPluginInteractions:
|
|||
|
||||
config.pluginmanager.register(A())
|
||||
assert len(l) == 0
|
||||
config.pluginmanager.do_configure(config=config)
|
||||
config.do_configure()
|
||||
assert len(l) == 1
|
||||
config.pluginmanager.register(A()) # leads to a configured() plugin
|
||||
assert len(l) == 2
|
||||
assert l[0] != l[1]
|
||||
|
||||
config.pluginmanager.do_unconfigure(config=config)
|
||||
config.do_unconfigure()
|
||||
config.pluginmanager.register(A())
|
||||
assert len(l) == 2
|
||||
|
||||
|
|
|
@ -208,13 +208,14 @@ def test_plugin_specify(testdir):
|
|||
testdir.parseconfig("-p", "nqweotexistent")
|
||||
""")
|
||||
#pytest.raises(ImportError,
|
||||
# "config.pluginmanager.do_configure(config)"
|
||||
# "config.do_configure(config)"
|
||||
#)
|
||||
|
||||
def test_plugin_already_exists(testdir):
|
||||
config = testdir.parseconfig("-p", "terminal")
|
||||
assert config.option.plugins == ['terminal']
|
||||
config.pluginmanager.do_configure(config)
|
||||
config.do_configure()
|
||||
config.do_unconfigure()
|
||||
|
||||
def test_exclude(testdir):
|
||||
hellodir = testdir.mkdir("hello")
|
||||
|
|
Loading…
Reference in New Issue