[py-svn] py-trunk commit 756383d54510: simplify pluginmanager, move plugin validation code to plugin, remove unused code
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Tue Dec 29 12:37:44 CET 2009
# HG changeset patch -- Bitbucket.org
# Project py-trunk
# URL http://bitbucket.org/hpk42/py-trunk/overview/
# User holger krekel <holger at merlinux.eu>
# Date 1262080741 -3600
# Node ID 756383d5451058b00a35aa42d815c9f75fccfdae
# Parent b38b9280c0732dee15ebe7d5f13d82f11d6dad32
simplify pluginmanager, move plugin validation code to plugin, remove unused code
--- a/py/plugin/pytest_helpconfig.py
+++ b/py/plugin/pytest_helpconfig.py
@@ -1,7 +1,7 @@
""" provide version info, conftest/environment config names.
"""
import py
-import sys
+import inspect, sys
def pytest_addoption(parser):
group = parser.getgroup('debugconfig')
@@ -61,3 +61,73 @@ conftest_options = (
('collect_ignore', '(relative) paths ignored during collection'),
('rsyncdirs', 'to-be-rsynced directories for dist-testing'),
)
+
+# =====================================================
+# 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))
+ )
+
--- a/testing/pytest/test_pluginmanager.py
+++ b/testing/pytest/test_pluginmanager.py
@@ -1,5 +1,5 @@
import py, os
-from py.impl.test.pluginmanager import PluginManager, canonical_importname, collectattr
+from py.impl.test.pluginmanager import PluginManager, canonical_importname
class TestBootstrapping:
def test_consider_env_fails_to_import(self, monkeypatch):
@@ -185,14 +185,14 @@ class TestBootstrapping:
class hello:
def pytest_gurgel(self):
pass
- py.test.raises(pp.Error, "pp.register(hello())")
+ py.test.raises(Exception, "pp.register(hello())")
def test_register_mismatch_arg(self):
pp = PluginManager()
class hello:
def pytest_configure(self, asd):
pass
- excinfo = py.test.raises(pp.Error, "pp.register(hello())")
+ excinfo = py.test.raises(Exception, "pp.register(hello())")
def test_canonical_importname(self):
for name in 'xyz', 'pytest_xyz', 'pytest_Xyz', 'Xyz':
@@ -270,18 +270,6 @@ class TestPytestPluginInteractions:
assert not pluginmanager.listattr("hello")
assert pluginmanager.listattr("x") == [42]
-def test_collectattr():
- class A:
- def pytest_hello(self):
- pass
- class B(A):
- def pytest_world(self):
- pass
- methods = py.builtin.sorted(collectattr(B))
- assert list(methods) == ['pytest_hello', 'pytest_world']
- methods = py.builtin.sorted(collectattr(B()))
- assert list(methods) == ['pytest_hello', 'pytest_world']
-
@py.test.mark.xfail
def test_namespace_has_default_and_env_plugins(testdir):
p = testdir.makepyfile("""
--- a/py/plugin/hookspec.py
+++ b/py/plugin/hookspec.py
@@ -159,7 +159,7 @@ def pytest_looponfailinfo(failreports, r
# error handling and internal debugging hooks
# -------------------------------------------------------------------------
-def pytest_plugin_registered(plugin):
+def pytest_plugin_registered(plugin, manager):
""" a new py lib plugin got registered. """
def pytest_plugin_unregistered(plugin):
--- a/py/impl/test/pluginmanager.py
+++ b/py/impl/test/pluginmanager.py
@@ -44,8 +44,7 @@ class PluginManager(object):
if name in self._name2plugin:
return False
self._name2plugin[name] = plugin
- self.hook.pytest_plugin_registered(plugin=plugin)
- self._checkplugin(plugin)
+ self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
self.comregistry.register(plugin)
return True
@@ -138,46 +137,6 @@ class PluginManager(object):
def _warn(self, msg):
print ("===WARNING=== %s" % (msg,))
- def _checkplugin(self, plugin):
- # =====================================================
- # check plugin hooks
- # =====================================================
- 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 self.Error("%s:\n%s" %(name, stringio.getvalue()))
#
#
# API for interacting with registered and instantiated plugin objects
@@ -224,9 +183,6 @@ class PluginManager(object):
config.hook.pytest_unconfigure(config=config)
config.pluginmanager.unregister(self)
-#
-# XXX old code to automatically load classes
-#
def canonical_importname(name):
name = name.lower()
modprefix = "pytest_"
@@ -254,59 +210,3 @@ def importplugin(importspec):
-def isgenerichook(name):
- return name == "pytest_plugins" or \
- name.startswith("pytest_funcarg__")
-
-def getargs(func):
- args = py.std.inspect.getargs(py.code.getrawcode(func))[0]
- startindex = py.std.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__,
- py.std.inspect.formatargspec(*py.std.inspect.getargspec(func))
- )
-
-if __name__ == "__main__":
- import py.plugin
- basedir = py._dir.join('_plugin')
- name2text = {}
- for p in basedir.listdir("pytest_*"):
- if p.ext == ".py" or (
- p.check(dir=1) and p.join("__init__.py").check()):
- impname = p.purebasename
- if impname.find("__") != -1:
- continue
- try:
- plugin = importplugin(impname)
- except (ImportError, py.impl.test.outcome.Skipped):
- name2text[impname] = "IMPORT ERROR"
- else:
- doc = plugin.__doc__ or ""
- doc = doc.strip()
- name2text[impname] = doc
-
- for name in sorted(name2text.keys()):
- text = name2text[name]
- if name[0] == "_":
- continue
- print ("%-20s %s" % (name, text.split("\n")[0]))
-
- #text = py.std.textwrap.wrap(name2text[name],
- # width = 80,
- # initial_indent="%s: " % name,
- # replace_whitespace = False)
- #for line in text:
- # print line
-
-
--- a/testing/plugin/test_pytest_helpconfig.py
+++ b/testing/plugin/test_pytest_helpconfig.py
@@ -1,4 +1,5 @@
import py, os
+from py.plugin.pytest_helpconfig import collectattr
def test_version(testdir):
assert py.version == py.__version__
@@ -16,3 +17,15 @@ def test_helpconfig(testdir):
"*cmdline*conftest*ENV*",
])
+def test_collectattr():
+ class A:
+ def pytest_hello(self):
+ pass
+ class B(A):
+ def pytest_world(self):
+ pass
+ methods = py.builtin.sorted(collectattr(B))
+ assert list(methods) == ['pytest_hello', 'pytest_world']
+ methods = py.builtin.sorted(collectattr(B()))
+ assert list(methods) == ['pytest_hello', 'pytest_world']
+
More information about the pytest-commit
mailing list