[py-svn] r62170 - in py/branch/pytestplugin/py/test: . plugin

hpk at codespeak.net hpk at codespeak.net
Thu Feb 26 00:42:20 CET 2009


Author: hpk
Date: Thu Feb 26 00:42:18 2009
New Revision: 62170

Modified:
   py/branch/pytestplugin/py/test/plugin/pytest_doctest.py
   py/branch/pytestplugin/py/test/plugin/pytest_plugintester.py
   py/branch/pytestplugin/py/test/plugin/pytest_terminal.py
   py/branch/pytestplugin/py/test/session.py
Log:
extend plugin api testinging
fix a bit doctests 


Modified: py/branch/pytestplugin/py/test/plugin/pytest_doctest.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/pytest_doctest.py	(original)
+++ py/branch/pytestplugin/py/test/plugin/pytest_doctest.py	Thu Feb 26 00:42:18 2009
@@ -49,9 +49,10 @@
             lines += checker.output_difference(example, 
                     doctestfailure.got, REPORT_UDIFF).split("\n")
             return ReprFailDoctest(reprlocation, lines)
-        #elif excinfo.errisinstance(py.compat.doctest.UnexpectedException):
+        elif excinfo.errisinstance(py.compat.doctest.UnexpectedException):
+            return # XXX 
         else: 
-            return super(DoctestTextfileContent, self).repr_failure(excinfo, outerr)
+            return super(DoctestItem, self).repr_failure(excinfo, outerr)
 
 class DoctestTextfile(DoctestItem):
     def runtest(self):
@@ -62,7 +63,6 @@
 
 class DoctestModule(DoctestItem):
     def runtest(self):
-        assert 0
         module = self.fspath.pyimport()
         failed, tot = py.compat.doctest.testmod(
             module, raise_on_error=True, verbose=0)
@@ -71,7 +71,6 @@
 #
 # Plugin tests
 #
-from py.__.test.outcome import Failed 
 
 class TestDoctests:
     def test_collect_testtextfile(self, testdir):
@@ -112,18 +111,27 @@
 
     @py.test.keywords(xfail=True)
     def test_doctest_unexpected_exception(self, testdir):
+        from py.__.test.outcome import Failed 
+
+        testdir.plugins.append(DoctestPlugin())
         p = testdir.maketxtfile("""
             >>> i = 0
+            >>> i = 1 
             >>> x
             2
         """)
-        col = testdir.getfscol(p)
-        testitem = col.join(p.basename)
-        excinfo = py.test.raises(Failed, "testitem.runtest()")
-        repr = testitem.repr_failure(excinfo, ("", ""))
-        assert repr.reprlocation 
+        sorter = testdir.inline_run(p)
+        events = sorter.getnamed("itemtestreport")
+        assert len(events) == 1
+        ev, = events
+        assert ev.failed
+        assert ev.longrepr 
+        # XXX 
+        #testitem, = items
+        #excinfo = py.test.raises(Failed, "testitem.runtest()")
+        #repr = testitem.repr_failure(excinfo, ("", ""))
+        #assert repr.reprlocation 
 
