eric7/DebugClients/Python/coverage/pytracer.py

branch
eric7
changeset 8527
2bd1325d727e
parent 8312
800c432b34c8
child 8775
0802ae193343
equal deleted inserted replaced
8526:587202572b10 8527:2bd1325d727e
11 11
12 # We need the YIELD_VALUE opcode below, in a comparison-friendly form. 12 # We need the YIELD_VALUE opcode below, in a comparison-friendly form.
13 YIELD_VALUE = dis.opmap['YIELD_VALUE'] 13 YIELD_VALUE = dis.opmap['YIELD_VALUE']
14 if env.PY2: 14 if env.PY2:
15 YIELD_VALUE = chr(YIELD_VALUE) 15 YIELD_VALUE = chr(YIELD_VALUE)
16
17 # When running meta-coverage, this file can try to trace itself, which confuses
18 # everything. Don't trace ourselves.
19
20 THIS_FILE = __file__.rstrip("co")
16 21
17 22
18 class PyTracer(object): 23 class PyTracer(object):
19 """Python implementation of the raw data tracer.""" 24 """Python implementation of the raw data tracer."""
20 25
70 ) 75 )
71 76
72 def log(self, marker, *args): 77 def log(self, marker, *args):
73 """For hard-core logging of what this tracer is doing.""" 78 """For hard-core logging of what this tracer is doing."""
74 with open("/tmp/debug_trace.txt", "a") as f: 79 with open("/tmp/debug_trace.txt", "a") as f:
75 f.write("{} {:x}.{:x}[{}] {:x} {}\n".format( 80 f.write("{} {}[{}]".format(
76 marker, 81 marker,
77 id(self), 82 id(self),
78 self.thread.ident,
79 len(self.data_stack), 83 len(self.data_stack),
80 self.threading.currentThread().ident,
81 " ".join(map(str, args))
82 )) 84 ))
85 if 0:
86 f.write(".{:x}.{:x}".format(
87 self.thread.ident,
88 self.threading.currentThread().ident,
89 ))
90 f.write(" {}".format(" ".join(map(str, args))))
91 if 0:
92 f.write(" | ")
93 stack = " / ".join(
94 (fname or "???").rpartition("/")[-1]
95 for _, fname, _, _ in self.data_stack
96 )
97 f.write(stack)
98 f.write("\n")
83 99
84 def _trace(self, frame, event, arg_unused): 100 def _trace(self, frame, event, arg_unused):
85 """The trace function passed to sys.settrace.""" 101 """The trace function passed to sys.settrace."""
86 102
87 #self.log(":", frame.f_code.co_filename, frame.f_lineno, event) 103 if THIS_FILE in frame.f_code.co_filename:
104 return None
105
106 #self.log(":", frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name + "()", event)
88 107
89 if (self.stopped and sys.gettrace() == self._trace): # pylint: disable=comparison-with-callable 108 if (self.stopped and sys.gettrace() == self._trace): # pylint: disable=comparison-with-callable
90 # The PyTrace.stop() method has been called, possibly by another 109 # The PyTrace.stop() method has been called, possibly by another
91 # thread, let's deactivate ourselves now. 110 # thread, let's deactivate ourselves now.
92 #self.log("X", frame.f_code.co_filename, frame.f_lineno) 111 if 0:
112 self.log("---\nX", frame.f_code.co_filename, frame.f_lineno)
113 f = frame
114 while f:
115 self.log(">", f.f_code.co_filename, f.f_lineno, f.f_code.co_name, f.f_trace)
116 f = f.f_back
93 sys.settrace(None) 117 sys.settrace(None)
118 self.cur_file_dict, self.cur_file_name, self.last_line, self.started_context = (
119 self.data_stack.pop()
120 )
94 return None 121 return None
95 122
96 if self.last_exc_back: 123 if self.last_exc_back:
97 if frame == self.last_exc_back: 124 if frame == self.last_exc_back:
98 # Someone forgot a return event. 125 # Someone forgot a return event.
102 self.cur_file_dict, self.cur_file_name, self.last_line, self.started_context = ( 129 self.cur_file_dict, self.cur_file_name, self.last_line, self.started_context = (
103 self.data_stack.pop() 130 self.data_stack.pop()
104 ) 131 )
105 self.last_exc_back = None 132 self.last_exc_back = None
106 133
134 # if event != 'call' and frame.f_code.co_filename != self.cur_file_name:
135 # self.log("---\n*", frame.f_code.co_filename, self.cur_file_name, frame.f_lineno)
136
107 if event == 'call': 137 if event == 'call':
108 # Should we start a new context? 138 # Should we start a new context?
109 if self.should_start_context and self.context is None: 139 if self.should_start_context and self.context is None:
110 context_maybe = self.should_start_context(frame) # pylint: disable=not-callable 140 context_maybe = self.should_start_context(frame)
111 if context_maybe is not None: 141 if context_maybe is not None:
112 self.context = context_maybe 142 self.context = context_maybe
113 self.started_context = True 143 self.started_context = True
114 self.switch_context(self.context) 144 self.switch_context(self.context)
115 else: 145 else:
130 ) 160 )
131 filename = frame.f_code.co_filename 161 filename = frame.f_code.co_filename
132 self.cur_file_name = filename 162 self.cur_file_name = filename
133 disp = self.should_trace_cache.get(filename) 163 disp = self.should_trace_cache.get(filename)
134 if disp is None: 164 if disp is None:
135 disp = self.should_trace(filename, frame) # pylint: disable=not-callable 165 disp = self.should_trace(filename, frame)
136 self.should_trace_cache[filename] = disp # pylint: disable=unsupported-assignment-operation 166 self.should_trace_cache[filename] = disp
137 167
138 self.cur_file_dict = None 168 self.cur_file_dict = None
139 if disp.trace: 169 if disp.trace:
140 tracename = disp.source_filename 170 tracename = disp.source_filename
141 if tracename not in self.data: # pylint: disable=unsupported-membership-test 171 if tracename not in self.data:
142 self.data[tracename] = {} # pylint: disable=unsupported-assignment-operation 172 self.data[tracename] = {}
143 self.cur_file_dict = self.data[tracename] # pylint: disable=unsubscriptable-object 173 self.cur_file_dict = self.data[tracename]
144 # The call event is really a "start frame" event, and happens for 174 # The call event is really a "start frame" event, and happens for
145 # function calls and re-entering generators. The f_lasti field is 175 # function calls and re-entering generators. The f_lasti field is
146 # -1 for calls, and a real offset for generators. Use <0 as the 176 # -1 for calls, and a real offset for generators. Use <0 as the
147 # line number for calls, and the real line number for generators. 177 # line number for calls, and the real line number for generators.
148 if getattr(frame, 'f_lasti', -1) < 0: 178 if getattr(frame, 'f_lasti', -1) < 0:
151 self.last_line = frame.f_lineno 181 self.last_line = frame.f_lineno
152 elif event == 'line': 182 elif event == 'line':
153 # Record an executed line. 183 # Record an executed line.
154 if self.cur_file_dict is not None: 184 if self.cur_file_dict is not None:
155 lineno = frame.f_lineno 185 lineno = frame.f_lineno
156 #if frame.f_code.co_filename != self.cur_file_name: 186
157 # self.log("*", frame.f_code.co_filename, self.cur_file_name, lineno)
158 if self.trace_arcs: 187 if self.trace_arcs:
159 self.cur_file_dict[(self.last_line, lineno)] = None 188 self.cur_file_dict[(self.last_line, lineno)] = None
160 else: 189 else:
161 self.cur_file_dict[lineno] = None 190 self.cur_file_dict[lineno] = None
162 self.last_line = lineno 191 self.last_line = lineno
225 # PyPy clears the trace function before running atexit functions, 254 # PyPy clears the trace function before running atexit functions,
226 # so don't warn if we are in atexit on PyPy and the trace function 255 # so don't warn if we are in atexit on PyPy and the trace function
227 # has changed to None. 256 # has changed to None.
228 dont_warn = (env.PYPY and env.PYPYVERSION >= (5, 4) and self.in_atexit and tf is None) 257 dont_warn = (env.PYPY and env.PYPYVERSION >= (5, 4) and self.in_atexit and tf is None)
229 if (not dont_warn) and tf != self._trace: # pylint: disable=comparison-with-callable 258 if (not dont_warn) and tf != self._trace: # pylint: disable=comparison-with-callable
230 self.warn( # pylint: disable=not-callable 259 self.warn(
231 "Trace function changed, measurement is likely wrong: %r" % (tf,), 260 "Trace function changed, measurement is likely wrong: %r" % (tf,),
232 slug="trace-changed", 261 slug="trace-changed",
233 ) 262 )
234 263
235 def activity(self): 264 def activity(self):

eric ide

mercurial