Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: third_party/cherrypy/lib/covercp.py

Issue 9368042: Add CherryPy to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/cherrypy/lib/caching.py ('k') | third_party/cherrypy/lib/cpstats.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 """Code-coverage tools for CherryPy.
2
3 To use this module, or the coverage tools in the test suite,
4 you need to download 'coverage.py', either Gareth Rees' `original
5 implementation <http://www.garethrees.org/2001/12/04/python-coverage/>`_
6 or Ned Batchelder's `enhanced version:
7 <http://www.nedbatchelder.com/code/modules/coverage.html>`_
8
9 To turn on coverage tracing, use the following code::
10
11 cherrypy.engine.subscribe('start', covercp.start)
12
13 DO NOT subscribe anything on the 'start_thread' channel, as previously
14 recommended. Calling start once in the main thread should be sufficient
15 to start coverage on all threads. Calling start again in each thread
16 effectively clears any coverage data gathered up to that point.
17
18 Run your code, then use the ``covercp.serve()`` function to browse the
19 results in a web browser. If you run this module from the command line,
20 it will call ``serve()`` for you.
21 """
22
23 import re
24 import sys
25 import cgi
26 from cherrypy._cpcompat import quote_plus
27 import os, os.path
28 localFile = os.path.join(os.path.dirname(__file__), "coverage.cache")
29
30 the_coverage = None
31 try:
32 from coverage import coverage
33 the_coverage = coverage(data_file=localFile)
34 def start():
35 the_coverage.start()
36 except ImportError:
37 # Setting the_coverage to None will raise errors
38 # that need to be trapped downstream.
39 the_coverage = None
40
41 import warnings
42 warnings.warn("No code coverage will be performed; coverage.py could not be imported.")
43
44 def start():
45 pass
46 start.priority = 20
47
48 TEMPLATE_MENU = """<html>
49 <head>
50 <title>CherryPy Coverage Menu</title>
51 <style>
52 body {font: 9pt Arial, serif;}
53 #tree {
54 font-size: 8pt;
55 font-family: Andale Mono, monospace;
56 white-space: pre;
57 }
58 #tree a:active, a:focus {
59 background-color: black;
60 padding: 1px;
61 color: white;
62 border: 0px solid #9999FF;
63 -moz-outline-style: none;
64 }
65 .fail { color: red;}
66 .pass { color: #888;}
67 #pct { text-align: right;}
68 h3 {
69 font-size: small;
70 font-weight: bold;
71 font-style: italic;
72 margin-top: 5px;
73 }
74 input { border: 1px solid #ccc; padding: 2px; }
75 .directory {
76 color: #933;
77 font-style: italic;
78 font-weight: bold;
79 font-size: 10pt;
80 }
81 .file {
82 color: #400;
83 }
84 a { text-decoration: none; }
85 #crumbs {
86 color: white;
87 font-size: 8pt;
88 font-family: Andale Mono, monospace;
89 width: 100%;
90 background-color: black;
91 }
92 #crumbs a {
93 color: #f88;
94 }
95 #options {
96 line-height: 2.3em;
97 border: 1px solid black;
98 background-color: #eee;
99 padding: 4px;
100 }
101 #exclude {
102 width: 100%;
103 margin-bottom: 3px;
104 border: 1px solid #999;
105 }
106 #submit {
107 background-color: black;
108 color: white;
109 border: 0;
110 margin-bottom: -9px;
111 }
112 </style>
113 </head>
114 <body>
115 <h2>CherryPy Coverage</h2>"""
116
117 TEMPLATE_FORM = """
118 <div id="options">
119 <form action='menu' method=GET>
120 <input type='hidden' name='base' value='%(base)s' />
121 Show percentages <input type='checkbox' %(showpct)s name='showpct' value='ch ecked' /><br />
122 Hide files over <input type='text' id='pct' name='pct' value='%(pct)s' size= '3' />%%<br />
123 Exclude files matching<br />
124 <input type='text' id='exclude' name='exclude' value='%(exclude)s' size='20' />
125 <br />
126
127 <input type='submit' value='Change view' id="submit"/>
128 </form>
129 </div>"""
130
131 TEMPLATE_FRAMESET = """<html>
132 <head><title>CherryPy coverage data</title></head>
133 <frameset cols='250, 1*'>
134 <frame src='menu?base=%s' />
135 <frame name='main' src='' />
136 </frameset>
137 </html>
138 """
139
140 TEMPLATE_COVERAGE = """<html>
141 <head>
142 <title>Coverage for %(name)s</title>
143 <style>
144 h2 { margin-bottom: .25em; }
145 p { margin: .25em; }
146 .covered { color: #000; background-color: #fff; }
147 .notcovered { color: #fee; background-color: #500; }
148 .excluded { color: #00f; background-color: #fff; }
149 table .covered, table .notcovered, table .excluded
150 { font-family: Andale Mono, monospace;
151 font-size: 10pt; white-space: pre; }
152
153 .lineno { background-color: #eee;}
154 .notcovered .lineno { background-color: #000;}
155 table { border-collapse: collapse;
156 </style>
157 </head>
158 <body>
159 <h2>%(name)s</h2>
160 <p>%(fullpath)s</p>
161 <p>Coverage: %(pc)s%%</p>"""
162
163 TEMPLATE_LOC_COVERED = """<tr class="covered">
164 <td class="lineno">%s&nbsp;</td>
165 <td>%s</td>
166 </tr>\n"""
167 TEMPLATE_LOC_NOT_COVERED = """<tr class="notcovered">
168 <td class="lineno">%s&nbsp;</td>
169 <td>%s</td>
170 </tr>\n"""
171 TEMPLATE_LOC_EXCLUDED = """<tr class="excluded">
172 <td class="lineno">%s&nbsp;</td>
173 <td>%s</td>
174 </tr>\n"""
175
176 TEMPLATE_ITEM = "%s%s<a class='file' href='report?name=%s' target='main'>%s</a>\ n"
177
178 def _percent(statements, missing):
179 s = len(statements)
180 e = s - len(missing)
181 if s > 0:
182 return int(round(100.0 * e / s))
183 return 0
184
185 def _show_branch(root, base, path, pct=0, showpct=False, exclude="",
186 coverage=the_coverage):
187
188 # Show the directory name and any of our children
189 dirs = [k for k, v in root.items() if v]
190 dirs.sort()
191 for name in dirs:
192 newpath = os.path.join(path, name)
193
194 if newpath.lower().startswith(base):
195 relpath = newpath[len(base):]
196 yield "| " * relpath.count(os.sep)
197 yield "<a class='directory' href='menu?base=%s&exclude=%s'>%s</a>\n" % \
198 (newpath, quote_plus(exclude), name)
199
200 for chunk in _show_branch(root[name], base, newpath, pct, showpct, exclu de, coverage=coverage):
201 yield chunk
202
203 # Now list the files
204 if path.lower().startswith(base):
205 relpath = path[len(base):]
206 files = [k for k, v in root.items() if not v]
207 files.sort()
208 for name in files:
209 newpath = os.path.join(path, name)
210
211 pc_str = ""
212 if showpct:
213 try:
214 _, statements, _, missing, _ = coverage.analysis2(newpath)
215 except:
216 # Yes, we really want to pass on all errors.
217 pass
218 else:
219 pc = _percent(statements, missing)
220 pc_str = ("%3d%% " % pc).replace(' ','&nbsp;')
221 if pc < float(pct) or pc == -1:
222 pc_str = "<span class='fail'>%s</span>" % pc_str
223 else:
224 pc_str = "<span class='pass'>%s</span>" % pc_str
225
226 yield TEMPLATE_ITEM % ("| " * (relpath.count(os.sep) + 1),
227 pc_str, newpath, name)
228
229 def _skip_file(path, exclude):
230 if exclude:
231 return bool(re.search(exclude, path))
232
233 def _graft(path, tree):
234 d = tree
235
236 p = path
237 atoms = []
238 while True:
239 p, tail = os.path.split(p)
240 if not tail:
241 break
242 atoms.append(tail)
243 atoms.append(p)
244 if p != "/":
245 atoms.append("/")
246
247 atoms.reverse()
248 for node in atoms:
249 if node:
250 d = d.setdefault(node, {})
251
252 def get_tree(base, exclude, coverage=the_coverage):
253 """Return covered module names as a nested dict."""
254 tree = {}
255 runs = coverage.data.executed_files()
256 for path in runs:
257 if not _skip_file(path, exclude) and not os.path.isdir(path):
258 _graft(path, tree)
259 return tree
260
261 class CoverStats(object):
262
263 def __init__(self, coverage, root=None):
264 self.coverage = coverage
265 if root is None:
266 # Guess initial depth. Files outside this path will not be
267 # reachable from the web interface.
268 import cherrypy
269 root = os.path.dirname(cherrypy.__file__)
270 self.root = root
271
272 def index(self):
273 return TEMPLATE_FRAMESET % self.root.lower()
274 index.exposed = True
275
276 def menu(self, base="/", pct="50", showpct="",
277 exclude=r'python\d\.\d|test|tut\d|tutorial'):
278
279 # The coverage module uses all-lower-case names.
280 base = base.lower().rstrip(os.sep)
281
282 yield TEMPLATE_MENU
283 yield TEMPLATE_FORM % locals()
284
285 # Start by showing links for parent paths
286 yield "<div id='crumbs'>"
287 path = ""
288 atoms = base.split(os.sep)
289 atoms.pop()
290 for atom in atoms:
291 path += atom + os.sep
292 yield ("<a href='menu?base=%s&exclude=%s'>%s</a> %s"
293 % (path, quote_plus(exclude), atom, os.sep))
294 yield "</div>"
295
296 yield "<div id='tree'>"
297
298 # Then display the tree
299 tree = get_tree(base, exclude, self.coverage)
300 if not tree:
301 yield "<p>No modules covered.</p>"
302 else:
303 for chunk in _show_branch(tree, base, "/", pct,
304 showpct=='checked', exclude, coverage=self .coverage):
305 yield chunk
306
307 yield "</div>"
308 yield "</body></html>"
309 menu.exposed = True
310
311 def annotated_file(self, filename, statements, excluded, missing):
312 source = open(filename, 'r')
313 buffer = []
314 for lineno, line in enumerate(source.readlines()):
315 lineno += 1
316 line = line.strip("\n\r")
317 empty_the_buffer = True
318 if lineno in excluded:
319 template = TEMPLATE_LOC_EXCLUDED
320 elif lineno in missing:
321 template = TEMPLATE_LOC_NOT_COVERED
322 elif lineno in statements:
323 template = TEMPLATE_LOC_COVERED
324 else:
325 empty_the_buffer = False
326 buffer.append((lineno, line))
327 if empty_the_buffer:
328 for lno, pastline in buffer:
329 yield template % (lno, cgi.escape(pastline))
330 buffer = []
331 yield template % (lineno, cgi.escape(line))
332
333 def report(self, name):
334 filename, statements, excluded, missing, _ = self.coverage.analysis2(nam e)
335 pc = _percent(statements, missing)
336 yield TEMPLATE_COVERAGE % dict(name=os.path.basename(name),
337 fullpath=name,
338 pc=pc)
339 yield '<table>\n'
340 for line in self.annotated_file(filename, statements, excluded,
341 missing):
342 yield line
343 yield '</table>'
344 yield '</body>'
345 yield '</html>'
346 report.exposed = True
347
348
349 def serve(path=localFile, port=8080, root=None):
350 if coverage is None:
351 raise ImportError("The coverage module could not be imported.")
352 from coverage import coverage
353 cov = coverage(data_file = path)
354 cov.load()
355
356 import cherrypy
357 cherrypy.config.update({'server.socket_port': int(port),
358 'server.thread_pool': 10,
359 'environment': "production",
360 })
361 cherrypy.quickstart(CoverStats(cov, root))
362
363 if __name__ == "__main__":
364 serve(*tuple(sys.argv[1:]))
365
OLDNEW
« no previous file with comments | « third_party/cherrypy/lib/caching.py ('k') | third_party/cherrypy/lib/cpstats.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698