-    @py.test.keywords(xfail=True)
     def test_doctestmodule(self, testdir):
         testdir.plugins.append(DoctestPlugin())
         p = testdir.makepyfile("""
@@ -137,7 +145,6 @@
         events = testdir.inline_run_with_plugins(p, "--doctest-modules")
         ev, = events.getnamed("itemtestreport")
         assert ev.failed 
-        assert isinstnace(ev.item, DoctestTextfile)
 
     def test_txtfile_failing(self, testdir):
         testdir.plugins.append('pytest_doctest')

Modified: py/branch/pytestplugin/py/test/plugin/pytest_plugintester.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/pytest_plugintester.py	(original)
+++ py/branch/pytestplugin/py/test/plugin/pytest_plugintester.py	Thu Feb 26 00:42:18 2009
@@ -37,23 +37,22 @@
                     break 
         return crunner 
 
-    def apicheck(self, impclass):
-        print "loading and checking", impclass 
+    def apicheck(self, pluginclass):
+        print "loading and checking", pluginclass 
         fail = False 
         pm = py.test._PytestPlugins()
-        plugin = impclass()
-        methods = collectattr(plugin.__class__)
+        methods = collectattr(pluginclass)
         hooks = collectattr(PytestPluginHooks)
         getargs = py.std.inspect.getargs
 
         def isgenerichook(name):
-            return name.startswith("pyevent_") or name.startswith("pytest_pyfuncarg")
+            return name.startswith("pytest_pyfuncarg_")
 
         while methods:
             name, method = methods.popitem()
             if isgenerichook(name):
-                continue # XXX also do some checks
-            if name not in hooks and not isgenerichook(name):
+                continue
+            if name not in hooks:
                 print "found unknown hook: %s" % name 
                 fail = True
             else:
@@ -65,8 +64,8 @@
                 for arg, hookarg in zip(method_args[0], hookargs[0]):
                     if arg != hookarg: 
                         print "argument mismatch:" 
-                        print "required:", formatdef(method)
-                        print "actual  :", formatdef(hook)
+                        print "actual  : %s.%s" %(pluginclass.__name__, formatdef(method))
+                        print "required:", formatdef(hook)
                         fail = True
                         break 
                 if not fail:
@@ -74,11 +73,12 @@
         if fail:
             py.test.fail("Plugin API error")
 
-def collectattr(obj, prefix="pytest_"):
+def collectattr(obj, prefixes=("pytest_", "pyevent_")):
     methods = {}
     for apiname in vars(obj): 
-        if apiname.startswith(prefix):
-            methods[apiname] = getattr(obj, apiname) 
+        for prefix in prefixes:
+            if apiname.startswith(prefix):
+                methods[apiname] = getattr(obj, apiname) 
     return methods 
 
 def formatdef(func):
@@ -133,13 +133,52 @@
     def pytest_terminal_summary(self, terminalreporter):
         """ add additional section in terminal summary reporting. """
 
-    #def pytest_termreport_result(self, event):
-    #    """ return (category, short, verbose) information about the given result event. 
-    #        ``category`` will be used for counting tests and 
-    #        pytest_termreport_summary will be called for each category. 
-    #        ``short`` will be used for printing progress info like "...F.."
-    #        ``verbose`` is used for printing verbose information. 
-    #    """ 
+    # events
+    def pyevent(self, eventname, *args, **kwargs):
+        """ called for each testing event. """
+
+    def pyevent_internalerror(self, event):
+        """ called for internal errors. """
+
+    def pyevent_itemstart(self, event):
+        """ test item gets collected. """
+
+    def pyevent_itemtestreport(self, event):
+        """ test has been run. """
+
+    def pyevent_deselected(self, event):
+        """ item has been dselected. """
+
+    def pyevent_collectionstart(self, event):
+        """ collector starts collecting. """
+
+    def pyevent_collectionreport(self, event):
+        """ collector finished collecting. """
+
+    def pyevent_testrunstart(self, event):
+        """ whole test run starts. """
+
+    def pyevent_testrunfinish(self, event):
+        """ whole test run starts. """
+
+    def pyevent_hostup(self, event):
+        """ Host is up. """
+
+    def pyevent_hostgatewayready(self, event):
+        """ Connection to Host is ready. """
+
+    def pyevent_hostdown(self, event):
+        """ Host is down. """
+
+    def pyevent_rescheduleitems(self, event):
+        """ Items from a host that went down. """
+
+    def pyevent_looponfailinginfo(self, event):
+        """ info for repeating failing tests. """
+
+    def pyevent_plugin_registered(self, plugin):
+        """ a new py lib plugin got registered. """
+        
    
 # ===============================================================================
 # plugin tests 

Modified: py/branch/pytestplugin/py/test/plugin/pytest_terminal.py
==============================================================================
--- py/branch/pytestplugin/py/test/plugin/pytest_terminal.py	(original)
+++ py/branch/pytestplugin/py/test/plugin/pytest_terminal.py	Thu Feb 26 00:42:18 2009
@@ -85,13 +85,13 @@
         else: 
             return self._tw.markup("???", red=True)
 
-    def pyevent_internalexception(self, ev):
-        for line in str(ev.repr).split("\n"):
+    def pyevent_internalerror(self, event):
+        for line in str(event.repr).split("\n"):
             self.write_line("InternalException: " + line)
 
-    def pyevent_hostgatewayready(self, ev):
+    def pyevent_hostgatewayready(self, event):
         if self.config.option.verbose:
-            self.write_line("HostGatewayReady: %s" %(ev.host,))
+            self.write_line("HostGatewayReady: %s" %(event.host,))
 
     def pyevent_plugin_registered(self, plugin):
         if self.config.option.traceconfig: 
@@ -101,63 +101,63 @@
             #     which garbles our output if we use self.write_line 
             self.write_line(msg)
 
-    def pyevent_hostup(self, ev):
-        d = ev.platinfo.copy()
-        d['hostid'] = ev.host.hostid
+    def pyevent_hostup(self, event):
+        d = event.platinfo.copy()
+        d['hostid'] = event.host.hostid
         d['version'] = repr_pythonversion(d['sys.version_info'])
         self.write_line("HOSTUP: %(hostid)s %(sys.platform)s "
                       "%(sys.executable)s - Python %(version)s" %
                       d)
 
-    def pyevent_hostdown(self, ev):
-        host = ev.host
-        error = ev.error
+    def pyevent_hostdown(self, event):
+        host = event.host
+        error = event.error
         if error:
             self.write_line("HostDown %s: %s" %(host.hostid, error))
 
-    def pyevent_itemstart(self, ev):
+    def pyevent_itemstart(self, event):
         if self.config.option.verbose:
-            info = ev.item.repr_metainfo()
+            info = event.item.repr_metainfo()
             line = info.verboseline(basedir=self.curdir) + " "
             extra = ""
-            if ev.host:
-                extra = "-> " + ev.host.hostid
+            if event.host:
+                extra = "-> " + event.host.hostid
             self.write_ensure_prefix(line, extra)
         else:
             # ensure that the path is printed before the 1st test of
             # a module starts running
-            fspath = ev.item.fspath 
+            fspath = event.item.fspath 
             self.write_fspath_result(fspath, "")
 
-    def pyevent_rescheduleitems(self, ev):
+    def pyevent_rescheduleitems(self, event):
         if self.config.option.debug:
-            self.write_sep("!", "RESCHEDULING %s " %(ev.items,))
+            self.write_sep("!", "RESCHEDULING %s " %(event.items,))
 
-    def pyevent_deselected(self, ev):
-        self.stats.setdefault('deselected', []).append(ev)
+    def pyevent_deselected(self, event):
+        self.stats.setdefault('deselected', []).append(event)
     
-    def pyevent_itemtestreport(self, ev):
-        fspath = ev.colitem.fspath 
-        cat, letter, word = self.getcategoryletterword(ev)
-        self.stats.setdefault(cat, []).append(ev)
+    def pyevent_itemtestreport(self, event):
+        fspath = event.colitem.fspath 
+        cat, letter, word = self.getcategoryletterword(event)
+        self.stats.setdefault(cat, []).append(event)
         if not self.config.option.verbose:
             self.write_fspath_result(fspath, letter)
         else:
-            info = ev.colitem.repr_metainfo()
+            info = event.colitem.repr_metainfo()
             line = info.verboseline(basedir=self.curdir) + " "
             self.write_ensure_prefix(line, word)
 
-    def pyevent_collectionreport(self, ev):
-        if not ev.passed:
-            if ev.failed:
-                self.stats.setdefault("failed", []).append(ev)
-                msg = ev.longrepr.reprcrash.message 
-                self.write_fspath_result(ev.colitem.fspath, "F")
-            elif ev.skipped:
-                self.stats.setdefault("skipped", []).append(ev)
-                self.write_fspath_result(ev.colitem.fspath, "S")
+    def pyevent_collectionreport(self, event):
+        if not event.passed:
+            if event.failed:
+                self.stats.setdefault("failed", []).append(event)
+                msg = event.longrepr.reprcrash.message 
+                self.write_fspath_result(event.colitem.fspath, "F")
+            elif event.skipped:
+                self.stats.setdefault("skipped", []).append(event)
+                self.write_fspath_result(event.colitem.fspath, "S")
 
-    def pyevent_testrunstart(self, ev):
+    def pyevent_testrunstart(self, event):
         self.write_sep("=", "test session starts", bold=True)
         self._sessionstarttime = py.std.time.time()
         rev = py.__pkg__.getrev()
@@ -174,30 +174,30 @@
         for i, testarg in py.builtin.enumerate(self.config.args):
             self.write_line("test object %d: %s" %(i+1, testarg))
 
-    def pyevent_testrunfinish(self, ev):
+    def pyevent_testrunfinish(self, event):
         self._tw.line("")
-        if ev.exitstatus in (0, 1, 2):
+        if event.exitstatus in (0, 1, 2):
             self.summary_failures()
             self.summary_skips()
             self.config.pytestplugins.call_each("pytest_terminal_summary", terminalreporter=self)
-        if ev.excrepr is not None:
-            self.summary_final_exc(ev.excrepr)
-        if ev.exitstatus == 2:
+        if event.excrepr is not None:
+            self.summary_final_exc(event.excrepr)
+        if event.exitstatus == 2:
             self.write_sep("!", "KEYBOARD INTERRUPT")
         self.summary_deselected()
         self.summary_stats()
 
-    def pyevent_looponfailinginfo(self, ev):
-        if ev.failreports:
+    def pyevent_looponfailinginfo(self, event):
+        if event.failreports:
             self.write_sep("#", "LOOPONFAILING", red=True)
-            for report in ev.failreports:
+            for report in event.failreports:
                 try:
                     loc = report.longrepr.reprcrash
                 except AttributeError:
                     loc = str(report.longrepr)[:50]
                 self.write_line(loc, red=True)
         self.write_sep("#", "waiting for changes")
-        for rootdir in ev.rootdirs:
+        for rootdir in event.rootdirs:
             self.write_line("### Watching:   %s" %(rootdir,), bold=True)
 
     #
@@ -265,24 +265,24 @@
     def outindent(self, line):
         self.out.line(self.indent + str(line))
 
-    def pyevent_collectionstart(self, ev):
-        self.outindent(ev.collector)
+    def pyevent_collectionstart(self, event):
+        self.outindent(event.collector)
         self.indent += self.INDENT 
     
     def pyevent_itemstart(self, event):
         self.outindent(event.item)
 
-    def pyevent_collectionreport(self, ev):
-        if not ev.passed:
-            self.outindent("!!! %s !!!" % ev.longrepr.reprcrash.message)
-            self._failed.append(ev)
+    def pyevent_collectionreport(self, event):
+        if not event.passed:
+            self.outindent("!!! %s !!!" % event.longrepr.reprcrash.message)
+            self._failed.append(event)
         self.indent = self.indent[:-len(self.INDENT)]
 
-    def pyevent_testrunfinish(self, session):
+    def pyevent_testrunfinish(self, event):
         if self._failed:
             self.out.sep("!", "collection failures")
-        for ev in self._failed:
-            ev.toterminal(self.out)
+        for event in self._failed:
+            event.toterminal(self.out)
                 
 def folded_skips(skipped):
     d = {}
@@ -399,11 +399,11 @@
             "E   ImportError: No module named xyz"
         ])
 
