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