58 """ |
57 """ |
59 Class implementing base class of the debugger. |
58 Class implementing base class of the debugger. |
60 |
59 |
61 Provides methods for the 'owning' client to call to step etc. |
60 Provides methods for the 'owning' client to call to step etc. |
62 """ |
61 """ |
|
62 |
63 lib = os.path.dirname(inspect.__file__) |
63 lib = os.path.dirname(inspect.__file__) |
64 # tuple required because it's accessed a lot of times by startswith method |
64 # tuple required because it's accessed a lot of times by startswith method |
65 pathsToSkip = ('<', os.path.dirname(__file__), inspect.__file__[:-1]) |
65 pathsToSkip = ("<", os.path.dirname(__file__), inspect.__file__[:-1]) |
66 filesToSkip = {} |
66 filesToSkip = {} |
67 |
67 |
68 # cache for fixed file names |
68 # cache for fixed file names |
69 _fnCache = {} |
69 _fnCache = {} |
70 |
70 |
71 # Stop all timers, when greenlets are used |
71 # Stop all timers, when greenlets are used |
72 pollTimerEnabled = True |
72 pollTimerEnabled = True |
73 |
73 |
74 def __init__(self, dbgClient): |
74 def __init__(self, dbgClient): |
75 """ |
75 """ |
76 Constructor |
76 Constructor |
77 |
77 |
78 @param dbgClient the owning client |
78 @param dbgClient the owning client |
79 """ |
79 """ |
80 self._dbgClient = dbgClient |
80 self._dbgClient = dbgClient |
81 |
81 |
82 # Some informations about the thread |
82 # Some informations about the thread |
83 self.isMainThread = False |
83 self.isMainThread = False |
84 self.quitting = False |
84 self.quitting = False |
85 self.id = -1 |
85 self.id = -1 |
86 self.name = '' |
86 self.name = "" |
87 |
87 |
88 self.tracePythonLibs(False) |
88 self.tracePythonLibs(False) |
89 |
89 |
90 # Special handling of a recursion error |
90 # Special handling of a recursion error |
91 self.skipFrames = 0 |
91 self.skipFrames = 0 |
92 |
92 |
93 self.isBroken = False |
93 self.isBroken = False |
94 self.isException = False |
94 self.isException = False |
95 self.cFrame = None |
95 self.cFrame = None |
96 |
96 |
97 # current frame we are at |
97 # current frame we are at |
98 self.currentFrame = None |
98 self.currentFrame = None |
99 |
99 |
100 # frames, where we want to stop or release debugger |
100 # frames, where we want to stop or release debugger |
101 self.stopframe = None |
101 self.stopframe = None |
102 self.returnframe = None |
102 self.returnframe = None |
103 self.stop_everywhere = False |
103 self.stop_everywhere = False |
104 |
104 |
105 self.__recursionDepth = -1 |
105 self.__recursionDepth = -1 |
106 self.setRecursionDepth(inspect.currentframe()) |
106 self.setRecursionDepth(inspect.currentframe()) |
107 |
107 |
108 # background task to periodicaly check for client interactions |
108 # background task to periodicaly check for client interactions |
109 self.eventPollFlag = False |
109 self.eventPollFlag = False |
110 self.timer = _thread.start_new_thread(self.__eventPollTimer, ()) |
110 self.timer = _thread.start_new_thread(self.__eventPollTimer, ()) |
111 |
111 |
112 # provide a hook to perform a hard breakpoint |
112 # provide a hook to perform a hard breakpoint |
113 # Use it like this: |
113 # Use it like this: |
114 # if hasattr(sys, 'breakpoint): sys.breakpoint() |
114 # if hasattr(sys, 'breakpoint): sys.breakpoint() |
115 sys.breakpoint = self.set_trace |
115 sys.breakpoint = self.set_trace |
116 if sys.version_info >= (3, 7): |
116 if sys.version_info >= (3, 7): |
121 Private method to set a flag every 0.5 s to check for new messages. |
121 Private method to set a flag every 0.5 s to check for new messages. |
122 """ |
122 """ |
123 while DebugBase.pollTimerEnabled: |
123 while DebugBase.pollTimerEnabled: |
124 time.sleep(0.5) |
124 time.sleep(0.5) |
125 self.eventPollFlag = True |
125 self.eventPollFlag = True |
126 |
126 |
127 self.eventPollFlag = False |
127 self.eventPollFlag = False |
128 |
128 |
129 def getCurrentFrame(self): |
129 def getCurrentFrame(self): |
130 """ |
130 """ |
131 Public method to return the current frame. |
131 Public method to return the current frame. |
132 |
132 |
133 @return the current frame |
133 @return the current frame |
134 @rtype frame object |
134 @rtype frame object |
135 """ |
135 """ |
136 # Don't show any local frames after the program was stopped |
136 # Don't show any local frames after the program was stopped |
137 if self.quitting: |
137 if self.quitting: |
138 return None |
138 return None |
139 |
139 |
140 return self.currentFrame |
140 return self.currentFrame |
141 |
141 |
142 def getFrameLocals(self, frmnr=0): |
142 def getFrameLocals(self, frmnr=0): |
143 """ |
143 """ |
144 Public method to return the locals dictionary of the current frame |
144 Public method to return the locals dictionary of the current frame |
145 or a frame below. |
145 or a frame below. |
146 |
146 |
147 @param frmnr distance of frame to get locals dictionary of. 0 is |
147 @param frmnr distance of frame to get locals dictionary of. 0 is |
148 the current frame (int) |
148 the current frame (int) |
149 @return locals dictionary of the frame |
149 @return locals dictionary of the frame |
150 """ |
150 """ |
151 f = self.currentFrame |
151 f = self.currentFrame |
152 while f is not None and frmnr > 0: |
152 while f is not None and frmnr > 0: |
153 f = f.f_back |
153 f = f.f_back |
154 frmnr -= 1 |
154 frmnr -= 1 |
155 return f.f_locals |
155 return f.f_locals |
156 |
156 |
157 def storeFrameLocals(self, frmnr=0): |
157 def storeFrameLocals(self, frmnr=0): |
158 """ |
158 """ |
159 Public method to store the locals into the frame, so an access to |
159 Public method to store the locals into the frame, so an access to |
160 frame.f_locals returns the last data. |
160 frame.f_locals returns the last data. |
161 |
161 |
162 @param frmnr distance of frame to store locals dictionary to. 0 is |
162 @param frmnr distance of frame to store locals dictionary to. 0 is |
163 the current frame (int) |
163 the current frame (int) |
164 """ |
164 """ |
165 cf = self.currentFrame |
165 cf = self.currentFrame |
166 while cf is not None and frmnr > 0: |
166 while cf is not None and frmnr > 0: |
167 cf = cf.f_back |
167 cf = cf.f_back |
168 frmnr -= 1 |
168 frmnr -= 1 |
169 |
169 |
170 with contextlib.suppress(Exception): |
170 with contextlib.suppress(Exception): |
171 if "__pypy__" in sys.builtin_module_names: |
171 if "__pypy__" in sys.builtin_module_names: |
172 import __pypy__ |
172 import __pypy__ |
|
173 |
173 __pypy__.locals_to_fast(cf) |
174 __pypy__.locals_to_fast(cf) |
174 return |
175 return |
175 |
176 |
176 ctypes.pythonapi.PyFrame_LocalsToFast( |
177 ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(cf), ctypes.c_int(0)) |
177 ctypes.py_object(cf), |
178 |
178 ctypes.c_int(0)) |
|
179 |
|
180 def step(self, traceMode): |
179 def step(self, traceMode): |
181 """ |
180 """ |
182 Public method to perform a step operation in this thread. |
181 Public method to perform a step operation in this thread. |
183 |
182 |
184 @param traceMode If it is True, then the step is a step into, |
183 @param traceMode If it is True, then the step is a step into, |
185 otherwise it is a step over. |
184 otherwise it is a step over. |
186 """ |
185 """ |
187 if traceMode: |
186 if traceMode: |
188 self.set_step() |
187 self.set_step() |
189 else: |
188 else: |
190 self.set_next(self.currentFrame) |
189 self.set_next(self.currentFrame) |
191 |
190 |
192 def stepOut(self): |
191 def stepOut(self): |
193 """ |
192 """ |
194 Public method to perform a step out of the current call. |
193 Public method to perform a step out of the current call. |
195 """ |
194 """ |
196 self.set_return(self.currentFrame) |
195 self.set_return(self.currentFrame) |
197 |
196 |
198 def go(self, special): |
197 def go(self, special): |
199 """ |
198 """ |
200 Public method to resume the thread. |
199 Public method to resume the thread. |
201 |
200 |
202 It resumes the thread stopping only at breakpoints or exceptions. |
201 It resumes the thread stopping only at breakpoints or exceptions. |
203 |
202 |
204 @param special flag indicating a special continue operation |
203 @param special flag indicating a special continue operation |
205 """ |
204 """ |
206 self.set_continue(special) |
205 self.set_continue(special) |
207 |
206 |
208 def setRecursionDepth(self, frame): |
207 def setRecursionDepth(self, frame): |
209 """ |
208 """ |
210 Public method to determine the current recursion depth. |
209 Public method to determine the current recursion depth. |
211 |
210 |
212 @param frame The current stack frame. |
211 @param frame The current stack frame. |
213 """ |
212 """ |
214 self.__recursionDepth = 0 |
213 self.__recursionDepth = 0 |
215 while frame is not None: |
214 while frame is not None: |
216 self.__recursionDepth += 1 |
215 self.__recursionDepth += 1 |
217 frame = frame.f_back |
216 frame = frame.f_back |
218 |
217 |
219 def profileWithRecursion(self, frame, event, arg): |
218 def profileWithRecursion(self, frame, event, arg): |
220 """ |
219 """ |
221 Public method used to trace some stuff independent of the debugger |
220 Public method used to trace some stuff independent of the debugger |
222 trace function. |
221 trace function. |
223 |
222 |
224 @param frame current stack frame |
223 @param frame current stack frame |
225 @type frame object |
224 @type frame object |
226 @param event trace event |
225 @param event trace event |
227 @type str |
226 @type str |
228 @param arg arguments |
227 @param arg arguments |
229 @type depends on the previous event parameter |
228 @type depends on the previous event parameter |
230 @exception RuntimeError raised to indicate too many recursions |
229 @exception RuntimeError raised to indicate too many recursions |
231 """ |
230 """ |
232 if event == 'return': |
231 if event == "return": |
233 self.cFrame = frame.f_back |
232 self.cFrame = frame.f_back |
234 self.__recursionDepth -= 1 |
233 self.__recursionDepth -= 1 |
235 if self._dbgClient.callTraceEnabled: |
234 if self._dbgClient.callTraceEnabled: |
236 self.__sendCallTrace(event, frame, self.cFrame) |
235 self.__sendCallTrace(event, frame, self.cFrame) |
237 elif event == 'call': |
236 elif event == "call": |
238 if self._dbgClient.callTraceEnabled: |
237 if self._dbgClient.callTraceEnabled: |
239 self.__sendCallTrace(event, self.cFrame, frame) |
238 self.__sendCallTrace(event, self.cFrame, frame) |
240 self.cFrame = frame |
239 self.cFrame = frame |
241 self.__recursionDepth += 1 |
240 self.__recursionDepth += 1 |
242 if self.__recursionDepth > gRecursionLimit: |
241 if self.__recursionDepth > gRecursionLimit: |
243 raise RuntimeError( |
242 raise RuntimeError( |
244 'maximum recursion depth exceeded\n' |
243 "maximum recursion depth exceeded\n" |
245 '(offending frame is two down the stack)') |
244 "(offending frame is two down the stack)" |
246 |
245 ) |
|
246 |
247 def profile(self, frame, event, arg): |
247 def profile(self, frame, event, arg): |
248 """ |
248 """ |
249 Public method used to trace some stuff independent of the debugger |
249 Public method used to trace some stuff independent of the debugger |
250 trace function. |
250 trace function. |
251 |
251 |
252 @param frame current stack frame |
252 @param frame current stack frame |
253 @type frame object |
253 @type frame object |
254 @param event trace event |
254 @param event trace event |
255 @type str |
255 @type str |
256 @param arg arguments |
256 @param arg arguments |
257 @type depends on the previous event parameter |
257 @type depends on the previous event parameter |
258 """ |
258 """ |
259 if event == 'return': |
259 if event == "return": |
260 self.__sendCallTrace(event, frame, frame.f_back) |
260 self.__sendCallTrace(event, frame, frame.f_back) |
261 elif event == 'call': |
261 elif event == "call": |
262 self.__sendCallTrace(event, frame.f_back, frame) |
262 self.__sendCallTrace(event, frame.f_back, frame) |
263 |
263 |
264 def __sendCallTrace(self, event, fromFrame, toFrame): |
264 def __sendCallTrace(self, event, fromFrame, toFrame): |
265 """ |
265 """ |
266 Private method to send a call/return trace. |
266 Private method to send a call/return trace. |
267 |
267 |
268 @param event trace event |
268 @param event trace event |
269 @type str |
269 @type str |
270 @param fromFrame originating frame |
270 @param fromFrame originating frame |
271 @type frame object |
271 @type frame object |
272 @param toFrame destination frame |
272 @param toFrame destination frame |
273 @type frame object |
273 @type frame object |
274 """ |
274 """ |
275 if not self.__skipFrame(fromFrame) and not self.__skipFrame(toFrame): |
275 if not self.__skipFrame(fromFrame) and not self.__skipFrame(toFrame): |
276 fromInfo = { |
276 fromInfo = { |
277 "filename": self._dbgClient.absPath( |
277 "filename": self._dbgClient.absPath(self.fix_frame_filename(fromFrame)), |
278 self.fix_frame_filename(fromFrame)), |
|
279 "linenumber": fromFrame.f_lineno, |
278 "linenumber": fromFrame.f_lineno, |
280 "codename": fromFrame.f_code.co_name, |
279 "codename": fromFrame.f_code.co_name, |
281 } |
280 } |
282 toInfo = { |
281 toInfo = { |
283 "filename": self._dbgClient.absPath( |
282 "filename": self._dbgClient.absPath(self.fix_frame_filename(toFrame)), |
284 self.fix_frame_filename(toFrame)), |
|
285 "linenumber": toFrame.f_lineno, |
283 "linenumber": toFrame.f_lineno, |
286 "codename": toFrame.f_code.co_name, |
284 "codename": toFrame.f_code.co_name, |
287 } |
285 } |
288 self._dbgClient.sendCallTrace(event, fromInfo, toInfo) |
286 self._dbgClient.sendCallTrace(event, fromInfo, toInfo) |
289 |
287 |
290 def trace_dispatch(self, frame, event, arg): |
288 def trace_dispatch(self, frame, event, arg): |
291 """ |
289 """ |
292 Public method reimplemented from bdb.py to do some special things. |
290 Public method reimplemented from bdb.py to do some special things. |
293 |
291 |
294 This specialty is to check the connection to the debug server |
292 This specialty is to check the connection to the debug server |
295 for new events (i.e. new breakpoints) while we are going through |
293 for new events (i.e. new breakpoints) while we are going through |
296 the code. |
294 the code. |
297 |
295 |
298 @param frame The current stack frame |
296 @param frame The current stack frame |
299 @type frame object |
297 @type frame object |
300 @param event The trace event |
298 @param event The trace event |
301 @type str |
299 @type str |
302 @param arg The arguments |
300 @param arg The arguments |
307 """ |
305 """ |
308 # give the client a chance to push through new break points. |
306 # give the client a chance to push through new break points. |
309 if self.eventPollFlag: |
307 if self.eventPollFlag: |
310 self._dbgClient.eventPoll() |
308 self._dbgClient.eventPoll() |
311 self.eventPollFlag = False |
309 self.eventPollFlag = False |
312 |
310 |
313 if self.quitting: |
311 if self.quitting: |
314 raise SystemExit |
312 raise SystemExit |
315 |
313 |
316 if event == 'line': |
314 if event == "line": |
317 if self.stop_here(frame) or self.break_here(frame): |
315 if self.stop_here(frame) or self.break_here(frame): |
318 if ( |
316 if ( |
319 self.stop_everywhere and |
317 self.stop_everywhere |
320 frame.f_back and |
318 and frame.f_back |
321 frame.f_back.f_code.co_name == "prepareJsonCommand" |
319 and frame.f_back.f_code.co_name == "prepareJsonCommand" |
322 ): |
320 ): |
323 # Just stepped into print statement, so skip these frames |
321 # Just stepped into print statement, so skip these frames |
324 self._set_stopinfo(None, frame.f_back) |
322 self._set_stopinfo(None, frame.f_back) |
325 else: |
323 else: |
326 self.user_line(frame) |
324 self.user_line(frame) |
327 return self.trace_dispatch |
325 return self.trace_dispatch |
328 |
326 |
329 if event == 'call': |
327 if event == "call": |
330 if ( |
328 if ( |
331 self.stop_here(frame) or |
329 self.stop_here(frame) |
332 self.__checkBreakInFrame(frame) or |
330 or self.__checkBreakInFrame(frame) |
333 Watch.watches != [] |
331 or Watch.watches != [] |
334 ) or ( |
332 ) or ( |
335 self.stopframe and |
333 self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
336 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
|
337 ): |
334 ): |
338 return self.trace_dispatch |
335 return self.trace_dispatch |
339 else: |
336 else: |
340 # No need to trace this function |
337 # No need to trace this function |
341 return None |
338 return None |
342 |
339 |
343 if event == 'return': |
340 if event == "return": |
344 if self.stop_here(frame) or frame == self.returnframe: |
341 if self.stop_here(frame) or frame == self.returnframe: |
345 # Ignore return events in generator except when stepping. |
342 # Ignore return events in generator except when stepping. |
346 if ( |
343 if ( |
347 self.stopframe and |
344 self.stopframe |
348 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
345 and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
349 ): |
346 ): |
350 return self.trace_dispatch |
347 return self.trace_dispatch |
351 # Only true if we didn't stop in this frame, because it's |
348 # Only true if we didn't stop in this frame, because it's |
352 # belonging to the eric debugger. |
349 # belonging to the eric debugger. |
353 if self.stopframe is frame and self.stoplineno != -1: |
350 if self.stopframe is frame and self.stoplineno != -1: |
354 self._set_stopinfo(None, frame.f_back) |
351 self._set_stopinfo(None, frame.f_back) |
355 return None |
352 return None |
356 |
353 |
357 if event == 'exception': |
354 if event == "exception": |
358 if not self.__skipFrame(frame): |
355 if not self.__skipFrame(frame): |
359 # When stepping with next/until/return in a generator frame, |
356 # When stepping with next/until/return in a generator frame, |
360 # skip the internal StopIteration exception (with no traceback) |
357 # skip the internal StopIteration exception (with no traceback) |
361 # triggered by a subiterator run with the 'yield from' |
358 # triggered by a subiterator run with the 'yield from' |
362 # statement. |
359 # statement. |
363 if not ( |
360 if not ( |
364 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS and |
361 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS |
365 arg[0] is StopIteration and |
362 and arg[0] is StopIteration |
366 arg[2] is None |
363 and arg[2] is None |
367 ): |
364 ): |
368 self.user_exception(arg) |
365 self.user_exception(arg) |
369 # Stop at the StopIteration or GeneratorExit exception when the |
366 # Stop at the StopIteration or GeneratorExit exception when the |
370 # user has set stopframe in a generator by issuing a return |
367 # user has set stopframe in a generator by issuing a return |
371 # command, or a next/until command at the last statement in the |
368 # command, or a next/until command at the last statement in the |
372 # generator before the exception. |
369 # generator before the exception. |
373 elif ( |
370 elif ( |
374 self.stopframe and |
371 self.stopframe |
375 frame is not self.stopframe and |
372 and frame is not self.stopframe |
376 (self.stopframe.f_code.co_flags & |
373 and (self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS) |
377 GENERATOR_AND_COROUTINE_FLAGS) and |
374 and arg[0] in (StopIteration, GeneratorExit) |
378 arg[0] in (StopIteration, GeneratorExit) |
|
379 ): |
375 ): |
380 self.user_exception(arg) |
376 self.user_exception(arg) |
381 return None |
377 return None |
382 |
378 |
383 if event == 'c_call': |
379 if event == "c_call": |
384 return None |
380 return None |
385 if event == 'c_exception': |
381 if event == "c_exception": |
386 return None |
382 return None |
387 if event == 'c_return': |
383 if event == "c_return": |
388 return None |
384 return None |
389 |
385 |
390 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING_M801__ |
386 print( # __IGNORE_WARNING_M801__ |
391 ' unknown debugging event: ', |
387 "DebugBase.trace_dispatch:" " unknown debugging event: ", |
392 repr(event)) |
388 repr(event), |
393 |
389 ) |
|
390 |
394 return self.trace_dispatch |
391 return self.trace_dispatch |
395 |
392 |
396 def set_trace(self, frame=None): |
393 def set_trace(self, frame=None): |
397 """ |
394 """ |
398 Public method to start debugging from 'frame'. |
395 Public method to start debugging from 'frame'. |
399 |
396 |
400 If frame is not specified, debugging starts from caller's frame. |
397 If frame is not specified, debugging starts from caller's frame. |
401 Because of jump optimizations it's not possible to use sys.breakpoint() |
398 Because of jump optimizations it's not possible to use sys.breakpoint() |
402 as last instruction in a function or method. |
399 as last instruction in a function or method. |
403 |
400 |
404 @param frame frame to start debugging from |
401 @param frame frame to start debugging from |
405 @type frame object |
402 @type frame object |
406 """ |
403 """ |
407 if frame is None: |
404 if frame is None: |
408 frame = sys._getframe().f_back # Skip set_trace method |
405 frame = sys._getframe().f_back # Skip set_trace method |
409 |
406 |
410 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
407 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ |
411 |
408 |
412 frame.f_trace = self.trace_dispatch |
409 frame.f_trace = self.trace_dispatch |
413 while frame.f_back is not None: |
410 while frame.f_back is not None: |
414 # stop at eric's debugger frame or a threading bootstrap |
411 # stop at eric's debugger frame or a threading bootstrap |
415 if frame.f_back.f_code == stopOnHandleCommand: |
412 if frame.f_back.f_code == stopOnHandleCommand: |
416 frame.f_trace = self.trace_dispatch |
413 frame.f_trace = self.trace_dispatch |
417 break |
414 break |
418 |
415 |
419 frame = frame.f_back |
416 frame = frame.f_back |
420 |
417 |
421 self.stop_everywhere = True |
418 self.stop_everywhere = True |
422 sys.settrace(self.trace_dispatch) |
419 sys.settrace(self.trace_dispatch) |
423 sys.setprofile(self._dbgClient.callTraceEnabled) |
420 sys.setprofile(self._dbgClient.callTraceEnabled) |
424 |
421 |
425 def bootstrap(self, target, args, kwargs): |
422 def bootstrap(self, target, args, kwargs): |
426 """ |
423 """ |
427 Public method to bootstrap a thread. |
424 Public method to bootstrap a thread. |
428 |
425 |
429 It wraps the call to the user function to enable tracing |
426 It wraps the call to the user function to enable tracing |
430 before hand. |
427 before hand. |
431 |
428 |
432 @param target function which is called in the new created thread |
429 @param target function which is called in the new created thread |
433 @type function pointer |
430 @type function pointer |
434 @param args arguments to pass to target |
431 @param args arguments to pass to target |
435 @type tuple |
432 @type tuple |
436 @param kwargs keyword arguments to pass to target |
433 @param kwargs keyword arguments to pass to target |
468 at exit |
466 at exit |
469 @type bool |
467 @type bool |
470 """ |
468 """ |
471 if globalsDict is None: |
469 if globalsDict is None: |
472 import __main__ |
470 import __main__ |
|
471 |
473 globalsDict = __main__.__dict__ |
472 globalsDict = __main__.__dict__ |
474 |
473 |
475 if localsDict is None: |
474 if localsDict is None: |
476 localsDict = globalsDict |
475 localsDict = globalsDict |
477 |
476 |
478 if not isinstance(cmd, types.CodeType): |
477 if not isinstance(cmd, types.CodeType): |
479 cmd = compile(cmd, "<string>", "exec") |
478 cmd = compile(cmd, "<string>", "exec") |
480 |
479 |
481 if debug: |
480 if debug: |
482 # First time the trace_dispatch function is called, a "base debug" |
481 # First time the trace_dispatch function is called, a "base debug" |
483 # function has to be returned, which is called at every user code |
482 # function has to be returned, which is called at every user code |
484 # function call. This is ensured by setting stop_everywhere. |
483 # function call. This is ensured by setting stop_everywhere. |
485 self.stop_everywhere = True |
484 self.stop_everywhere = True |
486 sys.settrace(self.trace_dispatch) |
485 sys.settrace(self.trace_dispatch) |
487 |
486 |
488 try: |
487 try: |
489 exec(cmd, globalsDict, localsDict) # secok |
488 exec(cmd, globalsDict, localsDict) # secok |
490 atexit._run_exitfuncs() |
489 atexit._run_exitfuncs() |
491 self._dbgClient.progTerminated(0, closeSession=closeSession) |
490 self._dbgClient.progTerminated(0, closeSession=closeSession) |
492 exitcode = 0 |
491 exitcode = 0 |
493 except SystemExit: |
492 except SystemExit: |
494 atexit._run_exitfuncs() |
493 atexit._run_exitfuncs() |
495 excinfo = sys.exc_info() |
494 excinfo = sys.exc_info() |
496 exitcode, message = self.__extractSystemExitMessage(excinfo) |
495 exitcode, message = self.__extractSystemExitMessage(excinfo) |
497 self._dbgClient.progTerminated(exitcode, message=message, |
496 self._dbgClient.progTerminated( |
498 closeSession=closeSession) |
497 exitcode, message=message, closeSession=closeSession |
|
498 ) |
499 except Exception: |
499 except Exception: |
500 excinfo = sys.exc_info() |
500 excinfo = sys.exc_info() |
501 self.user_exception(excinfo, True) |
501 self.user_exception(excinfo, True) |
502 exitcode = 242 |
502 exitcode = 242 |
503 finally: |
503 finally: |
603 printerr(e) |
603 printerr(e) |
604 |
604 |
605 def set_quit(self): |
605 def set_quit(self): |
606 """ |
606 """ |
607 Public method to quit. |
607 Public method to quit. |
608 |
608 |
609 Disables the trace functions and resets all frame pointer. |
609 Disables the trace functions and resets all frame pointer. |
610 """ |
610 """ |
611 sys.setprofile(None) |
611 sys.setprofile(None) |
612 self.stopframe = None |
612 self.stopframe = None |
613 self.returnframe = None |
613 self.returnframe = None |
614 for debugThread in self._dbgClient.threads.values(): |
614 for debugThread in self._dbgClient.threads.values(): |
615 debugThread.quitting = True |
615 debugThread.quitting = True |
616 |
616 |
617 def fix_frame_filename(self, frame): |
617 def fix_frame_filename(self, frame): |
618 """ |
618 """ |
619 Public method used to fixup the filename for a given frame. |
619 Public method used to fixup the filename for a given frame. |
620 |
620 |
621 The logic employed here is that if a module was loaded |
621 The logic employed here is that if a module was loaded |
622 from a .pyc file, then the correct .py to operate with |
622 from a .pyc file, then the correct .py to operate with |
623 should be in the same path as the .pyc. The reason this |
623 should be in the same path as the .pyc. The reason this |
624 logic is needed is that when a .pyc file is generated, the |
624 logic is needed is that when a .pyc file is generated, the |
625 filename embedded and thus what is readable in the code object |
625 filename embedded and thus what is readable in the code object |
626 of the frame object is the fully qualified filepath when the |
626 of the frame object is the fully qualified filepath when the |
627 pyc is generated. If files are moved from machine to machine |
627 pyc is generated. If files are moved from machine to machine |
628 this can break debugging as the .pyc will refer to the .py |
628 this can break debugging as the .pyc will refer to the .py |
629 on the original machine. Another case might be sharing |
629 on the original machine. Another case might be sharing |
630 code over a network... This logic deals with that. |
630 code over a network... This logic deals with that. |
631 |
631 |
632 @param frame the frame object |
632 @param frame the frame object |
633 @type frame object |
633 @type frame object |
634 @return fixed up file name |
634 @return fixed up file name |
635 @rtype str |
635 @rtype str |
636 """ |
636 """ |
637 # get module name from __file__ |
637 # get module name from __file__ |
638 fn = frame.f_globals.get('__file__') |
638 fn = frame.f_globals.get("__file__") |
639 try: |
639 try: |
640 return self._fnCache[fn] |
640 return self._fnCache[fn] |
641 except KeyError: |
641 except KeyError: |
642 if fn is None: |
642 if fn is None: |
643 return frame.f_code.co_filename |
643 return frame.f_code.co_filename |
644 |
644 |
645 absFilename = os.path.abspath(fn) |
645 absFilename = os.path.abspath(fn) |
646 if absFilename.endswith(('.pyc', '.pyo', '.pyd')): |
646 if absFilename.endswith((".pyc", ".pyo", ".pyd")): |
647 fixedName = absFilename[:-1] |
647 fixedName = absFilename[:-1] |
648 if not os.path.exists(fixedName): |
648 if not os.path.exists(fixedName): |
649 fixedName = absFilename |
649 fixedName = absFilename |
650 else: |
650 else: |
651 fixedName = absFilename |
651 fixedName = absFilename |
655 |
655 |
656 def __checkBreakInFrame(self, frame): |
656 def __checkBreakInFrame(self, frame): |
657 """ |
657 """ |
658 Private method to check if the function / method has a line number |
658 Private method to check if the function / method has a line number |
659 which is a breakpoint. |
659 which is a breakpoint. |
660 |
660 |
661 @param frame the frame object |
661 @param frame the frame object |
662 @type frame object |
662 @type frame object |
663 @return Flag indicating a function / method with breakpoint |
663 @return Flag indicating a function / method with breakpoint |
664 @rtype bool |
664 @rtype bool |
665 """ |
665 """ |
666 try: |
666 try: |
667 return Breakpoint.breakInFrameCache[ |
667 return Breakpoint.breakInFrameCache[ |
668 frame.f_globals.get('__file__'), |
668 frame.f_globals.get("__file__"), frame.f_code.co_firstlineno |
669 frame.f_code.co_firstlineno] |
669 ] |
670 except KeyError: |
670 except KeyError: |
671 filename = self.fix_frame_filename(frame) |
671 filename = self.fix_frame_filename(frame) |
672 if filename not in Breakpoint.breakInFile: |
672 if filename not in Breakpoint.breakInFile: |
673 Breakpoint.breakInFrameCache[ |
673 Breakpoint.breakInFrameCache[ |
674 frame.f_globals.get('__file__'), |
674 frame.f_globals.get("__file__"), frame.f_code.co_firstlineno |
675 frame.f_code.co_firstlineno] = False |
675 ] = False |
676 return False |
676 return False |
677 lineNo = frame.f_code.co_firstlineno |
677 lineNo = frame.f_code.co_firstlineno |
678 lineNumbers = [lineNo] |
678 lineNumbers = [lineNo] |
679 |
679 |
680 co_lnotab = frame.f_code.co_lnotab[1::2] |
680 co_lnotab = frame.f_code.co_lnotab[1::2] |
681 |
681 |
682 # No need to handle special case if a lot of lines between |
682 # No need to handle special case if a lot of lines between |
683 # (e.g. closure), because the additional lines won't cause a bp |
683 # (e.g. closure), because the additional lines won't cause a bp |
684 for co_lno in co_lnotab: |
684 for co_lno in co_lnotab: |
685 if co_lno >= 0x80: |
685 if co_lno >= 0x80: |
686 lineNo -= 0x100 |
686 lineNo -= 0x100 |
687 lineNo += co_lno |
687 lineNo += co_lno |
688 lineNumbers.append(lineNo) |
688 lineNumbers.append(lineNo) |
689 |
689 |
690 for bp in Breakpoint.breakInFile[filename]: |
690 for bp in Breakpoint.breakInFile[filename]: |
691 if bp in lineNumbers: |
691 if bp in lineNumbers: |
692 Breakpoint.breakInFrameCache[ |
692 Breakpoint.breakInFrameCache[ |
693 frame.f_globals.get('__file__'), |
693 frame.f_globals.get("__file__"), frame.f_code.co_firstlineno |
694 frame.f_code.co_firstlineno] = True |
694 ] = True |
695 return True |
695 return True |
696 Breakpoint.breakInFrameCache[ |
696 Breakpoint.breakInFrameCache[ |
697 frame.f_globals.get('__file__'), |
697 frame.f_globals.get("__file__"), frame.f_code.co_firstlineno |
698 frame.f_code.co_firstlineno] = False |
698 ] = False |
699 return False |
699 return False |
700 |
700 |
701 def break_here(self, frame): |
701 def break_here(self, frame): |
702 """ |
702 """ |
703 Public method reimplemented from bdb.py to fix the filename from the |
703 Public method reimplemented from bdb.py to fix the filename from the |
704 frame. |
704 frame. |
705 |
705 |
706 See fix_frame_filename for more info. |
706 See fix_frame_filename for more info. |
707 |
707 |
708 @param frame the frame object |
708 @param frame the frame object |
709 @type frame object |
709 @type frame object |
710 @return flag indicating the break status |
710 @return flag indicating the break status |
711 @rtype bool |
711 @rtype bool |
712 """ |
712 """ |
713 filename = self.fix_frame_filename(frame) |
713 filename = self.fix_frame_filename(frame) |
714 if (filename, frame.f_lineno) in Breakpoint.breaks: |
714 if (filename, frame.f_lineno) in Breakpoint.breaks: |
715 bp, flag = Breakpoint.effectiveBreak( |
715 bp, flag = Breakpoint.effectiveBreak(filename, frame.f_lineno, frame) |
716 filename, frame.f_lineno, frame) |
|
717 if bp: |
716 if bp: |
718 # flag says ok to delete temp. bp |
717 # flag says ok to delete temp. bp |
719 if flag and bp.temporary: |
718 if flag and bp.temporary: |
720 self.__do_clearBreak(filename, frame.f_lineno) |
719 self.__do_clearBreak(filename, frame.f_lineno) |
721 return True |
720 return True |
722 |
721 |
723 if Watch.watches != []: |
722 if Watch.watches != []: |
724 bp, flag = Watch.effectiveWatch(frame) |
723 bp, flag = Watch.effectiveWatch(frame) |
725 if bp: |
724 if bp: |
726 # flag says ok to delete temp. watch |
725 # flag says ok to delete temp. watch |
727 if flag and bp.temporary: |
726 if flag and bp.temporary: |
728 self.__do_clearWatch(bp.cond) |
727 self.__do_clearWatch(bp.cond) |
729 return True |
728 return True |
730 |
729 |
731 return False |
730 return False |
732 |
731 |
733 def __do_clearBreak(self, filename, lineno): |
732 def __do_clearBreak(self, filename, lineno): |
734 """ |
733 """ |
735 Private method called to clear a temporary breakpoint. |
734 Private method called to clear a temporary breakpoint. |
736 |
735 |
737 @param filename name of the file the bp belongs to |
736 @param filename name of the file the bp belongs to |
738 @type str |
737 @type str |
739 @param lineno linenumber of the bp |
738 @param lineno linenumber of the bp |
740 @type int |
739 @type int |
741 """ |
740 """ |
768 fr = self.getCurrentFrame() |
767 fr = self.getCurrentFrame() |
769 elif type(frame) == list: |
768 elif type(frame) == list: |
770 fr, tb_lineno = frame.pop(0) |
769 fr, tb_lineno = frame.pop(0) |
771 else: |
770 else: |
772 fr = frame |
771 fr = frame |
773 |
772 |
774 stack = [] |
773 stack = [] |
775 while fr is not None: |
774 while fr is not None: |
776 if applyTrace: |
775 if applyTrace: |
777 # Reset the trace function so we can be sure |
776 # Reset the trace function so we can be sure |
778 # to trace all functions up the stack... This gets around |
777 # to trace all functions up the stack... This gets around |
779 # problems where an exception/breakpoint has occurred |
778 # problems where an exception/breakpoint has occurred |
780 # but we had disabled tracing along the way via a None |
779 # but we had disabled tracing along the way via a None |
781 # return from dispatch_call |
780 # return from dispatch_call |
782 fr.f_trace = self.trace_dispatch |
781 fr.f_trace = self.trace_dispatch |
783 |
782 |
784 fname = self._dbgClient.absPath(self.fix_frame_filename(fr)) |
783 fname = self._dbgClient.absPath(self.fix_frame_filename(fr)) |
785 # Always show at least one stack frame, even if it's from eric. |
784 # Always show at least one stack frame, even if it's from eric. |
786 if stack and os.path.basename(fname).startswith( |
785 if stack and os.path.basename(fname).startswith( |
787 ("DebugBase.py", "DebugClientBase.py", |
786 ( |
788 "ThreadExtension.py", "threading.py") |
787 "DebugBase.py", |
|
788 "DebugClientBase.py", |
|
789 "ThreadExtension.py", |
|
790 "threading.py", |
|
791 ) |
789 ): |
792 ): |
790 break |
793 break |
791 |
794 |
792 fline = tb_lineno or fr.f_lineno |
795 fline = tb_lineno or fr.f_lineno |
793 ffunc = fr.f_code.co_name |
796 ffunc = fr.f_code.co_name |
794 |
797 |
795 if ffunc == '?': |
798 if ffunc == "?": |
796 ffunc = '' |
799 ffunc = "" |
797 |
800 |
798 if ffunc and not ffunc.startswith("<"): |
801 if ffunc and not ffunc.startswith("<"): |
799 argInfo = getargvalues(fr) |
802 argInfo = getargvalues(fr) |
800 try: |
803 try: |
801 fargs = formatargvalues( |
804 fargs = formatargvalues( |
802 argInfo.args, argInfo.varargs, |
805 argInfo.args, argInfo.varargs, argInfo.keywords, argInfo.locals |
803 argInfo.keywords, argInfo.locals) |
806 ) |
804 except Exception: |
807 except Exception: |
805 fargs = "" |
808 fargs = "" |
806 else: |
809 else: |
807 fargs = "" |
810 fargs = "" |
808 |
811 |
809 stack.append([fname, fline, ffunc, fargs]) |
812 stack.append([fname, fline, ffunc, fargs]) |
810 |
813 |
811 # is it a stack frame or exception list? |
814 # is it a stack frame or exception list? |
812 if type(frame) == list: |
815 if type(frame) == list: |
813 if frame != []: |
816 if frame != []: |
814 fr, tb_lineno = frame.pop(0) |
817 fr, tb_lineno = frame.pop(0) |
815 else: |
818 else: |
816 fr = None |
819 fr = None |
817 else: |
820 else: |
818 fr = fr.f_back |
821 fr = fr.f_back |
819 |
822 |
820 return stack |
823 return stack |
821 |
824 |
822 def user_line(self, frame): |
825 def user_line(self, frame): |
823 """ |
826 """ |
824 Public method reimplemented to handle the program about to execute a |
827 Public method reimplemented to handle the program about to execute a |
825 particular line. |
828 particular line. |
826 |
829 |
827 @param frame the frame object |
830 @param frame the frame object |
828 """ |
831 """ |
829 # We never stop on line 0. |
832 # We never stop on line 0. |
830 if frame.f_lineno == 0: |
833 if frame.f_lineno == 0: |
831 return |
834 return |
832 |
835 |
833 self.isBroken = True |
836 self.isBroken = True |
834 self.currentFrame = frame |
837 self.currentFrame = frame |
835 stack = self.getStack(frame, applyTrace=True) |
838 stack = self.getStack(frame, applyTrace=True) |
836 |
839 |
837 self._dbgClient.lockClient() |
840 self._dbgClient.lockClient() |
838 self._dbgClient.currentThread = self |
841 self._dbgClient.currentThread = self |
839 self._dbgClient.currentThreadExec = self |
842 self._dbgClient.currentThreadExec = self |
840 |
843 |
841 self._dbgClient.sendResponseLine(stack, self.name) |
844 self._dbgClient.sendResponseLine(stack, self.name) |
842 self._dbgClient.eventLoop() |
845 self._dbgClient.eventLoop() |
843 |
846 |
844 self.isBroken = False |
847 self.isBroken = False |
845 self._dbgClient.unlockClient() |
848 self._dbgClient.unlockClient() |
846 |
849 |
847 self._dbgClient.dumpThreadList() |
850 self._dbgClient.dumpThreadList() |
848 |
851 |
849 def user_exception(self, excinfo, unhandled=False): |
852 def user_exception(self, excinfo, unhandled=False): |
850 """ |
853 """ |
851 Public method reimplemented to report an exception to the debug server. |
854 Public method reimplemented to report an exception to the debug server. |
852 |
855 |
853 @param excinfo details about the exception |
856 @param excinfo details about the exception |
854 @type tuple(Exception, excval object, traceback frame object) |
857 @type tuple(Exception, excval object, traceback frame object) |
855 @param unhandled flag indicating an uncaught exception |
858 @param unhandled flag indicating an uncaught exception |
856 @type bool |
859 @type bool |
857 """ |
860 """ |
858 exctype, excval, exctb = excinfo |
861 exctype, excval, exctb = excinfo |
859 |
862 |
860 if ((exctype in [GeneratorExit, StopIteration] and |
863 if ( |
861 unhandled is False) or |
864 exctype in [GeneratorExit, StopIteration] and unhandled is False |
862 exctype == SystemExit): |
865 ) or exctype == SystemExit: |
863 # ignore these |
866 # ignore these |
864 return |
867 return |
865 |
868 |
866 if exctype in [SyntaxError, IndentationError]: |
869 if exctype in [SyntaxError, IndentationError]: |
867 try: |
870 try: |
868 if type(excval) == tuple: |
871 if type(excval) == tuple: |
869 message, details = excval |
872 message, details = excval |
870 filename, lineno, charno, text = details |
873 filename, lineno, charno, text = details |
871 else: |
874 else: |
872 message = excval.msg |
875 message = excval.msg |
873 filename = excval.filename |
876 filename = excval.filename |
874 lineno = excval.lineno |
877 lineno = excval.lineno |
875 charno = excval.offset |
878 charno = excval.offset |
876 |
879 |
877 if filename is None: |
880 if filename is None: |
878 realSyntaxError = False |
881 realSyntaxError = False |
879 else: |
882 else: |
880 if charno is None: |
883 if charno is None: |
881 charno = 0 |
884 charno = 0 |
882 |
885 |
883 filename = os.path.abspath(filename) |
886 filename = os.path.abspath(filename) |
884 realSyntaxError = os.path.exists(filename) |
887 realSyntaxError = os.path.exists(filename) |
885 |
888 |
886 except (AttributeError, ValueError): |
889 except (AttributeError, ValueError): |
887 message = "" |
890 message = "" |
888 filename = "" |
891 filename = "" |
889 lineno = 0 |
892 lineno = 0 |
890 charno = 0 |
893 charno = 0 |
891 realSyntaxError = True |
894 realSyntaxError = True |
892 |
895 |
893 if realSyntaxError: |
896 if realSyntaxError: |
894 self._dbgClient.sendSyntaxError( |
897 self._dbgClient.sendSyntaxError( |
895 message, filename, lineno, charno, self.name) |
898 message, filename, lineno, charno, self.name |
|
899 ) |
896 self._dbgClient.eventLoop() |
900 self._dbgClient.eventLoop() |
897 return |
901 return |
898 |
902 |
899 self.skipFrames = 0 |
903 self.skipFrames = 0 |
900 if (exctype == RuntimeError and |
904 if ( |
901 str(excval).startswith('maximum recursion depth exceeded') or |
905 exctype == RuntimeError |
902 exctype == RecursionError): # __IGNORE_WARNING__ |
906 and str(excval).startswith("maximum recursion depth exceeded") |
903 excval = 'maximum recursion depth exceeded' |
907 or exctype == RecursionError |
|
908 ): # __IGNORE_WARNING__ |
|
909 excval = "maximum recursion depth exceeded" |
904 depth = 0 |
910 depth = 0 |
905 tb = exctb |
911 tb = exctb |
906 while tb: |
912 while tb: |
907 tb = tb.tb_next |
913 tb = tb.tb_next |
908 |
914 |
909 if (tb and tb.tb_frame.f_code.co_name == 'trace_dispatch' and |
915 if ( |
910 __file__.startswith(tb.tb_frame.f_code.co_filename)): |
916 tb |
|
917 and tb.tb_frame.f_code.co_name == "trace_dispatch" |
|
918 and __file__.startswith(tb.tb_frame.f_code.co_filename) |
|
919 ): |
911 depth = 1 |
920 depth = 1 |
912 self.skipFrames += depth |
921 self.skipFrames += depth |
913 |
922 |
914 # always 1 if running without debugger |
923 # always 1 if running without debugger |
915 self.skipFrames = max(1, self.skipFrames) |
924 self.skipFrames = max(1, self.skipFrames) |
916 |
925 |
917 exctype = self.__extractExceptionName(exctype) |
926 exctype = self.__extractExceptionName(exctype) |
918 |
927 |
919 if excval is None: |
928 if excval is None: |
920 excval = '' |
929 excval = "" |
921 |
930 |
922 exctypetxt = ( |
931 exctypetxt = ( |
923 "unhandled {0!s}".format(str(exctype)) |
932 "unhandled {0!s}".format(str(exctype)) if unhandled else str(exctype) |
924 if unhandled else |
|
925 str(exctype) |
|
926 ) |
933 ) |
927 excvaltxt = str(excval) |
934 excvaltxt = str(excval) |
928 |
935 |
929 # Don't step into libraries, which are used by our debugger methods |
936 # Don't step into libraries, which are used by our debugger methods |
930 if exctb is not None: |
937 if exctb is not None: |
931 self.stop_everywhere = False |
938 self.stop_everywhere = False |
932 |
939 |
933 self.isBroken = True |
940 self.isBroken = True |
934 self.isException = True |
941 self.isException = True |
935 |
942 |
936 disassembly = None |
943 disassembly = None |
937 stack = [] |
944 stack = [] |
938 if exctb: |
945 if exctb: |
939 frlist = self.__extract_stack(exctb) |
946 frlist = self.__extract_stack(exctb) |
940 frlist.reverse() |
947 frlist.reverse() |
941 disassembly = self.__disassemble(frlist[0][0]) |
948 disassembly = self.__disassemble(frlist[0][0]) |
942 |
949 |
943 self.currentFrame = frlist[0][0] |
950 self.currentFrame = frlist[0][0] |
944 stack = self.getStack(frlist[self.skipFrames:]) |
951 stack = self.getStack(frlist[self.skipFrames :]) |
945 |
952 |
946 self._dbgClient.lockClient() |
953 self._dbgClient.lockClient() |
947 self._dbgClient.currentThread = self |
954 self._dbgClient.currentThread = self |
948 self._dbgClient.currentThreadExec = self |
955 self._dbgClient.currentThreadExec = self |
949 self._dbgClient.sendException(exctypetxt, excvaltxt, stack, self.name) |
956 self._dbgClient.sendException(exctypetxt, excvaltxt, stack, self.name) |
950 self._dbgClient.setDisassembly(disassembly) |
957 self._dbgClient.setDisassembly(disassembly) |
951 self._dbgClient.dumpThreadList() |
958 self._dbgClient.dumpThreadList() |
952 |
959 |
953 if exctb is not None: |
960 if exctb is not None: |
954 # When polling kept enabled, it isn't possible to resume after an |
961 # When polling kept enabled, it isn't possible to resume after an |
955 # unhandled exception without further user interaction. |
962 # unhandled exception without further user interaction. |
956 self._dbgClient.eventLoop(True) |
963 self._dbgClient.eventLoop(True) |
957 |
964 |
958 self.skipFrames = 0 |
965 self.skipFrames = 0 |
959 |
966 |
960 self.isBroken = False |
967 self.isBroken = False |
961 self.isException = False |
968 self.isException = False |
962 stop_everywhere = self.stop_everywhere |
969 stop_everywhere = self.stop_everywhere |
963 self.stop_everywhere = False |
970 self.stop_everywhere = False |
964 self.eventPollFlag = False |
971 self.eventPollFlag = False |
965 self._dbgClient.unlockClient() |
972 self._dbgClient.unlockClient() |
966 self.stop_everywhere = stop_everywhere |
973 self.stop_everywhere = stop_everywhere |
967 |
974 |
968 self._dbgClient.dumpThreadList() |
975 self._dbgClient.dumpThreadList() |
969 |
976 |
970 def __extractExceptionName(self, exctype): |
977 def __extractExceptionName(self, exctype): |
971 """ |
978 """ |
972 Private method to extract the exception name given the exception |
979 Private method to extract the exception name given the exception |
973 type object. |
980 type object. |
974 |
981 |
975 @param exctype type of the exception |
982 @param exctype type of the exception |
976 @return exception name (string) |
983 @return exception name (string) |
977 """ |
984 """ |
978 return str(exctype).replace("<class '", "").replace("'>", "") |
985 return str(exctype).replace("<class '", "").replace("'>", "") |
979 |
986 |
980 def __extract_stack(self, exctb): |
987 def __extract_stack(self, exctb): |
981 """ |
988 """ |
982 Private member to return a list of stack frames. |
989 Private member to return a list of stack frames. |
983 |
990 |
984 @param exctb exception traceback |
991 @param exctb exception traceback |
985 @return list of stack frames |
992 @return list of stack frames |
986 """ |
993 """ |
987 tb = exctb |
994 tb = exctb |
988 stack = [] |
995 stack = [] |
1086 exitcode = 1 |
1092 exitcode = 1 |
1087 message = str(code) |
1093 message = str(code) |
1088 else: |
1094 else: |
1089 exitcode = 1 |
1095 exitcode = 1 |
1090 message = str(excval) |
1096 message = str(excval) |
1091 |
1097 |
1092 return exitcode, message |
1098 return exitcode, message |
1093 |
1099 |
1094 def stop_here(self, frame): |
1100 def stop_here(self, frame): |
1095 """ |
1101 """ |
1096 Public method reimplemented to filter out debugger files. |
1102 Public method reimplemented to filter out debugger files. |
1097 |
1103 |
1098 Tracing is turned off for files that are part of the |
1104 Tracing is turned off for files that are part of the |
1099 debugger that are called from the application being debugged. |
1105 debugger that are called from the application being debugged. |
1100 |
1106 |
1101 @param frame the frame object |
1107 @param frame the frame object |
1102 @type frame object |
1108 @type frame object |
1103 @return flag indicating whether the debugger should stop here |
1109 @return flag indicating whether the debugger should stop here |
1104 @rtype bool |
1110 @rtype bool |
1105 """ |
1111 """ |
1106 if self.__skipFrame(frame): |
1112 if self.__skipFrame(frame): |
1107 return False |
1113 return False |
1108 |
1114 |
1109 if frame is self.stopframe: |
1115 if frame is self.stopframe: |
1110 if self.stoplineno == -1: |
1116 if self.stoplineno == -1: |
1111 return False |
1117 return False |
1112 return frame.f_lineno >= self.stoplineno |
1118 return frame.f_lineno >= self.stoplineno |
1113 return self.stop_everywhere or frame is self.returnframe |
1119 return self.stop_everywhere or frame is self.returnframe |
1114 |
1120 |
1115 def tracePythonLibs(self, enable): |
1121 def tracePythonLibs(self, enable): |
1116 """ |
1122 """ |
1117 Public method to update the settings to trace into Python libraries. |
1123 Public method to update the settings to trace into Python libraries. |
1118 |
1124 |
1119 @param enable flag to debug into Python libraries |
1125 @param enable flag to debug into Python libraries |
1120 @type bool |
1126 @type bool |
1121 """ |
1127 """ |
1122 pathsToSkip = list(self.pathsToSkip) |
1128 pathsToSkip = list(self.pathsToSkip) |
1123 # don't trace into Python library? |
1129 # don't trace into Python library? |
1124 if enable: |
1130 if enable: |
1125 pathsToSkip = [x for x in pathsToSkip if not x.endswith( |
1131 pathsToSkip = [ |
1126 ("site-packages", "dist-packages", self.lib))] |
1132 x |
|
1133 for x in pathsToSkip |
|
1134 if not x.endswith(("site-packages", "dist-packages", self.lib)) |
|
1135 ] |
1127 else: |
1136 else: |
1128 pathsToSkip.append(self.lib) |
1137 pathsToSkip.append(self.lib) |
1129 localLib = [x for x in sys.path if x.endswith(("site-packages", |
1138 localLib = [ |
1130 "dist-packages")) and not x.startswith(self.lib)] |
1139 x |
|
1140 for x in sys.path |
|
1141 if x.endswith(("site-packages", "dist-packages")) |
|
1142 and not x.startswith(self.lib) |
|
1143 ] |
1131 pathsToSkip.extend(localLib) |
1144 pathsToSkip.extend(localLib) |
1132 |
1145 |
1133 self.pathsToSkip = tuple(set(pathsToSkip)) |
1146 self.pathsToSkip = tuple(set(pathsToSkip)) |
1134 |
1147 |
1135 def __skipFrame(self, frame): |
1148 def __skipFrame(self, frame): |
1136 """ |
1149 """ |
1137 Private method to filter out debugger files. |
1150 Private method to filter out debugger files. |
1138 |
1151 |
1139 Tracing is turned off for files that are part of the |
1152 Tracing is turned off for files that are part of the |
1140 debugger that are called from the application being debugged. |
1153 debugger that are called from the application being debugged. |
1141 |
1154 |
1142 @param frame the frame object |
1155 @param frame the frame object |
1143 @type frame object |
1156 @type frame object |
1144 @return flag indicating whether the debugger should skip this frame |
1157 @return flag indicating whether the debugger should skip this frame |
1145 @rtype bool |
1158 @rtype bool |
1146 """ |
1159 """ |