comparison tests/coverage.py @ 3223:53e843840349

Whitespace/Tab cleanup
author Thomas Arendsen Hein <thomas@intevation.de>
date Sun, 01 Oct 2006 19:26:33 +0200
parents d3bddedfdbd0
children 306055f5b65c
comparison
equal deleted inserted replaced
3222:a5603ad915c5 3223:53e843840349
85 compiler.visitor.ASTVisitor.__init__(self) 85 compiler.visitor.ASTVisitor.__init__(self)
86 self.statements = statements 86 self.statements = statements
87 self.excluded = excluded 87 self.excluded = excluded
88 self.suite_spots = suite_spots 88 self.suite_spots = suite_spots
89 self.excluding_suite = 0 89 self.excluding_suite = 0
90 90
91 def doRecursive(self, node): 91 def doRecursive(self, node):
92 self.recordNodeLine(node) 92 self.recordNodeLine(node)
93 for n in node.getChildNodes(): 93 for n in node.getChildNodes():
94 self.dispatch(n) 94 self.dispatch(n)
95 95
96 visitStmt = visitModule = doRecursive 96 visitStmt = visitModule = doRecursive
97 97
98 def doCode(self, node): 98 def doCode(self, node):
99 if hasattr(node, 'decorators') and node.decorators: 99 if hasattr(node, 'decorators') and node.decorators:
100 self.dispatch(node.decorators) 100 self.dispatch(node.decorators)
101 self.doSuite(node, node.code) 101 self.doSuite(node, node.code)
102 102
103 visitFunction = visitClass = doCode 103 visitFunction = visitClass = doCode
104 104
105 def getFirstLine(self, node): 105 def getFirstLine(self, node):
106 # Find the first line in the tree node. 106 # Find the first line in the tree node.
107 lineno = node.lineno 107 lineno = node.lineno
117 # Find the first line in the tree node. 117 # Find the first line in the tree node.
118 lineno = node.lineno 118 lineno = node.lineno
119 for n in node.getChildNodes(): 119 for n in node.getChildNodes():
120 lineno = max(lineno, self.getLastLine(n)) 120 lineno = max(lineno, self.getLastLine(n))
121 return lineno 121 return lineno
122 122
123 def doStatement(self, node): 123 def doStatement(self, node):
124 self.recordLine(self.getFirstLine(node)) 124 self.recordLine(self.getFirstLine(node))
125 125
126 visitAssert = visitAssign = visitAssTuple = visitDiscard = visitPrint = \ 126 visitAssert = visitAssign = visitAssTuple = visitDiscard = visitPrint = \
127 visitPrintnl = visitRaise = visitSubscript = visitDecorators = \ 127 visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
128 doStatement 128 doStatement
129 129
130 def recordNodeLine(self, node): 130 def recordNodeLine(self, node):
131 return self.recordLine(node.lineno) 131 return self.recordLine(node.lineno)
132 132
133 def recordLine(self, lineno): 133 def recordLine(self, lineno):
134 # Returns a bool, whether the line is included or excluded. 134 # Returns a bool, whether the line is included or excluded.
135 if lineno: 135 if lineno:
136 # Multi-line tests introducing suites have to get charged to their 136 # Multi-line tests introducing suites have to get charged to their
137 # keyword. 137 # keyword.
151 # Otherwise, this is an executable line. 151 # Otherwise, this is an executable line.
152 else: 152 else:
153 self.statements[lineno] = 1 153 self.statements[lineno] = 1
154 return 1 154 return 1
155 return 0 155 return 0
156 156
157 default = recordNodeLine 157 default = recordNodeLine
158 158
159 def recordAndDispatch(self, node): 159 def recordAndDispatch(self, node):
160 self.recordNodeLine(node) 160 self.recordNodeLine(node)
161 self.dispatch(node) 161 self.dispatch(node)
162 162
163 def doSuite(self, intro, body, exclude=0): 163 def doSuite(self, intro, body, exclude=0):
164 exsuite = self.excluding_suite 164 exsuite = self.excluding_suite
165 if exclude or (intro and not self.recordNodeLine(intro)): 165 if exclude or (intro and not self.recordNodeLine(intro)):
166 self.excluding_suite = 1 166 self.excluding_suite = 1
167 self.recordAndDispatch(body) 167 self.recordAndDispatch(body)
168 self.excluding_suite = exsuite 168 self.excluding_suite = exsuite
169 169
170 def doPlainWordSuite(self, prevsuite, suite): 170 def doPlainWordSuite(self, prevsuite, suite):
171 # Finding the exclude lines for else's is tricky, because they aren't 171 # Finding the exclude lines for else's is tricky, because they aren't
172 # present in the compiler parse tree. Look at the previous suite, 172 # present in the compiler parse tree. Look at the previous suite,
173 # and find its last line. If any line between there and the else's 173 # and find its last line. If any line between there and the else's
174 # first line are excluded, then we exclude the else. 174 # first line are excluded, then we exclude the else.
178 if self.suite_spots.has_key(l): 178 if self.suite_spots.has_key(l):
179 self.doSuite(None, suite, exclude=self.excluded.has_key(l)) 179 self.doSuite(None, suite, exclude=self.excluded.has_key(l))
180 break 180 break
181 else: 181 else:
182 self.doSuite(None, suite) 182 self.doSuite(None, suite)
183 183
184 def doElse(self, prevsuite, node): 184 def doElse(self, prevsuite, node):
185 if node.else_: 185 if node.else_:
186 self.doPlainWordSuite(prevsuite, node.else_) 186 self.doPlainWordSuite(prevsuite, node.else_)
187 187
188 def visitFor(self, node): 188 def visitFor(self, node):
189 self.doSuite(node, node.body) 189 self.doSuite(node, node.body)
190 self.doElse(node.body, node) 190 self.doElse(node.body, node)
191 191
192 def visitIf(self, node): 192 def visitIf(self, node):
214 prev = node.body 214 prev = node.body
215 self.doPlainWordSuite(prev, h) 215 self.doPlainWordSuite(prev, h)
216 else: 216 else:
217 self.doSuite(a, h) 217 self.doSuite(a, h)
218 self.doElse(node.handlers[-1][2], node) 218 self.doElse(node.handlers[-1][2], node)
219 219
220 def visitTryFinally(self, node): 220 def visitTryFinally(self, node):
221 self.doSuite(node, node.body) 221 self.doSuite(node, node.body)
222 self.doPlainWordSuite(node.body, node.final) 222 self.doPlainWordSuite(node.body, node.final)
223 223
224 def visitGlobal(self, node): 224 def visitGlobal(self, node):
225 # "global" statements don't execute like others (they don't call the 225 # "global" statements don't execute like others (they don't call the
226 # trace function), so don't record their line numbers. 226 # trace function), so don't record their line numbers.
227 pass 227 pass
228 228
238 cache_env = "COVERAGE_FILE" 238 cache_env = "COVERAGE_FILE"
239 239
240 # A dictionary with an entry for (Python source file name, line number 240 # A dictionary with an entry for (Python source file name, line number
241 # in that file) if that line has been executed. 241 # in that file) if that line has been executed.
242 c = {} 242 c = {}
243 243
244 # A map from canonical Python source file name to a dictionary in 244 # A map from canonical Python source file name to a dictionary in
245 # which there's an entry for each line number that has been 245 # which there's an entry for each line number that has been
246 # executed. 246 # executed.
247 cexecuted = {} 247 cexecuted = {}
248 248
264 self.nesting = 0 264 self.nesting = 0
265 self.cstack = [] 265 self.cstack = []
266 self.xstack = [] 266 self.xstack = []
267 self.relative_dir = os.path.normcase(os.path.abspath(os.curdir)+os.path.sep) 267 self.relative_dir = os.path.normcase(os.path.abspath(os.curdir)+os.path.sep)
268 268
269 # t(f, x, y). This method is passed to sys.settrace as a trace function. 269 # t(f, x, y). This method is passed to sys.settrace as a trace function.
270 # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and 270 # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and
271 # the arguments and return value of the trace function. 271 # the arguments and return value of the trace function.
272 # See [van Rossum 2001-07-20a, 3.2] for a description of frame and code 272 # See [van Rossum 2001-07-20a, 3.2] for a description of frame and code
273 # objects. 273 # objects.
274 274
275 def t(self, f, w, a): #pragma: no cover 275 def t(self, f, w, a): #pragma: no cover
276 #print w, f.f_code.co_filename, f.f_lineno 276 #print w, f.f_code.co_filename, f.f_lineno
277 if w == 'line': 277 if w == 'line':
278 self.c[(f.f_code.co_filename, f.f_lineno)] = 1 278 self.c[(f.f_code.co_filename, f.f_lineno)] = 1
279 for c in self.cstack: 279 for c in self.cstack:
280 c[(f.f_code.co_filename, f.f_lineno)] = 1 280 c[(f.f_code.co_filename, f.f_lineno)] = 1
281 return self.t 281 return self.t
282 282
283 def help(self, error=None): 283 def help(self, error=None):
284 if error: 284 if error:
285 print error 285 print error
286 print 286 print
287 print __doc__ 287 print __doc__
328 action = settings.get('erase') or args_needed 328 action = settings.get('erase') or args_needed
329 if not action: 329 if not action:
330 self.help("You must specify at least one of -e, -x, -r, or -a.") 330 self.help("You must specify at least one of -e, -x, -r, or -a.")
331 if not args_needed and args: 331 if not args_needed and args:
332 self.help("Unexpected arguments %s." % args) 332 self.help("Unexpected arguments %s." % args)
333 333
334 self.get_ready() 334 self.get_ready()
335 self.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]') 335 self.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]')
336 336
337 if settings.get('erase'): 337 if settings.get('erase'):
338 self.erase() 338 self.erase()
357 if settings.get('annotate'): 357 if settings.get('annotate'):
358 self.annotate(args, directory, ignore_errors, omit_prefixes=omit) 358 self.annotate(args, directory, ignore_errors, omit_prefixes=omit)
359 359
360 def use_cache(self, usecache): 360 def use_cache(self, usecache):
361 self.usecache = usecache 361 self.usecache = usecache
362 362
363 def get_ready(self): 363 def get_ready(self):
364 if self.usecache and not self.cache: 364 if self.usecache and not self.cache:
365 self.cache = os.path.abspath(os.environ.get(self.cache_env, 365 self.cache = os.path.abspath(os.environ.get(self.cache_env,
366 self.cache_default)) 366 self.cache_default))
367 self.restore() 367 self.restore()
368 self.analysis_cache = {} 368 self.analysis_cache = {}
369 369
370 def start(self): 370 def start(self):
371 self.get_ready() 371 self.get_ready()
372 if self.nesting == 0: #pragma: no cover 372 if self.nesting == 0: #pragma: no cover
373 sys.settrace(self.t) 373 sys.settrace(self.t)
374 if hasattr(threading, 'settrace'): 374 if hasattr(threading, 'settrace'):
375 threading.settrace(self.t) 375 threading.settrace(self.t)
376 self.nesting += 1 376 self.nesting += 1
377 377
378 def stop(self): 378 def stop(self):
379 self.nesting -= 1 379 self.nesting -= 1
380 if self.nesting == 0: #pragma: no cover 380 if self.nesting == 0: #pragma: no cover
381 sys.settrace(None) 381 sys.settrace(None)
382 if hasattr(threading, 'settrace'): 382 if hasattr(threading, 'settrace'):
396 self.exclude_re += "(" + re + ")" 396 self.exclude_re += "(" + re + ")"
397 397
398 def begin_recursive(self): 398 def begin_recursive(self):
399 self.cstack.append(self.c) 399 self.cstack.append(self.c)
400 self.xstack.append(self.exclude_re) 400 self.xstack.append(self.exclude_re)
401 401
402 def end_recursive(self): 402 def end_recursive(self):
403 self.c = self.cstack.pop() 403 self.c = self.cstack.pop()
404 self.exclude_re = self.xstack.pop() 404 self.exclude_re = self.xstack.pop()
405 405
406 # save(). Save coverage data to the coverage cache. 406 # save(). Save coverage data to the coverage cache.
450 break 450 break
451 cf = os.path.normcase(os.path.abspath(f)) 451 cf = os.path.normcase(os.path.abspath(f))
452 self.canonical_filename_cache[filename] = cf 452 self.canonical_filename_cache[filename] = cf
453 return self.canonical_filename_cache[filename] 453 return self.canonical_filename_cache[filename]
454 454
455 # canonicalize_filenames(). Copy results from "c" to "cexecuted", 455 # canonicalize_filenames(). Copy results from "c" to "cexecuted",
456 # canonicalizing filenames on the way. Clear the "c" map. 456 # canonicalizing filenames on the way. Clear the "c" map.
457 457
458 def canonicalize_filenames(self): 458 def canonicalize_filenames(self):
459 for filename, lineno in self.c.keys(): 459 for filename, lineno in self.c.keys():
460 f = self.canonical_filename(filename) 460 f = self.canonical_filename(filename)
548 excluded[i+1] = 1 548 excluded[i+1] = 1
549 549
550 import parser 550 import parser
551 tree = parser.suite(text+'\n\n').totuple(1) 551 tree = parser.suite(text+'\n\n').totuple(1)
552 self.get_suite_spots(tree, suite_spots) 552 self.get_suite_spots(tree, suite_spots)
553 553
554 # Use the compiler module to parse the text and find the executable 554 # Use the compiler module to parse the text and find the executable
555 # statements. We add newlines to be impervious to final partial lines. 555 # statements. We add newlines to be impervious to final partial lines.
556 statements = {} 556 statements = {}
557 ast = compiler.parse(text+'\n\n') 557 ast = compiler.parse(text+'\n\n')
558 visitor = StatementFindingAstVisitor(statements, excluded, suite_spots) 558 visitor = StatementFindingAstVisitor(statements, excluded, suite_spots)
711 except KeyboardInterrupt: 711 except KeyboardInterrupt:
712 raise 712 raise
713 except: 713 except:
714 if not ignore_errors: 714 if not ignore_errors:
715 raise 715 raise
716 716
717 def annotate_file(self, filename, statements, excluded, missing, directory=None): 717 def annotate_file(self, filename, statements, excluded, missing, directory=None):
718 source = open(filename, 'r') 718 source = open(filename, 'r')
719 if directory: 719 if directory:
720 dest_file = os.path.join(directory, 720 dest_file = os.path.join(directory,
721 os.path.basename(filename) 721 os.path.basename(filename)
739 if i < len(statements) and statements[i] == lineno: 739 if i < len(statements) and statements[i] == lineno:
740 covered = j >= len(missing) or missing[j] > lineno 740 covered = j >= len(missing) or missing[j] > lineno
741 if self.blank_re.match(line): 741 if self.blank_re.match(line):
742 dest.write(' ') 742 dest.write(' ')
743 elif self.else_re.match(line): 743 elif self.else_re.match(line):
744 # Special logic for lines containing only 'else:'. 744 # Special logic for lines containing only 'else:'.
745 # See [GDR 2001-12-04b, 3.2]. 745 # See [GDR 2001-12-04b, 3.2].
746 if i >= len(statements) and j >= len(missing): 746 if i >= len(statements) and j >= len(missing):
747 dest.write('! ') 747 dest.write('! ')
748 elif i >= len(statements) or j >= len(missing): 748 elif i >= len(statements) or j >= len(missing):
749 dest.write('> ') 749 dest.write('> ')
848 # 848 #
849 # 2004-12-31 NMB Allow for keyword arguments in the module global functions. 849 # 2004-12-31 NMB Allow for keyword arguments in the module global functions.
850 # Thanks, Allen. 850 # Thanks, Allen.
851 # 851 #
852 # 2005-12-02 NMB Call threading.settrace so that all threads are measured. 852 # 2005-12-02 NMB Call threading.settrace so that all threads are measured.
853 # Thanks Martin Fuzzey. Add a file argument to report so that reports can be 853 # Thanks Martin Fuzzey. Add a file argument to report so that reports can be
854 # captured to a different destination. 854 # captured to a different destination.
855 # 855 #
856 # 2005-12-03 NMB coverage.py can now measure itself. 856 # 2005-12-03 NMB coverage.py can now measure itself.
857 # 857 #
858 # 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames, 858 # 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames,