2009-02-27 18:18:27 +08:00
|
|
|
"""
|
2009-04-09 22:34:53 +08:00
|
|
|
managing loading and interacting with pytest plugins.
|
2009-02-27 18:18:27 +08:00
|
|
|
"""
|
|
|
|
import py
|
2009-04-08 04:46:50 +08:00
|
|
|
from py.__.test.plugin import api
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-05-19 05:26:16 +08:00
|
|
|
def check_old_use(mod, modname):
|
|
|
|
clsname = modname[len('pytest_'):].capitalize() + "Plugin"
|
|
|
|
assert not hasattr(mod, clsname), (mod, clsname)
|
|
|
|
|
2009-04-09 22:03:09 +08:00
|
|
|
class PluginManager(object):
|
|
|
|
def __init__(self, comregistry=None):
|
|
|
|
if comregistry is None:
|
|
|
|
comregistry = py._com.Registry()
|
|
|
|
self.comregistry = comregistry
|
|
|
|
self.MultiCall = self.comregistry.MultiCall
|
2009-04-09 22:34:53 +08:00
|
|
|
self.impname2plugin = {}
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-05-08 00:01:53 +08:00
|
|
|
self.hook = py._com.Hooks(
|
|
|
|
hookspecs=api.PluginHooks,
|
2009-04-09 22:34:53 +08:00
|
|
|
registry=self.comregistry)
|
2009-04-08 04:46:50 +08:00
|
|
|
|
2009-05-20 01:25:21 +08:00
|
|
|
def _getpluginname(self, plugin, name):
|
2009-05-19 05:26:16 +08:00
|
|
|
if name is None:
|
2009-05-20 01:25:21 +08:00
|
|
|
if hasattr(plugin, '__name__'):
|
|
|
|
name = plugin.__name__.split(".")[-1]
|
|
|
|
else:
|
|
|
|
name = id(plugin)
|
|
|
|
return name
|
|
|
|
|
|
|
|
def register(self, plugin, name=None):
|
|
|
|
assert not self.isregistered(plugin)
|
|
|
|
name = self._getpluginname(plugin, name)
|
|
|
|
assert name not in self.impname2plugin
|
|
|
|
self.impname2plugin[name] = plugin
|
|
|
|
self.hook.pytest_plugin_registered(plugin=plugin)
|
|
|
|
self.comregistry.register(plugin)
|
|
|
|
return True
|
2009-04-09 23:03:58 +08:00
|
|
|
|
2009-02-27 18:18:27 +08:00
|
|
|
def unregister(self, plugin):
|
2009-05-08 00:01:53 +08:00
|
|
|
self.hook.pytest_plugin_unregistered(plugin=plugin)
|
2009-04-09 22:03:09 +08:00
|
|
|
self.comregistry.unregister(plugin)
|
2009-05-19 05:26:16 +08:00
|
|
|
for name, value in self.impname2plugin.items():
|
|
|
|
if value == plugin:
|
|
|
|
del self.impname2plugin[name]
|
2009-04-09 23:03:58 +08:00
|
|
|
|
2009-05-20 01:25:21 +08:00
|
|
|
def isregistered(self, plugin, name=None):
|
|
|
|
return self._getpluginname(plugin, name) in self.impname2plugin
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def getplugins(self):
|
2009-04-09 22:34:53 +08:00
|
|
|
return list(self.comregistry)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
# API for bootstrapping
|
|
|
|
#
|
|
|
|
def getplugin(self, importname):
|
2009-05-19 05:26:16 +08:00
|
|
|
impname = canonical_importname(importname)
|
2009-04-09 22:34:53 +08:00
|
|
|
return self.impname2plugin[impname]
|
2009-04-09 22:21:07 +08:00
|
|
|
|
|
|
|
def _envlist(self, varname):
|
|
|
|
val = py.std.os.environ.get(varname, None)
|
|
|
|
if val is not None:
|
|
|
|
return val.split(',')
|
|
|
|
return ()
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def consider_env(self):
|
2009-04-09 22:21:07 +08:00
|
|
|
for spec in self._envlist("PYTEST_PLUGINS"):
|
2009-02-27 18:18:27 +08:00
|
|
|
self.import_plugin(spec)
|
|
|
|
|
2009-04-18 02:09:29 +08:00
|
|
|
def consider_preparse(self, args):
|
|
|
|
for opt1,opt2 in zip(args, args[1:]):
|
|
|
|
if opt1 == "-p":
|
|
|
|
self.import_plugin(opt2)
|
|
|
|
|
2009-02-27 18:18:27 +08:00
|
|
|
def consider_conftest(self, conftestmodule):
|
|
|
|
cls = getattr(conftestmodule, 'ConftestPlugin', None)
|
2009-05-19 05:26:16 +08:00
|
|
|
if cls is not None:
|
|
|
|
raise ValueError("%r: 'ConftestPlugins' only existed till 1.0.0b1, "
|
|
|
|
"were removed in 1.0.0b2" % (cls,))
|
|
|
|
if self.register(conftestmodule, name=conftestmodule.__file__):
|
|
|
|
self.consider_module(conftestmodule)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def consider_module(self, mod):
|
|
|
|
attr = getattr(mod, "pytest_plugins", ())
|
|
|
|
if attr:
|
|
|
|
if not isinstance(attr, (list, tuple)):
|
|
|
|
attr = (attr,)
|
|
|
|
for spec in attr:
|
|
|
|
self.import_plugin(spec)
|
|
|
|
|
|
|
|
def import_plugin(self, spec):
|
|
|
|
assert isinstance(spec, str)
|
2009-05-19 05:26:16 +08:00
|
|
|
modname = canonical_importname(spec)
|
2009-04-09 22:34:53 +08:00
|
|
|
if modname in self.impname2plugin:
|
2009-02-27 18:18:27 +08:00
|
|
|
return
|
|
|
|
mod = importplugin(modname)
|
2009-05-19 05:26:16 +08:00
|
|
|
check_old_use(mod, modname)
|
2009-05-20 01:25:21 +08:00
|
|
|
self.register(mod)
|
2009-02-27 18:18:27 +08:00
|
|
|
self.consider_module(mod)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# API for interacting with registered and instantiated plugin objects
|
|
|
|
#
|
|
|
|
#
|
|
|
|
def getfirst(self, attrname):
|
2009-04-09 22:03:09 +08:00
|
|
|
for x in self.comregistry.listattr(attrname):
|
2009-02-27 18:18:27 +08:00
|
|
|
return x
|
|
|
|
|
2009-04-14 08:23:42 +08:00
|
|
|
def listattr(self, attrname, plugins=None, extra=()):
|
|
|
|
return self.comregistry.listattr(attrname, plugins=plugins, extra=extra)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-04-03 22:18:47 +08:00
|
|
|
def notify_exception(self, excinfo=None):
|
|
|
|
if excinfo is None:
|
|
|
|
excinfo = py.code.ExceptionInfo()
|
|
|
|
excrepr = excinfo.getrepr(funcargs=True, showlocals=True)
|
2009-05-08 00:01:53 +08:00
|
|
|
return self.hook.pytest_internalerror(excrepr=excrepr)
|
2009-04-03 22:18:47 +08:00
|
|
|
|
2009-02-27 18:18:27 +08:00
|
|
|
def do_addoption(self, parser):
|
2009-04-09 22:03:09 +08:00
|
|
|
methods = self.comregistry.listattr("pytest_addoption", reverse=True)
|
2009-03-21 23:17:30 +08:00
|
|
|
mc = py._com.MultiCall(methods, parser=parser)
|
|
|
|
mc.execute()
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-04-09 07:33:48 +08:00
|
|
|
def pytest_plugin_registered(self, plugin):
|
2009-02-27 18:18:27 +08:00
|
|
|
if hasattr(self, '_config'):
|
2009-04-10 02:39:59 +08:00
|
|
|
self.call_plugin(plugin, "pytest_addoption", parser=self._config._parser)
|
|
|
|
self.call_plugin(plugin, "pytest_configure", config=self._config)
|
|
|
|
|
|
|
|
def call_plugin(self, plugin, methname, **kwargs):
|
|
|
|
return self.MultiCall(self.listattr(methname, plugins=[plugin]),
|
|
|
|
**kwargs).execute(firstresult=True)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-03-01 21:56:29 +08:00
|
|
|
def do_configure(self, config):
|
2009-02-27 18:18:27 +08:00
|
|
|
assert not hasattr(self, '_config')
|
2009-04-09 22:03:09 +08:00
|
|
|
config.pluginmanager.register(self)
|
2009-02-27 18:18:27 +08:00
|
|
|
self._config = config
|
2009-05-08 00:01:53 +08:00
|
|
|
config.hook.pytest_configure(config=self._config)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-03-01 21:56:29 +08:00
|
|
|
def do_unconfigure(self, config):
|
2009-02-27 18:18:27 +08:00
|
|
|
config = self._config
|
|
|
|
del self._config
|
2009-05-08 00:01:53 +08:00
|
|
|
config.hook.pytest_unconfigure(config=config)
|
2009-04-09 22:03:09 +08:00
|
|
|
config.pluginmanager.unregister(self)
|
2009-02-27 18:18:27 +08:00
|
|
|
|
2009-04-04 05:18:41 +08:00
|
|
|
def do_itemrun(self, item, pdb=None):
|
2009-05-21 04:02:08 +08:00
|
|
|
res = self.hook.pytest_itemrun(item=item, pdb=pdb)
|
2009-04-04 06:36:29 +08:00
|
|
|
if res is None:
|
|
|
|
raise ValueError("could not run %r" %(item,))
|
2009-04-04 05:18:41 +08:00
|
|
|
|
2009-02-27 18:18:27 +08:00
|
|
|
#
|
|
|
|
# XXX old code to automatically load classes
|
|
|
|
#
|
2009-05-19 05:26:16 +08:00
|
|
|
def canonical_importname(name):
|
|
|
|
name = name.lower()
|
2009-02-27 18:18:27 +08:00
|
|
|
modprefix = "pytest_"
|
2009-05-19 05:26:16 +08:00
|
|
|
if not name.startswith(modprefix):
|
|
|
|
name = modprefix + name
|
|
|
|
return name
|
2009-02-27 18:18:27 +08:00
|
|
|
|
|
|
|
def importplugin(importspec):
|
|
|
|
try:
|
|
|
|
return __import__(importspec)
|
|
|
|
except ImportError, e:
|
2009-03-04 01:42:32 +08:00
|
|
|
if str(e).find(importspec) == -1:
|
|
|
|
raise
|
2009-02-27 18:18:27 +08:00
|
|
|
try:
|
|
|
|
return __import__("py.__.test.plugin.%s" %(importspec), None, None, '__doc__')
|
2009-03-04 01:42:32 +08:00
|
|
|
except ImportError, e:
|
|
|
|
if str(e).find(importspec) == -1:
|
|
|
|
raise
|
2009-03-19 04:49:38 +08:00
|
|
|
#print "syspath:", py.std.sys.path
|
|
|
|
#print "curdir:", py.std.os.getcwd()
|
2009-02-27 23:46:00 +08:00
|
|
|
return __import__(importspec) # show the original exception
|