-    def test_internal_exception(self, testdir, linecomp):
+    def test_internalerror(self, testdir, linecomp):
         modcol = testdir.getmodulecol("def test_one(): pass")
         rep = TerminalReporter(modcol._config, file=linecomp.stringio)
         excinfo = py.test.raises(ValueError, "raise ValueError('hello')")
-        rep.pyevent_internalexception(event.InternalException(excinfo))
+        rep.pyevent_internalerror(event.InternalException(excinfo))
         linecomp.assert_contains_lines([
             "InternalException: >*raise ValueError*"
         ])
@@ -621,3 +621,8 @@
         assert repr_pythonversion() == str(x) 
     finally: 
         py.magic.revert(sys, 'version_info') 
+
+def test_generic(plugintester):
+    plugintester.apicheck(TerminalPlugin)
+    plugintester.apicheck(TerminalReporter)
+    plugintester.apicheck(CollectonlyReporter)

Modified: py/branch/pytestplugin/py/test/session.py
==============================================================================
--- py/branch/pytestplugin/py/test/session.py	(original)
+++ py/branch/pytestplugin/py/test/session.py	Thu Feb 26 00:42:18 2009
@@ -123,12 +123,14 @@
                     break 
                 if not self.config.option.collectonly: 
                     self.runtest(item)
+
             py.test.collect.Item._setupstate.teardown_all()
         except KeyboardInterrupt:
             captured_excinfo = py.code.ExceptionInfo()
             exitstatus = outcome.EXIT_INTERRUPTED
         except:
-            self.bus.notify("internalerror", event.InternalException())
+            captured_excinfo = py.code.ExceptionInfo()
+            self.bus.notify("internalerror", event.InternalException(captured_excinfo))
             exitstatus = outcome.EXIT_INTERNALERROR
         if exitstatus == 0 and self._testsfailed:
             exitstatus = outcome.EXIT_TESTSFAILED



More information about the pytest-commit mailing list