src/eric7/DebugClients/Python/DebugBase.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9462
e65379fdbd97
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
24 24
25 gRecursionLimit = 64 25 gRecursionLimit = 64
26 26
27 try: 27 try:
28 GENERATOR_AND_COROUTINE_FLAGS = ( 28 GENERATOR_AND_COROUTINE_FLAGS = (
29 inspect.CO_GENERATOR | inspect.CO_COROUTINE | 29 inspect.CO_GENERATOR | inspect.CO_COROUTINE | inspect.CO_ASYNC_GENERATOR
30 inspect.CO_ASYNC_GENERATOR
31 ) 30 )
32 except AttributeError: 31 except AttributeError:
33 # Python < 3.7 32 # Python < 3.7
34 GENERATOR_AND_COROUTINE_FLAGS = inspect.CO_GENERATOR 33 GENERATOR_AND_COROUTINE_FLAGS = inspect.CO_GENERATOR
35 34
36 35
37 def printerr(s): 36 def printerr(s):
38 """ 37 """
39 Module function used for debugging the debug client. 38 Module function used for debugging the debug client.
40 39
41 @param s data to be printed 40 @param s data to be printed
42 """ 41 """
43 sys.__stderr__.write('{0!s}\n'.format(s)) 42 sys.__stderr__.write("{0!s}\n".format(s))
44 sys.__stderr__.flush() 43 sys.__stderr__.flush()
45 44
46 45
47 def setRecursionLimit(limit): 46 def setRecursionLimit(limit):
48 """ 47 """
49 Module function to set the recursion limit. 48 Module function to set the recursion limit.
50 49
51 @param limit recursion limit (integer) 50 @param limit recursion limit (integer)
52 """ 51 """
53 global gRecursionLimit 52 global gRecursionLimit
54 gRecursionLimit = limit 53 gRecursionLimit = limit
55 54
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
438 """ 435 """
439 try: 436 try:
440 # Because in the initial run method the "base debug" function is 437 # Because in the initial run method the "base debug" function is
441 # set up, it's also valid for the threads afterwards. 438 # set up, it's also valid for the threads afterwards.
442 sys.settrace(self.trace_dispatch) 439 sys.settrace(self.trace_dispatch)
443 440
444 target(*args, **kwargs) 441 target(*args, **kwargs)
445 except Exception: 442 except Exception:
446 excinfo = sys.exc_info() 443 excinfo = sys.exc_info()
447 self.user_exception(excinfo, True) 444 self.user_exception(excinfo, True)
448 finally: 445 finally:
449 sys.settrace(None) 446 sys.settrace(None)
450 sys.setprofile(None) 447 sys.setprofile(None)
451 448
452 def run(self, cmd, globalsDict=None, localsDict=None, debug=True, 449 def run(
453 closeSession=True): 450 self, cmd, globalsDict=None, localsDict=None, debug=True, closeSession=True
451 ):
454 """ 452 """
455 Public method to start a given command under debugger control. 453 Public method to start a given command under debugger control.
456 454
457 @param cmd command / code to execute under debugger control 455 @param cmd command / code to execute under debugger control
458 @type str or CodeType 456 @type str or CodeType
459 @param globalsDict dictionary of global variables for cmd 457 @param globalsDict dictionary of global variables for cmd
460 @type dict 458 @type dict
461 @param localsDict dictionary of local variables for cmd 459 @param localsDict dictionary of local variables for cmd
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:
506 return exitcode 506 return exitcode
507 507
508 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0): 508 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
509 """ 509 """
510 Protected method to update the frame pointers. 510 Protected method to update the frame pointers.
511 511
512 @param stopframe the frame object where to stop 512 @param stopframe the frame object where to stop
513 @type frame object 513 @type frame object
514 @param returnframe the frame object where to stop on a function return 514 @param returnframe the frame object where to stop on a function return
515 @type frame object 515 @type frame object
516 @param stoplineno line number to stop at. If stoplineno is greater than 516 @param stoplineno line number to stop at. If stoplineno is greater than
521 self.stopframe = stopframe 521 self.stopframe = stopframe
522 self.returnframe = returnframe 522 self.returnframe = returnframe
523 # stoplineno >= 0 means: stop at line >= the stoplineno 523 # stoplineno >= 0 means: stop at line >= the stoplineno
524 # stoplineno -1 means: don't stop at all 524 # stoplineno -1 means: don't stop at all
525 self.stoplineno = stoplineno 525 self.stoplineno = stoplineno
526 526
527 if returnframe is not None: 527 if returnframe is not None:
528 # Ensure to be able to stop on the return frame 528 # Ensure to be able to stop on the return frame
529 returnframe.f_trace = self.trace_dispatch 529 returnframe.f_trace = self.trace_dispatch
530 self.stop_everywhere = False 530 self.stop_everywhere = False
531 531
532 def set_continue(self, special): 532 def set_continue(self, special):
533 """ 533 """
534 Public method to stop only on next breakpoint. 534 Public method to stop only on next breakpoint.
535 535
536 @param special flag indicating a special continue operation 536 @param special flag indicating a special continue operation
537 @type bool 537 @type bool
538 """ 538 """
539 # Here we only set a new stop frame if it is a normal continue. 539 # Here we only set a new stop frame if it is a normal continue.
540 if not special: 540 if not special:
541 self._set_stopinfo(None, None, -1) 541 self._set_stopinfo(None, None, -1)
542 542
543 # Disable tracing if not started in debug mode 543 # Disable tracing if not started in debug mode
544 if not self._dbgClient.debugging: 544 if not self._dbgClient.debugging:
545 sys.settrace(None) 545 sys.settrace(None)
546 sys.setprofile(None) 546 sys.setprofile(None)
547 547
548 def set_until(self, frame=None, lineno=None): 548 def set_until(self, frame=None, lineno=None):
549 """ 549 """
550 Public method to stop when the line with the lineno greater than the 550 Public method to stop when the line with the lineno greater than the
551 current one is reached or when returning from current frame. 551 current one is reached or when returning from current frame.
552 552
553 @param frame reference to the frame object 553 @param frame reference to the frame object
554 @type frame object 554 @type frame object
555 @param lineno line number to continue to 555 @param lineno line number to continue to
556 @type int 556 @type int
557 """ 557 """
570 self.stop_everywhere = True 570 self.stop_everywhere = True
571 571
572 def set_next(self, frame): 572 def set_next(self, frame):
573 """ 573 """
574 Public method to stop on the next line in or below the given frame. 574 Public method to stop on the next line in or below the given frame.
575 575
576 @param frame the frame object 576 @param frame the frame object
577 @type frame object 577 @type frame object
578 """ 578 """
579 self._set_stopinfo(frame, frame.f_back) 579 self._set_stopinfo(frame, frame.f_back)
580 frame.f_trace = self.trace_dispatch 580 frame.f_trace = self.trace_dispatch
581 581
582 def set_return(self, frame): 582 def set_return(self, frame):
583 """ 583 """
584 Public method to stop when returning from the given frame. 584 Public method to stop when returning from the given frame.
585 585
586 @param frame the frame object 586 @param frame the frame object
587 @type frame object 587 @type frame object
588 """ 588 """
589 self._set_stopinfo(None, frame.f_back) 589 self._set_stopinfo(None, frame.f_back)
590 590
591 def move_instruction_pointer(self, lineno): 591 def move_instruction_pointer(self, lineno):
592 """ 592 """
593 Public method to move the instruction pointer to another line. 593 Public method to move the instruction pointer to another line.
594 594
595 @param lineno new line number 595 @param lineno new line number
596 @type int 596 @type int
597 """ 597 """
598 try: 598 try:
599 self.currentFrame.f_lineno = lineno 599 self.currentFrame.f_lineno = lineno
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 """
743 self._dbgClient.sendClearTemporaryBreakpoint(filename, lineno) 742 self._dbgClient.sendClearTemporaryBreakpoint(filename, lineno)
744 743
745 def __do_clearWatch(self, cond): 744 def __do_clearWatch(self, cond):
746 """ 745 """
747 Private method called to clear a temporary watch expression. 746 Private method called to clear a temporary watch expression.
748 747
749 @param cond expression of the watch expression to be cleared 748 @param cond expression of the watch expression to be cleared
750 @type str 749 @type str
751 """ 750 """
752 Watch.clear_watch(cond) 751 Watch.clear_watch(cond)
753 self._dbgClient.sendClearTemporaryWatch(cond) 752 self._dbgClient.sendClearTemporaryWatch(cond)
754 753
755 def getStack(self, frame=None, applyTrace=False): 754 def getStack(self, frame=None, applyTrace=False):
756 """ 755 """
757 Public method to get the stack. 756 Public method to get the stack.
758 757
759 @param frame frame object to inspect 758 @param frame frame object to inspect
760 @type frame object or list 759 @type frame object or list
761 @param applyTrace flag to assign trace function to fr.f_trace 760 @param applyTrace flag to assign trace function to fr.f_trace
762 @type bool 761 @type bool
763 @return list of lists with file name (string), line number (integer) 762 @return list of lists with file name (string), line number (integer)
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 = []
993 return stack 1000 return stack
994 1001
995 def __disassemble(self, frame): 1002 def __disassemble(self, frame):
996 """ 1003 """
997 Private method to generate a disassembly of the given code object. 1004 Private method to generate a disassembly of the given code object.
998 1005
999 @param frame frame object to be disassembled 1006 @param frame frame object to be disassembled
1000 @type code 1007 @type code
1001 @return dictionary containing the disassembly information 1008 @return dictionary containing the disassembly information
1002 @rtype dict 1009 @rtype dict
1003 """ 1010 """
1005 disDict = { 1012 disDict = {
1006 "lasti": frame.f_lasti, 1013 "lasti": frame.f_lasti,
1007 "firstlineno": co.co_firstlineno, 1014 "firstlineno": co.co_firstlineno,
1008 "instructions": [], 1015 "instructions": [],
1009 } 1016 }
1010 1017
1011 # 1. disassembly info 1018 # 1. disassembly info
1012 for instr in dis.get_instructions(co): 1019 for instr in dis.get_instructions(co):
1013 instrDict = { 1020 instrDict = {
1014 "lineno": 1021 "lineno": 0 if instr.starts_line is None else instr.starts_line,
1015 0 if instr.starts_line is None else instr.starts_line,
1016 "isJumpTarget": instr.is_jump_target, 1022 "isJumpTarget": instr.is_jump_target,
1017 "offset": instr.offset, 1023 "offset": instr.offset,
1018 "opname": instr.opname, 1024 "opname": instr.opname,
1019 "arg": instr.arg, 1025 "arg": instr.arg,
1020 "argrepr": instr.argrepr, 1026 "argrepr": instr.argrepr,
1021 } 1027 }
1022 disDict["instructions"].append(instrDict) 1028 disDict["instructions"].append(instrDict)
1023 1029
1024 # 2. code info 1030 # 2. code info
1025 # Note: keep in sync with PythonDisViewer.__createCodeInfo() 1031 # Note: keep in sync with PythonDisViewer.__createCodeInfo()
1026 disDict["codeinfo"] = { 1032 disDict["codeinfo"] = {
1027 "name": co.co_name, 1033 "name": co.co_name,
1028 "filename": co.co_filename, 1034 "filename": co.co_filename,
1041 try: 1047 try:
1042 disDict["codeinfo"]["posonlyargcount"] = co.co_posonlyargcount 1048 disDict["codeinfo"]["posonlyargcount"] = co.co_posonlyargcount
1043 except AttributeError: 1049 except AttributeError:
1044 # does not exist prior to 3.8.0 1050 # does not exist prior to 3.8.0
1045 disDict["codeinfo"]["posonlyargcount"] = 0 1051 disDict["codeinfo"]["posonlyargcount"] = 0
1046 1052
1047 return disDict 1053 return disDict
1048 1054
1049 def __extractSystemExitMessage(self, excinfo): 1055 def __extractSystemExitMessage(self, excinfo):
1050 """ 1056 """
1051 Private method to get the SystemExit code and message. 1057 Private method to get the SystemExit code and message.
1052 1058
1053 @param excinfo details about the SystemExit exception 1059 @param excinfo details about the SystemExit exception
1054 @type tuple(Exception, excval object, traceback frame object) 1060 @type tuple(Exception, excval object, traceback frame object)
1055 @return SystemExit code and message 1061 @return SystemExit code and message
1056 @rtype int, str 1062 @rtype int, str
1057 """ 1063 """
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 """

eric ide

mercurial