src/eric7/DebugClients/Python/coverage/annotate.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8775
0802ae193343
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
3
4 """Source file annotation for coverage.py."""
5
6 import os
7 import re
8
9 from coverage.files import flat_rootname
10 from coverage.misc import ensure_dir, isolate_module
11 from coverage.report import get_analysis_to_report
12
13 os = isolate_module(os)
14
15
16 class AnnotateReporter:
17 """Generate annotated source files showing line coverage.
18
19 This reporter creates annotated copies of the measured source files. Each
20 .py file is copied as a .py,cover file, with a left-hand margin annotating
21 each line::
22
23 > def h(x):
24 - if 0: #pragma: no cover
25 - pass
26 > if x == 1:
27 ! a = 1
28 > else:
29 > a = 2
30
31 > h(2)
32
33 Executed lines use '>', lines not executed use '!', lines excluded from
34 consideration use '-'.
35
36 """
37
38 def __init__(self, coverage):
39 self.coverage = coverage
40 self.config = self.coverage.config
41 self.directory = None
42
43 blank_re = re.compile(r"\s*(#|$)")
44 else_re = re.compile(r"\s*else\s*:\s*(#|$)")
45
46 def report(self, morfs, directory=None):
47 """Run the report.
48
49 See `coverage.report()` for arguments.
50
51 """
52 self.directory = directory
53 self.coverage.get_data()
54 for fr, analysis in get_analysis_to_report(self.coverage, morfs):
55 self.annotate_file(fr, analysis)
56
57 def annotate_file(self, fr, analysis):
58 """Annotate a single file.
59
60 `fr` is the FileReporter for the file to annotate.
61
62 """
63 statements = sorted(analysis.statements)
64 missing = sorted(analysis.missing)
65 excluded = sorted(analysis.excluded)
66
67 if self.directory:
68 ensure_dir(self.directory)
69 dest_file = os.path.join(self.directory, flat_rootname(fr.relative_filename()))
70 if dest_file.endswith("_py"):
71 dest_file = dest_file[:-3] + ".py"
72 dest_file += ",cover"
73 else:
74 dest_file = fr.filename + ",cover"
75
76 with open(dest_file, 'w', encoding='utf-8') as dest:
77 i = j = 0
78 covered = True
79 source = fr.source()
80 for lineno, line in enumerate(source.splitlines(True), start=1):
81 while i < len(statements) and statements[i] < lineno:
82 i += 1
83 while j < len(missing) and missing[j] < lineno:
84 j += 1
85 if i < len(statements) and statements[i] == lineno:
86 covered = j >= len(missing) or missing[j] > lineno
87 if self.blank_re.match(line):
88 dest.write(' ')
89 elif self.else_re.match(line):
90 # Special logic for lines containing only 'else:'.
91 if j >= len(missing):
92 dest.write('> ')
93 elif statements[i] == missing[j]:
94 dest.write('! ')
95 else:
96 dest.write('> ')
97 elif lineno in excluded:
98 dest.write('- ')
99 elif covered:
100 dest.write('> ')
101 else:
102 dest.write('! ')
103
104 dest.write(line)

eric ide

mercurial