| OLD | NEW |
| 1 """Raw data collector for Coverage.""" | 1 """Raw data collector for Coverage.""" |
| 2 | 2 |
| 3 import os, sys, threading | 3 import os, sys, threading |
| 4 | 4 |
| 5 try: | 5 try: |
| 6 # Use the C extension code when we can, for speed. | 6 # Use the C extension code when we can, for speed. |
| 7 from coverage.tracer import CTracer # pylint: disable=F0401,E0611 | 7 from coverage.tracer import CTracer # pylint: disable=F0401,E0611 |
| 8 except ImportError: | 8 except ImportError: |
| 9 # Couldn't import the C extension, maybe it isn't built. | 9 # Couldn't import the C extension, maybe it isn't built. |
| 10 if os.getenv('COVERAGE_TEST_TRACER') == 'c': | 10 if os.getenv('COVERAGE_TEST_TRACER') == 'c': |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 self.data = None | 44 self.data = None |
| 45 self.should_trace = None | 45 self.should_trace = None |
| 46 self.should_trace_cache = None | 46 self.should_trace_cache = None |
| 47 self.warn = None | 47 self.warn = None |
| 48 self.cur_file_data = None | 48 self.cur_file_data = None |
| 49 self.last_line = 0 | 49 self.last_line = 0 |
| 50 self.data_stack = [] | 50 self.data_stack = [] |
| 51 self.last_exc_back = None | 51 self.last_exc_back = None |
| 52 self.last_exc_firstlineno = 0 | 52 self.last_exc_firstlineno = 0 |
| 53 self.arcs = False | 53 self.arcs = False |
| 54 self.thread = None |
| 55 self.stopped = False |
| 54 | 56 |
| 55 def _trace(self, frame, event, arg_unused): | 57 def _trace(self, frame, event, arg_unused): |
| 56 """The trace function passed to sys.settrace.""" | 58 """The trace function passed to sys.settrace.""" |
| 57 | 59 |
| 58 #print("trace event: %s %r @%d" % ( | 60 if self.stopped: |
| 59 # event, frame.f_code.co_filename, frame.f_lineno), | 61 return |
| 60 # file=sys.stderr) | 62 |
| 63 if 0: |
| 64 sys.stderr.write("trace event: %s %r @%d\n" % ( |
| 65 event, frame.f_code.co_filename, frame.f_lineno |
| 66 )) |
| 61 | 67 |
| 62 if self.last_exc_back: | 68 if self.last_exc_back: |
| 63 if frame == self.last_exc_back: | 69 if frame == self.last_exc_back: |
| 64 # Someone forgot a return event. | 70 # Someone forgot a return event. |
| 65 if self.arcs and self.cur_file_data: | 71 if self.arcs and self.cur_file_data: |
| 66 pair = (self.last_line, -self.last_exc_firstlineno) | 72 pair = (self.last_line, -self.last_exc_firstlineno) |
| 67 self.cur_file_data[pair] = None | 73 self.cur_file_data[pair] = None |
| 68 self.cur_file_data, self.last_line = self.data_stack.pop() | 74 self.cur_file_data, self.last_line = self.data_stack.pop() |
| 69 self.last_exc_back = None | 75 self.last_exc_back = None |
| 70 | 76 |
| 71 if event == 'call': | 77 if event == 'call': |
| 72 # Entering a new function context. Decide if we should trace | 78 # Entering a new function context. Decide if we should trace |
| 73 # in this file. | 79 # in this file. |
| 74 self.data_stack.append((self.cur_file_data, self.last_line)) | 80 self.data_stack.append((self.cur_file_data, self.last_line)) |
| 75 filename = frame.f_code.co_filename | 81 filename = frame.f_code.co_filename |
| 76 tracename = self.should_trace_cache.get(filename) | 82 if filename not in self.should_trace_cache: |
| 77 if tracename is None: | |
| 78 tracename = self.should_trace(filename, frame) | 83 tracename = self.should_trace(filename, frame) |
| 79 self.should_trace_cache[filename] = tracename | 84 self.should_trace_cache[filename] = tracename |
| 85 else: |
| 86 tracename = self.should_trace_cache[filename] |
| 80 #print("called, stack is %d deep, tracename is %r" % ( | 87 #print("called, stack is %d deep, tracename is %r" % ( |
| 81 # len(self.data_stack), tracename)) | 88 # len(self.data_stack), tracename)) |
| 82 if tracename: | 89 if tracename: |
| 83 if tracename not in self.data: | 90 if tracename not in self.data: |
| 84 self.data[tracename] = {} | 91 self.data[tracename] = {} |
| 85 self.cur_file_data = self.data[tracename] | 92 self.cur_file_data = self.data[tracename] |
| 86 else: | 93 else: |
| 87 self.cur_file_data = None | 94 self.cur_file_data = None |
| 88 # Set the last_line to -1 because the next arc will be entering a | 95 # Set the last_line to -1 because the next arc will be entering a |
| 89 # code block, indicated by (-1, n). | 96 # code block, indicated by (-1, n). |
| (...skipping 20 matching lines...) Expand all Loading... |
| 110 self.last_exc_back = frame.f_back | 117 self.last_exc_back = frame.f_back |
| 111 self.last_exc_firstlineno = frame.f_code.co_firstlineno | 118 self.last_exc_firstlineno = frame.f_code.co_firstlineno |
| 112 return self._trace | 119 return self._trace |
| 113 | 120 |
| 114 def start(self): | 121 def start(self): |
| 115 """Start this Tracer. | 122 """Start this Tracer. |
| 116 | 123 |
| 117 Return a Python function suitable for use with sys.settrace(). | 124 Return a Python function suitable for use with sys.settrace(). |
| 118 | 125 |
| 119 """ | 126 """ |
| 127 self.thread = threading.currentThread() |
| 120 sys.settrace(self._trace) | 128 sys.settrace(self._trace) |
| 121 return self._trace | 129 return self._trace |
| 122 | 130 |
| 123 def stop(self): | 131 def stop(self): |
| 124 """Stop this Tracer.""" | 132 """Stop this Tracer.""" |
| 133 self.stopped = True |
| 134 if self.thread != threading.currentThread(): |
| 135 # Called on a different thread than started us: we can't unhook |
| 136 # ourseves, but we've set the flag that we should stop, so we won't |
| 137 # do any more tracing. |
| 138 return |
| 139 |
| 125 if hasattr(sys, "gettrace") and self.warn: | 140 if hasattr(sys, "gettrace") and self.warn: |
| 126 if sys.gettrace() != self._trace: | 141 if sys.gettrace() != self._trace: |
| 127 msg = "Trace function changed, measurement is likely wrong: %r" | 142 msg = "Trace function changed, measurement is likely wrong: %r" |
| 128 self.warn(msg % (sys.gettrace(),)) | 143 self.warn(msg % (sys.gettrace(),)) |
| 129 #--debug | 144 #print("Stopping tracer on %s" % threading.current_thread().ident) |
| 130 #from coverage.misc import short_stack | |
| 131 #self.warn(msg % (sys.gettrace()))#, short_stack())) | |
| 132 sys.settrace(None) | 145 sys.settrace(None) |
| 133 | 146 |
| 134 def get_stats(self): | 147 def get_stats(self): |
| 135 """Return a dictionary of statistics, or None.""" | 148 """Return a dictionary of statistics, or None.""" |
| 136 return None | 149 return None |
| 137 | 150 |
| 138 | 151 |
| 139 class Collector(object): | 152 class Collector(object): |
| 140 """Collects trace data. | 153 """Collects trace data. |
| 141 | 154 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 154 | 167 |
| 155 # The stack of active Collectors. Collectors are added here when started, | 168 # The stack of active Collectors. Collectors are added here when started, |
| 156 # and popped when stopped. Collectors on the stack are paused when not | 169 # and popped when stopped. Collectors on the stack are paused when not |
| 157 # the top, and resumed when they become the top again. | 170 # the top, and resumed when they become the top again. |
| 158 _collectors = [] | 171 _collectors = [] |
| 159 | 172 |
| 160 def __init__(self, should_trace, timid, branch, warn): | 173 def __init__(self, should_trace, timid, branch, warn): |
| 161 """Create a collector. | 174 """Create a collector. |
| 162 | 175 |
| 163 `should_trace` is a function, taking a filename, and returning a | 176 `should_trace` is a function, taking a filename, and returning a |
| 164 canonicalized filename, or False depending on whether the file should | 177 canonicalized filename, or None depending on whether the file should |
| 165 be traced or not. | 178 be traced or not. |
| 166 | 179 |
| 167 If `timid` is true, then a slower simpler trace function will be | 180 If `timid` is true, then a slower simpler trace function will be |
| 168 used. This is important for some environments where manipulation of | 181 used. This is important for some environments where manipulation of |
| 169 tracing functions make the faster more sophisticated trace function not | 182 tracing functions make the faster more sophisticated trace function not |
| 170 operate properly. | 183 operate properly. |
| 171 | 184 |
| 172 If `branch` is true, then branches will be measured. This involves | 185 If `branch` is true, then branches will be measured. This involves |
| 173 collecting data on which statements followed each other (arcs). Use | 186 collecting data on which statements followed each other (arcs). Use |
| 174 `get_arc_data` to get the arc data. | 187 `get_arc_data` to get the arc data. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 198 return self._trace_class.__name__ | 211 return self._trace_class.__name__ |
| 199 | 212 |
| 200 def reset(self): | 213 def reset(self): |
| 201 """Clear collected data, and prepare to collect more.""" | 214 """Clear collected data, and prepare to collect more.""" |
| 202 # A dictionary mapping filenames to dicts with linenumber keys, | 215 # A dictionary mapping filenames to dicts with linenumber keys, |
| 203 # or mapping filenames to dicts with linenumber pairs as keys. | 216 # or mapping filenames to dicts with linenumber pairs as keys. |
| 204 self.data = {} | 217 self.data = {} |
| 205 | 218 |
| 206 # A cache of the results from should_trace, the decision about whether | 219 # A cache of the results from should_trace, the decision about whether |
| 207 # to trace execution in a file. A dict of filename to (filename or | 220 # to trace execution in a file. A dict of filename to (filename or |
| 208 # False). | 221 # None). |
| 209 self.should_trace_cache = {} | 222 self.should_trace_cache = {} |
| 210 | 223 |
| 211 # Our active Tracers. | 224 # Our active Tracers. |
| 212 self.tracers = [] | 225 self.tracers = [] |
| 213 | 226 |
| 214 def _start_tracer(self): | 227 def _start_tracer(self): |
| 215 """Start a new Tracer object, and store it in self.tracers.""" | 228 """Start a new Tracer object, and store it in self.tracers.""" |
| 216 tracer = self._trace_class() | 229 tracer = self._trace_class() |
| 217 tracer.data = self.data | 230 tracer.data = self.data |
| 218 tracer.arcs = self.branch | 231 tracer.arcs = self.branch |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 Data is { filename: { (l1, l2): None, ...}, ...} | 344 Data is { filename: { (l1, l2): None, ...}, ...} |
| 332 | 345 |
| 333 Note that no data is collected or returned if the Collector wasn't | 346 Note that no data is collected or returned if the Collector wasn't |
| 334 created with `branch` true. | 347 created with `branch` true. |
| 335 | 348 |
| 336 """ | 349 """ |
| 337 if self.branch: | 350 if self.branch: |
| 338 return self.data | 351 return self.data |
| 339 else: | 352 else: |
| 340 return {} | 353 return {} |
| OLD | NEW |