Mercurial > hg
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, |