160 lines
5.4 KiB
Python
160 lines
5.4 KiB
Python
|
""" provide version info, conftest/environment config names.
|
||
|
"""
|
||
|
import py
|
||
|
import inspect, sys
|
||
|
|
||
|
def pytest_addoption(parser):
|
||
|
group = parser.getgroup('debugconfig')
|
||
|
group.addoption('--version', action="store_true",
|
||
|
help="display py lib version and import information.")
|
||
|
group._addoption('-p', action="append", dest="plugins", default = [],
|
||
|
metavar="name",
|
||
|
help="early-load given plugin (multi-allowed).")
|
||
|
group.addoption('--traceconfig',
|
||
|
action="store_true", dest="traceconfig", default=False,
|
||
|
help="trace considerations of conftest.py files."),
|
||
|
group._addoption('--nomagic',
|
||
|
action="store_true", dest="nomagic", default=False,
|
||
|
help="don't reinterpret asserts, no traceback cutting. ")
|
||
|
group.addoption('--debug',
|
||
|
action="store_true", dest="debug", default=False,
|
||
|
help="generate and show internal debugging information.")
|
||
|
group.addoption("--help-config", action="store_true", dest="helpconfig",
|
||
|
help="show available conftest.py and ENV-variable names.")
|
||
|
|
||
|
|
||
|
def pytest_configure(__multicall__, config):
|
||
|
if config.option.version:
|
||
|
p = py.path.local(py.__file__).dirpath()
|
||
|
sys.stderr.write("This is py.test version %s, imported from %s\n" %
|
||
|
(py.__version__, p))
|
||
|
sys.exit(0)
|
||
|
if not config.option.helpconfig:
|
||
|
return
|
||
|
__multicall__.execute()
|
||
|
options = []
|
||
|
for group in config._parser._groups:
|
||
|
options.extend(group.options)
|
||
|
widths = [0] * 10
|
||
|
tw = py.io.TerminalWriter()
|
||
|
tw.sep("-")
|
||
|
tw.line("%-13s | %-18s | %-25s | %s" %(
|
||
|
"cmdline name", "conftest.py name", "ENV-variable name", "help"))
|
||
|
tw.sep("-")
|
||
|
|
||
|
options = [opt for opt in options if opt._long_opts]
|
||
|
options.sort(key=lambda x: x._long_opts)
|
||
|
for opt in options:
|
||
|
if not opt._long_opts:
|
||
|
continue
|
||
|
optstrings = list(opt._long_opts) # + list(opt._short_opts)
|
||
|
optstrings = filter(None, optstrings)
|
||
|
optstring = "|".join(optstrings)
|
||
|
line = "%-13s | %-18s | %-25s | %s" %(
|
||
|
optstring,
|
||
|
"option_%s" % opt.dest,
|
||
|
"PYTEST_OPTION_%s" % opt.dest.upper(),
|
||
|
opt.help and opt.help or "",
|
||
|
)
|
||
|
tw.line(line[:tw.fullwidth])
|
||
|
for name, help in conftest_options:
|
||
|
line = "%-13s | %-18s | %-25s | %s" %(
|
||
|
"",
|
||
|
name,
|
||
|
"",
|
||
|
help,
|
||
|
)
|
||
|
tw.line(line[:tw.fullwidth])
|
||
|
|
||
|
tw.sep("-")
|
||
|
sys.exit(0)
|
||
|
|
||
|
conftest_options = (
|
||
|
('pytest_plugins', 'list of plugin names to load'),
|
||
|
('collect_ignore', '(relative) paths ignored during collection'),
|
||
|
('rsyncdirs', 'to-be-rsynced directories for dist-testing'),
|
||
|
)
|
||
|
|
||
|
def pytest_report_header(config):
|
||
|
lines = []
|
||
|
if config.option.debug or config.option.traceconfig:
|
||
|
lines.append("using py lib: %s" % (py.path.local(py.__file__).dirpath()))
|
||
|
if config.option.traceconfig:
|
||
|
lines.append("active plugins:")
|
||
|
plugins = []
|
||
|
items = config.pluginmanager._name2plugin.items()
|
||
|
for name, plugin in items:
|
||
|
lines.append(" %-20s: %s" %(name, repr(plugin)))
|
||
|
return lines
|
||
|
|
||
|
|
||
|
# =====================================================
|
||
|
# validate plugin syntax and hooks
|
||
|
# =====================================================
|
||
|
|
||
|
def pytest_plugin_registered(manager, plugin):
|
||
|
hookspec = manager.hook._hookspecs
|
||
|
methods = collectattr(plugin)
|
||
|
hooks = collectattr(hookspec)
|
||
|
stringio = py.io.TextIO()
|
||
|
def Print(*args):
|
||
|
if args:
|
||
|
stringio.write(" ".join(map(str, args)))
|
||
|
stringio.write("\n")
|
||
|
|
||
|
fail = False
|
||
|
while methods:
|
||
|
name, method = methods.popitem()
|
||
|
#print "checking", name
|
||
|
if isgenerichook(name):
|
||
|
continue
|
||
|
if name not in hooks:
|
||
|
Print("found unknown hook:", name)
|
||
|
fail = True
|
||
|
else:
|
||
|
method_args = getargs(method)
|
||
|
if '__multicall__' in method_args:
|
||
|
method_args.remove('__multicall__')
|
||
|
hook = hooks[name]
|
||
|
hookargs = getargs(hook)
|
||
|
for arg in method_args:
|
||
|
if arg not in hookargs:
|
||
|
Print("argument %r not available" %(arg, ))
|
||
|
Print("actual definition: %s" %(formatdef(method)))
|
||
|
Print("available hook arguments: %s" %
|
||
|
", ".join(hookargs))
|
||
|
fail = True
|
||
|
break
|
||
|
#if not fail:
|
||
|
# print "matching hook:", formatdef(method)
|
||
|
if fail:
|
||
|
name = getattr(plugin, '__name__', plugin)
|
||
|
raise PluginValidationError("%s:\n%s" %(name, stringio.getvalue()))
|
||
|
|
||
|
class PluginValidationError(Exception):
|
||
|
""" plugin failed validation. """
|
||
|
|
||
|
def isgenerichook(name):
|
||
|
return name == "pytest_plugins" or \
|
||
|
name.startswith("pytest_funcarg__")
|
||
|
|
||
|
def getargs(func):
|
||
|
args = inspect.getargs(py.code.getrawcode(func))[0]
|
||
|
startindex = inspect.ismethod(func) and 1 or 0
|
||
|
return args[startindex:]
|
||
|
|
||
|
def collectattr(obj, prefixes=("pytest_",)):
|
||
|
methods = {}
|
||
|
for apiname in dir(obj):
|
||
|
for prefix in prefixes:
|
||
|
if apiname.startswith(prefix):
|
||
|
methods[apiname] = getattr(obj, apiname)
|
||
|
return methods
|
||
|
|
||
|
def formatdef(func):
|
||
|
return "%s%s" %(
|
||
|
func.__name__,
|
||
|
inspect.formatargspec(*inspect.getargspec(func))
|
||
|
)
|
||
|
|