DebugClients/Python3/coverage/annotate.py

changeset 29
391dc0bc4ae5
parent 0
de9c2efb9d02
child 3495
fac17a82b431
equal deleted inserted replaced
28:dde24fc7f7ba 29:391dc0bc4ae5
4 4
5 from .report import Reporter 5 from .report import Reporter
6 6
7 class AnnotateReporter(Reporter): 7 class AnnotateReporter(Reporter):
8 """Generate annotated source files showing line coverage. 8 """Generate annotated source files showing line coverage.
9 9
10 This reporter creates annotated copies of the measured source files. Each 10 This reporter creates annotated copies of the measured source files. Each
11 .py file is copied as a .py,cover file, with a left-hand margin annotating 11 .py file is copied as a .py,cover file, with a left-hand margin annotating
12 each line:: 12 each line::
13 13
14 > def h(x): 14 > def h(x):
15 - if 0: #pragma: no cover 15 - if 0: #pragma: no cover
16 - pass 16 - pass
17 > if x == 1: 17 > if x == 1:
18 ! a = 1 18 ! a = 1
19 > else: 19 > else:
20 > a = 2 20 > a = 2
21 21
22 > h(2) 22 > h(2)
23 23
24 Executed lines use '>', lines not executed use '!', lines excluded from 24 Executed lines use '>', lines not executed use '!', lines excluded from
25 consideration use '-'. 25 consideration use '-'.
26 26
27 """ 27 """
28 28
29 def __init__(self, coverage, ignore_errors=False): 29 def __init__(self, coverage, ignore_errors=False):
30 super(AnnotateReporter, self).__init__(coverage, ignore_errors) 30 super(AnnotateReporter, self).__init__(coverage, ignore_errors)
31 self.directory = None 31 self.directory = None
32 32
33 blank_re = re.compile(r"\s*(#|$)") 33 blank_re = re.compile(r"\s*(#|$)")
34 else_re = re.compile(r"\s*else\s*:\s*(#|$)") 34 else_re = re.compile(r"\s*else\s*:\s*(#|$)")
35 35
36 def report(self, morfs, directory=None, omit_prefixes=None): 36 def report(self, morfs, directory=None, omit_prefixes=None):
37 """Run the report.""" 37 """Run the report."""
38 self.report_files(self.annotate_file, morfs, directory, omit_prefixes) 38 self.report_files(self.annotate_file, morfs, directory, omit_prefixes)
39 39
40 def annotate_file(self, cu, statements, excluded, missing): 40 def annotate_file(self, cu, analysis):
41 """Annotate a single file. 41 """Annotate a single file.
42 42
43 `cu` is the CodeUnit for the file to annotate. 43 `cu` is the CodeUnit for the file to annotate.
44 44
45 """ 45 """
46 if not cu.relative:
47 return
48
46 filename = cu.filename 49 filename = cu.filename
47 source = cu.source_file() 50 source = cu.source_file()
48 if self.directory: 51 if self.directory:
49 dest_file = os.path.join(self.directory, cu.flat_rootname()) 52 dest_file = os.path.join(self.directory, cu.flat_rootname())
50 dest_file += ".py,cover" 53 dest_file += ".py,cover"
51 else: 54 else:
52 dest_file = filename + ",cover" 55 dest_file = filename + ",cover"
53 dest = open(dest_file, 'w') 56 dest = open(dest_file, 'w')
57
58 statements = analysis.statements
59 missing = analysis.missing
60 excluded = analysis.excluded
54 61
55 lineno = 0 62 lineno = 0
56 i = 0 63 i = 0
57 j = 0 64 j = 0
58 covered = True 65 covered = True
68 if i < len(statements) and statements[i] == lineno: 75 if i < len(statements) and statements[i] == lineno:
69 covered = j >= len(missing) or missing[j] > lineno 76 covered = j >= len(missing) or missing[j] > lineno
70 if self.blank_re.match(line): 77 if self.blank_re.match(line):
71 dest.write(' ') 78 dest.write(' ')
72 elif self.else_re.match(line): 79 elif self.else_re.match(line):
73 # Special logic for lines containing only 'else:'. 80 # Special logic for lines containing only 'else:'.
74 if i >= len(statements) and j >= len(missing): 81 if i >= len(statements) and j >= len(missing):
75 dest.write('! ') 82 dest.write('! ')
76 elif i >= len(statements) or j >= len(missing): 83 elif i >= len(statements) or j >= len(missing):
77 dest.write('> ') 84 dest.write('> ')
78 elif statements[i] == missing[j]: 85 elif statements[i] == missing[j]:

eric ide

mercurial