DebugClients/Python/coverage/annotate.py

Sun, 03 Jul 2011 18:01:53 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 03 Jul 2011 18:01:53 +0200
changeset 1166
a94b0a2fafd7
parent 790
2c0ea0163ef4
child 3495
fac17a82b431
permissions
-rw-r--r--

Extended the unit test interface to support skipped tests, expected failures and unexpected successes and to better cope with Python2 scripts when run from the eric IDE.

"""Source file annotation for Coverage."""

import os, re

from .report import Reporter

class AnnotateReporter(Reporter):
    """Generate annotated source files showing line coverage.

    This reporter creates annotated copies of the measured source files. Each
    .py file is copied as a .py,cover file, with a left-hand margin annotating
    each line::

        > def h(x):
        -     if 0:   #pragma: no cover
        -         pass
        >     if x == 1:
        !         a = 1
        >     else:
        >         a = 2

        > h(2)

    Executed lines use '>', lines not executed use '!', lines excluded from
    consideration use '-'.

    """

    def __init__(self, coverage, ignore_errors=False):
        super(AnnotateReporter, self).__init__(coverage, ignore_errors)
        self.directory = None

    blank_re = re.compile(r"\s*(#|$)")
    else_re = re.compile(r"\s*else\s*:\s*(#|$)")

    def report(self, morfs, directory=None, omit_prefixes=None):
        """Run the report."""
        self.report_files(self.annotate_file, morfs, directory, omit_prefixes)

    def annotate_file(self, cu, analysis):
        """Annotate a single file.

        `cu` is the CodeUnit for the file to annotate.

        """
        if not cu.relative:
            return

        filename = cu.filename
        source = cu.source_file()
        if self.directory:
            dest_file = os.path.join(self.directory, cu.flat_rootname())
            dest_file += ".py,cover"
        else:
            dest_file = filename + ",cover"
        dest = open(dest_file, 'w')

        statements = analysis.statements
        missing = analysis.missing
        excluded = analysis.excluded

        lineno = 0
        i = 0
        j = 0
        covered = True
        while True:
            line = source.readline()
            if line == '':
                break
            lineno += 1
            while i < len(statements) and statements[i] < lineno:
                i += 1
            while j < len(missing) and missing[j] < lineno:
                j += 1
            if i < len(statements) and statements[i] == lineno:
                covered = j >= len(missing) or missing[j] > lineno
            if self.blank_re.match(line):
                dest.write('  ')
            elif self.else_re.match(line):
                # Special logic for lines containing only 'else:'.
                if i >= len(statements) and j >= len(missing):
                    dest.write('! ')
                elif i >= len(statements) or j >= len(missing):
                    dest.write('> ')
                elif statements[i] == missing[j]:
                    dest.write('! ')
                else:
                    dest.write('> ')
            elif lineno in excluded:
                dest.write('- ')
            elif covered:
                dest.write('> ')
            else:
                dest.write('! ')
            dest.write(line)
        source.close()
        dest.close()

#
# eflag: FileType = Python2

eric ide

mercurial