pypy / pytest_resultlog.py

# xxx copied and tweaked from py.lib trunk until a new release comes around
"""resultlog plugin for machine-readable logging of test results. 
   Useful for buildbot integration code. 
""" 

import py

def pytest_addoption(parser):
    group = parser.addgroup("resultlog", "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
    if resultlog:
        logfile = open(resultlog, 'w', 1) # line buffered
        config._resultlog = ResultLog(config, logfile) 
        config.pluginmanager.register(config._resultlog)

def pytest_unconfigure(config):
    resultlog = getattr(config, '_resultlog', None)
    if resultlog:
        resultlog.logfile.close()
        del config._resultlog 
        config.pluginmanager.unregister(resultlog)

def generic_path(item):
    chain = item.listchain()
    gpath = [chain[0].name]
    fspath = chain[0].fspath
    fspart = False
    for node in chain[1:]:
        newfspath = node.fspath
        if newfspath == fspath:
            if fspart:
                gpath.append(':')
                fspart = False
            else:
                gpath.append('.')            
        else:
            gpath.append('/')
            fspart = True
        name = node.name
        if name[0] in '([':
            gpath.pop()
        gpath.append(name)
        fspath = newfspath
    return ''.join(gpath)
        
class ResultLog(object):
    def __init__(self, config, logfile):
        self.config = config
        self.logfile = logfile # preferably line buffered

    def write_log_entry(self, testpath, shortrepr, longrepr):
        print >>self.logfile, "%s %s" % (shortrepr, testpath)
        for line in longrepr.splitlines():
            print >>self.logfile, " %s" % line

    def log_outcome(self, node, shortrepr, longrepr):
        testpath = generic_path(node)
        self.write_log_entry(testpath, shortrepr, longrepr) 

    def pytest_runtest_logreport(self, report):
        res = self.config.hook.pytest_report_teststatus(report=report)
        if res is not None:
            code = res[1]
        else:
            code = report.shortrepr
        if code == 'x':
            longrepr = str(report.longrepr)
        elif code == 'P':
            longrepr = ''
        elif report.passed:
            longrepr = ""
        elif report.failed:
            longrepr = str(report.longrepr) 
        elif report.skipped:
            longrepr = str(report.longrepr.reprcrash.message)
        self.log_outcome(report.item, code, longrepr) 

    def pytest_collectreport(self, report):
        if not report.passed:
            if report.failed: 
                code = "F"
            else:
                assert report.skipped
                code = "S"
            longrepr = str(report.longrepr.reprcrash)
            self.log_outcome(report.collector, code, longrepr)    

    def pytest_internalerror(self, excrepr):
        path = excrepr.reprcrash.path 
        self.write_log_entry(path, '!', str(excrepr))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.