Ticket #262: improve-covercp.patch
-
cherrypy/test/test.py
old new 209 209 sys.stdout.write(".") 210 210 sys.stdout.flush() 211 211 name = os.path.split(morf)[1] 212 if morf.find('test') != -1: 213 continue 212 214 try: 213 215 _, statements, _, missing, readable = self.coverage.analysis2(morf) 214 216 n = len(statements) -
cherrypy/lib/autoreload.py
old new 16 16 for filename in filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values())) + reloadFiles: 17 17 if filename.endswith(".pyc"): 18 18 filename = filename[:-1] 19 mtime = os.stat(filename).st_mtime 19 try: 20 mtime = os.stat(filename).st_mtime 21 except OSError: 22 sys.exit(3) # force reload 20 23 if filename not in mtimes: 21 24 mtimes[filename] = mtime 22 25 continue -
cherrypy/lib/covercp.py
old new 77 77 <title>CherryPy Coverage Menu</title> 78 78 <style> 79 79 body {font: 9pt Arial, serif;} 80 #tree {font: 8pt Courier, sans-serif;} 80 #tree { 81 font-size: 8pt; 82 font-family: Andale Mono, monospace; 83 white-space: pre; 84 } 81 85 #tree a:active, a:focus { 82 background-color: #EEEEFF;86 background-color: black; 83 87 padding: 1px; 84 border: 1px solid #9999FF; 88 color: white; 89 border: 0px solid #9999FF; 85 90 -moz-outline-style: none; 86 } 87 .fail {color: red;} 88 .pass {color: #888;} 89 #pct {text-align: right;} 90 h3 { font-size: small; font-weight: bold; font-style: italic; margin-top: 5px;} 91 } 92 .fail { color: red;} 93 .pass { color: #888;} 94 #pct { text-align: right;} 95 h3 { 96 font-size: small; 97 font-weight: bold; 98 font-style: italic; 99 margin-top: 5px; 100 } 91 101 input { border: 1px solid #ccc; padding: 2px; } 102 .directory { 103 color: #933; 104 font-style: italic; 105 font-weight: bold; 106 font-size: 10pt; 107 } 108 .file { 109 color: #400; 110 } 111 a { text-decoration: none; } 112 #crumbs { 113 color: white; 114 font-size: 8pt; 115 font-family: Andale Mono, monospace; 116 width: 100%; 117 background-color: black; 118 } 119 #crumbs a { 120 color: #f88; 121 } 122 #options { 123 line-height: 2.3em; 124 border: 1px solid black; 125 background-color: #eee; 126 padding: 4px; 127 } 128 #exclude { 129 width: 100%; 130 margin-bottom: 3px; 131 border: 1px solid #999; 132 } 133 #submit { 134 background-color: black; 135 color: white; 136 border: 0; 137 margin-bottom: -9px; 138 } 92 139 </style> 93 140 </head> 94 141 <body> 95 142 <h2>CherryPy Coverage</h2>""" 96 143 97 144 TEMPLATE_FORM = """ 145 <div id="options"> 98 146 <form action='menu' method=GET> 99 147 <input type='hidden' name='base' value='%(base)s' /> 100 <h3>Options</h3> 101 <input type='checkbox' %(showpct)s name='showpct' value='checked'/> 102 show percentages <br /> 148 Show percentages <input type='checkbox' %(showpct)s name='showpct' value='checked'/><br /> 103 149 Hide files over <input type='text' id='pct' name='pct' value='%(pct)s' size='3' />%%<br /> 104 150 Exclude files matching<br /> 105 151 <input type='text' id='exclude' name='exclude' value='%(exclude)s' size='20' /> 106 152 <br /> 107 153 108 <input type='submit' value='Change view' /> 109 </form>""" 154 <input type='submit' value='Change view' id="submit"/> 155 </form> 156 </div>""" 110 157 111 158 TEMPLATE_FRAMESET = """<html> 112 159 <head><title>CherryPy coverage data</title></head> … … 153 200 <td>%s</td> 154 201 </tr>\n""" 155 202 203 TEMPLATE_ITEM = "%s%s<a class='file' href='report?name=%s' target='main'>%s</a>\n" 156 204 157 def _skip_file(path, exclude):158 if exclude:159 return bool(re.search(exclude, path))160 161 205 def _percent(statements, missing): 162 206 s = len(statements) 163 207 e = s - len(missing) … … 168 212 def _show_branch(root, base="", path="", pct=0, showpct=False, exclude=""): 169 213 170 214 # Show the directory name and any of our children 171 dirs = [k for k, v in root.iteritems() if v is not None]215 dirs = [k for k, v in root.iteritems() if v] 172 216 dirs.sort() 173 217 for name in dirs: 174 if path: 218 if path == '/': 219 newpath = '/' + name 220 else: 175 221 newpath = os.sep.join((path, name)) 176 else:177 newpath = name178 222 179 223 if newpath.startswith(base): 180 224 relpath = newpath[len(base):] 181 yield "<nobr>" + ("| " * relpath.count(os.sep)) + "<b>" 182 yield ("<a href='menu?base=%s&exclude=%s'>%s</a>" % 183 (newpath, urllib.quote_plus(exclude), name)) 184 yield "</b></nobr><br />\n" 225 yield "| " * relpath.count(os.sep) 226 yield "<a class='directory' href='menu?base=%s&exclude=%s'>%s</a>\n" % \ 227 (newpath, urllib.quote_plus(exclude), name) 185 228 186 229 for chunk in _show_branch(root[name], base, newpath, pct, showpct, exclude): 187 230 yield chunk … … 189 232 # Now list the files 190 233 if path.startswith(base): 191 234 relpath = path[len(base):] 192 files = [k for k, v in root.iteritems() if v is None]235 files = [k for k, v in root.iteritems() if not v] 193 236 files.sort() 194 237 for name in files: 195 if path: 238 if path == '/': 239 newpath = '/' + name 240 else: 196 241 newpath = os.sep.join((path, name)) 197 else:198 newpath = name199 242 200 243 pc_str = "" 201 244 if showpct: … … 212 255 else: 213 256 pc_str = "<span class='pass'>%s</span>" % pc_str 214 257 215 yield ("<nobr>%s%s<a href='report?name=%s' target='main'>%s</a></nobr><br />\n" 216 % ("| " * (relpath.count(os.sep) + 1), pc_str, newpath, name))258 yield TEMPLATE_ITEM % ("| " * (relpath.count(os.sep) + 1), 259 pc_str, newpath, name) 217 260 261 def _skip_file(path, exclude): 262 if exclude: 263 return bool(re.search(exclude, path)) 264 265 def _graft(path, tree): 266 d = tree 267 for node in path.split(os.sep): 268 if node: 269 d = d.setdefault(node, {}) 270 218 271 def get_tree(base, exclude): 219 272 """Return covered module names as a nested dict.""" 220 273 tree = {} 221 274 coverage.get_ready() 222 275 runs = coverage.cexecuted.keys() 223 276 if runs: 224 tree = {}225 def graft(path):226 head, tail = os.path.split(path)227 if tail:228 return graft(head).setdefault(tail, {})229 else:230 return tree.setdefault(head.strip(r"\/"), {})231 232 277 for path in runs: 233 278 if not _skip_file(path, exclude) and not os.path.isdir(path): 234 head, tail = os.path.split(path) 235 if head.startswith(base): 236 graft(head)[tail] = None 279 _graft(path, tree) 237 280 return tree 238 281 239 240 282 class CoverStats(object): 241 283 242 284 def index(self): 243 285 return TEMPLATE_FRAMESET 244 286 index.exposed = True 245 287 246 def menu(self, base=" ", pct="50", showpct="",288 def menu(self, base="/", pct="50", showpct="", 247 289 exclude=r'python\d\.\d|test|tut\d|tutorial'): 248 290 249 291 # The coverage module uses all-lower-case names. … … 252 294 yield TEMPLATE_MENU 253 295 yield TEMPLATE_FORM % locals() 254 296 255 yield "<div id='tree'>"256 257 297 # Start by showing links for parent paths 298 yield "<div id='crumbs'>" 258 299 path = "" 259 300 atoms = base.split(os.sep) 260 301 atoms.pop() 261 302 for atom in atoms: 262 303 path += atom + os.sep 263 yield ("< nobr><b><a href='menu?base=%s&exclude=%s'>%s</a></b></nobr>%s\n"304 yield ("<a href='menu?base=%s&exclude=%s'>%s</a> %s" 264 305 % (path, urllib.quote_plus(exclude), atom, os.sep)) 306 yield "</div>" 265 307 308 yield "<div id='tree'>" 309 310 # Then display the tree 266 311 tree = get_tree(base, exclude) 267 312 if not tree: 268 313 yield "<p>No modules covered.</p>" 269 314 else: 270 # Now show all visible branches 271 yield "<br />" 272 for chunk in _show_branch(tree, base, "", pct, showpct=='checked', exclude): 315 for chunk in _show_branch(tree, base, '/', pct, 316 showpct=='checked', exclude): 273 317 yield chunk 274 318 275 319 yield "</div>" … … 315 359 316 360 def serve(path=localFile, port=8080): 317 361 if coverage is None: 318 raise ImportError(" <p>The coverage module could not be imported.</p>")362 raise ImportError("The coverage module could not be imported.") 319 363 coverage.cache_default = path 320 364 321 365 import cherrypy 322 366 cherrypy.root = CoverStats() 323 367 cherrypy.config.update({'server.socketPort': port, 324 368 'server.threadPool': 10, 325 'server.environment': " production",369 'server.environment': "development", 326 370 }) 327 371 cherrypy.server.start() 328 372

