[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