refine plugin registration, allow new "-p no:NAME" way to prevent/undo plugin registration
This commit is contained in:
+1
-1
@@ -300,9 +300,9 @@ class Config(object):
|
||||
if addopts:
|
||||
args[:] = self.getini("addopts") + args
|
||||
self._checkversion()
|
||||
self.pluginmanager.consider_preparse(args)
|
||||
self.pluginmanager.consider_setuptools_entrypoints()
|
||||
self.pluginmanager.consider_env()
|
||||
self.pluginmanager.consider_preparse(args)
|
||||
self._setinitialconftest(args)
|
||||
self.pluginmanager.do_addoption(self._parser)
|
||||
|
||||
|
||||
+36
-48
@@ -11,11 +11,9 @@ assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: "
|
||||
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
||||
|
||||
default_plugins = (
|
||||
"config mark session terminal runner python pdb unittest capture skipping "
|
||||
"config mark main terminal runner python pdb unittest capture skipping "
|
||||
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
||||
"junitxml doctest").split()
|
||||
|
||||
IMPORTPREFIX = "pytest_"
|
||||
"junitxml resultlog doctest").split()
|
||||
|
||||
class TagTracer:
|
||||
def __init__(self, prefix="[pytest] "):
|
||||
@@ -79,20 +77,12 @@ class PluginManager(object):
|
||||
for spec in default_plugins:
|
||||
self.import_plugin(spec)
|
||||
|
||||
def _getpluginname(self, plugin, name):
|
||||
if name is None:
|
||||
if hasattr(plugin, '__name__'):
|
||||
name = plugin.__name__.split(".")[-1]
|
||||
else:
|
||||
name = id(plugin)
|
||||
return name
|
||||
|
||||
def register(self, plugin, name=None, prepend=False):
|
||||
assert not self.isregistered(plugin), plugin
|
||||
assert not self.isregistered(plugin), plugin
|
||||
name = self._getpluginname(plugin, name)
|
||||
name = name or getattr(plugin, '__name__', str(id(plugin)))
|
||||
if name in self._name2plugin:
|
||||
return False
|
||||
#self.trace("registering", name, plugin)
|
||||
self._name2plugin[name] = plugin
|
||||
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
|
||||
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
|
||||
@@ -112,7 +102,7 @@ class PluginManager(object):
|
||||
del self._name2plugin[name]
|
||||
|
||||
def isregistered(self, plugin, name=None):
|
||||
if self._getpluginname(plugin, name) in self._name2plugin:
|
||||
if self.getplugin(name) is not None:
|
||||
return True
|
||||
for val in self._name2plugin.values():
|
||||
if plugin == val:
|
||||
@@ -136,11 +126,12 @@ class PluginManager(object):
|
||||
return False
|
||||
|
||||
def getplugin(self, name):
|
||||
if name is None:
|
||||
return None
|
||||
try:
|
||||
return self._name2plugin[name]
|
||||
except KeyError:
|
||||
impname = canonical_importname(name)
|
||||
return self._name2plugin[impname]
|
||||
return self._name2plugin.get("_pytest." + name, None)
|
||||
|
||||
# API for bootstrapping
|
||||
#
|
||||
@@ -160,19 +151,28 @@ class PluginManager(object):
|
||||
except ImportError:
|
||||
return # XXX issue a warning
|
||||
for ep in iter_entry_points('pytest11'):
|
||||
name = canonical_importname(ep.name)
|
||||
if name in self._name2plugin:
|
||||
if ep.name in self._name2plugin:
|
||||
continue
|
||||
try:
|
||||
plugin = ep.load()
|
||||
except DistributionNotFound:
|
||||
continue
|
||||
name = ep.name
|
||||
if name.startswith("pytest_"):
|
||||
name = name[7:]
|
||||
self.register(plugin, name=name)
|
||||
|
||||
def consider_preparse(self, args):
|
||||
for opt1,opt2 in zip(args, args[1:]):
|
||||
if opt1 == "-p":
|
||||
self.import_plugin(opt2)
|
||||
if opt2.startswith("no:"):
|
||||
name = opt2[3:]
|
||||
if self.getplugin(name) is not None:
|
||||
self.unregister(None, name=name)
|
||||
self._name2plugin[name] = -1
|
||||
else:
|
||||
if self.getplugin(opt2) is None:
|
||||
self.import_plugin(opt2)
|
||||
|
||||
def consider_conftest(self, conftestmodule):
|
||||
if self.register(conftestmodule, name=conftestmodule.__file__):
|
||||
@@ -186,15 +186,19 @@ class PluginManager(object):
|
||||
for spec in attr:
|
||||
self.import_plugin(spec)
|
||||
|
||||
def import_plugin(self, spec):
|
||||
assert isinstance(spec, str)
|
||||
modname = canonical_importname(spec)
|
||||
if modname in self._name2plugin:
|
||||
def import_plugin(self, modname):
|
||||
assert isinstance(modname, str)
|
||||
if self.getplugin(modname) is not None:
|
||||
return
|
||||
try:
|
||||
#self.trace("importing", modname)
|
||||
mod = importplugin(modname)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except ImportError:
|
||||
if modname.startswith("pytest_"):
|
||||
return self.import_plugin(modname[7:])
|
||||
raise
|
||||
except:
|
||||
e = py.std.sys.exc_info()[1]
|
||||
if not hasattr(py.test, 'skip'):
|
||||
@@ -290,34 +294,18 @@ class PluginManager(object):
|
||||
return MultiCall(methods=self.listattr(methname, plugins=[plugin]),
|
||||
kwargs=kwargs, firstresult=True).execute()
|
||||
|
||||
def canonical_importname(name):
|
||||
if '.' in name:
|
||||
return name
|
||||
name = name.lower()
|
||||
if not name.startswith(IMPORTPREFIX):
|
||||
name = IMPORTPREFIX + name
|
||||
return name
|
||||
|
||||
def importplugin(importspec):
|
||||
#print "importing", importspec
|
||||
name = importspec
|
||||
try:
|
||||
return __import__(importspec, None, None, '__doc__')
|
||||
mod = "_pytest." + name
|
||||
return __import__(mod, None, None, '__doc__')
|
||||
except ImportError:
|
||||
e = py.std.sys.exc_info()[1]
|
||||
if str(e).find(importspec) == -1:
|
||||
raise
|
||||
name = importspec
|
||||
try:
|
||||
if name.startswith("pytest_"):
|
||||
name = importspec[7:]
|
||||
return __import__("_pytest.%s" %(name), None, None, '__doc__')
|
||||
except ImportError:
|
||||
e = py.std.sys.exc_info()[1]
|
||||
if str(e).find(name) == -1:
|
||||
raise
|
||||
# show the original exception, not the failing internal one
|
||||
return __import__(importspec, None, None, '__doc__')
|
||||
|
||||
#e = py.std.sys.exc_info()[1]
|
||||
#if str(e).find(name) == -1:
|
||||
# raise
|
||||
pass #
|
||||
return __import__(importspec, None, None, '__doc__')
|
||||
|
||||
class MultiCall:
|
||||
""" execute a call into multiple python functions/methods. """
|
||||
|
||||
@@ -80,7 +80,11 @@ def pytest_report_header(config):
|
||||
plugins = []
|
||||
items = config.pluginmanager._name2plugin.items()
|
||||
for name, plugin in items:
|
||||
lines.append(" %-20s: %s" %(name, repr(plugin)))
|
||||
if hasattr(plugin, '__file__'):
|
||||
r = plugin.__file__
|
||||
else:
|
||||
r = repr(plugin)
|
||||
lines.append(" %-20s: %s" %(name, r))
|
||||
return lines
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ def pytest_addoption(parser):
|
||||
help="only load conftest.py's relative to specified dir.")
|
||||
|
||||
group = parser.getgroup("debugconfig",
|
||||
"test process debugging and configuration")
|
||||
"test session debugging and configuration")
|
||||
group.addoption('--basetemp', dest="basetemp", default=None, metavar="dir",
|
||||
help="base temporary directory for this test run.")
|
||||
|
||||
@@ -336,7 +336,7 @@ class Session(FSCollector):
|
||||
def __init__(self, config):
|
||||
super(Session, self).__init__(py.path.local(), parent=None,
|
||||
config=config, session=self)
|
||||
self.config.pluginmanager.register(self, name="session", prepend=True)
|
||||
assert self.config.pluginmanager.register(self, name="session", prepend=True)
|
||||
self._testsfailed = 0
|
||||
self.shouldstop = False
|
||||
self.trace = config.trace.root.get("collection")
|
||||
+1
-1
@@ -6,7 +6,7 @@ import re
|
||||
import inspect
|
||||
import time
|
||||
from fnmatch import fnmatch
|
||||
from _pytest.session import Session
|
||||
from _pytest.main import Session
|
||||
from py.builtin import print_
|
||||
from _pytest.core import HookRelay
|
||||
|
||||
|
||||
+1
-1
@@ -730,7 +730,7 @@ class FuncargRequest:
|
||||
raise self.LookupError(msg)
|
||||
|
||||
def showfuncargs(config):
|
||||
from _pytest.session import Session
|
||||
from _pytest.main import Session
|
||||
session = Session(config)
|
||||
session.perform_collect()
|
||||
if session.items:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
""" (disabled by default) create result information in a plain text file. """
|
||||
|
||||
import py
|
||||
from py.builtin import print_
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("resultlog", "resultlog plugin options")
|
||||
group.addoption('--resultlog', action="store", dest="resultlog", metavar="path", default=None,
|
||||
help="path for machine-readable result log.")
|
||||
group = parser.getgroup("terminal reporting", "resultlog plugin options")
|
||||
group.addoption('--resultlog', action="store", dest="resultlog",
|
||||
metavar="path", default=None,
|
||||
help="path for machine-readable result log.")
|
||||
|
||||
def pytest_configure(config):
|
||||
resultlog = config.option.resultlog
|
||||
@@ -52,9 +52,9 @@ class ResultLog(object):
|
||||
self.logfile = logfile # preferably line buffered
|
||||
|
||||
def write_log_entry(self, testpath, lettercode, longrepr):
|
||||
print_("%s %s" % (lettercode, testpath), file=self.logfile)
|
||||
py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
|
||||
for line in longrepr.splitlines():
|
||||
print_(" %s" % line, file=self.logfile)
|
||||
py.builtin.print_(" %s" % line, file=self.logfile)
|
||||
|
||||
def log_outcome(self, report, lettercode, longrepr):
|
||||
testpath = getattr(report, 'nodeid', None)
|
||||
|
||||
Reference in New Issue
Block a user