eric6/DebugClients/Python/DebugBase.py

changeset 7897
9acc015ea443
parent 7894
4370a8b30648
child 7900
72b88fb20261
equal deleted inserted replaced
7896:75ce42b1df23 7897:9acc015ea443
20 20
21 import _thread 21 import _thread
22 from DebugUtilities import getargvalues, formatargvalues 22 from DebugUtilities import getargvalues, formatargvalues
23 23
24 gRecursionLimit = 64 24 gRecursionLimit = 64
25
26 GENERATOR_AND_COROUTINE_FLAGS = (
27 inspect.CO_GENERATOR | inspect.CO_COROUTINE | inspect.CO_ASYNC_GENERATOR
28 )
25 29
26 30
27 def printerr(s): 31 def printerr(s):
28 """ 32 """
29 Module function used for debugging the debug client. 33 Module function used for debugging the debug client.
307 if self.quitting: 311 if self.quitting:
308 raise SystemExit 312 raise SystemExit
309 313
310 if event == 'line': 314 if event == 'line':
311 if self.stop_here(frame) or self.break_here(frame): 315 if self.stop_here(frame) or self.break_here(frame):
312 if (self.stop_everywhere and frame.f_back and 316 if (
313 frame.f_back.f_code.co_name == "prepareJsonCommand"): 317 self.stop_everywhere and
318 frame.f_back and
319 frame.f_back.f_code.co_name == "prepareJsonCommand"
320 ):
314 # Just stepped into print statement, so skip these frames 321 # Just stepped into print statement, so skip these frames
315 self._set_stopinfo(None, frame.f_back) 322 self._set_stopinfo(None, frame.f_back)
316 else: 323 else:
317 self.user_line(frame) 324 self.user_line(frame)
318 return self.trace_dispatch 325 return self.trace_dispatch
319 326
320 if event == 'call': 327 if event == 'call':
321 if (self.stop_here(frame) or 328 if (
322 self.__checkBreakInFrame(frame) or 329 self.stop_here(frame) or
323 Watch.watches != []): 330 self.__checkBreakInFrame(frame) or
331 Watch.watches != []
332 ):
333 return self.trace_dispatch
334 elif (
335 self.stopframe and
336 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
337 ):
324 return self.trace_dispatch 338 return self.trace_dispatch
325 else: 339 else:
326 # No need to trace this function 340 # No need to trace this function
327 return None 341 return None
328 342
329 if event == 'return': 343 if event == 'return':
330 if frame == self.returnframe: 344 if self.stop_here(frame) or frame == self.returnframe:
331 # Only true if we didn't stopped in this frame, because it's 345 # Ignore return events in generator except when stepping.
346 if (
347 self.stopframe and
348 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
349 ):
350 return self.trace_dispatch
351 # Only true if we didn't stop in this frame, because it's
332 # belonging to the eric debugger. 352 # belonging to the eric debugger.
333 self._set_stopinfo(None, frame.f_back) 353 if self.stopframe is frame and self.stoplineno != -1:
354 self._set_stopinfo(None, frame.f_back)
334 return None 355 return None
335 356
336 if event == 'exception': 357 if event == 'exception':
337 if not self.__skipFrame(frame): 358 if not self.__skipFrame(frame):
338 # When stepping with next/until/return in a generator frame, 359 # When stepping with next/until/return in a generator frame,
339 # skip the internal StopIteration exception (with no traceback) 360 # skip the internal StopIteration exception (with no traceback)
340 # triggered by a subiterator run with the 'yield from' 361 # triggered by a subiterator run with the 'yield from'
341 # statement. 362 # statement.
342 if not (frame.f_code.co_flags & inspect.CO_GENERATOR and 363 if not (
343 arg[0] is StopIteration and arg[2] is None): 364 frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS and
365 arg[0] is StopIteration and
366 arg[2] is None
367 ):
344 self.user_exception(arg) 368 self.user_exception(arg)
345 # Stop at the StopIteration or GeneratorExit exception when the 369 # Stop at the StopIteration or GeneratorExit exception when the
346 # user has set stopframe in a generator by issuing a return 370 # user has set stopframe in a generator by issuing a return
347 # command, or a next/until command at the last statement in the 371 # command, or a next/until command at the last statement in the
348 # generator before the exception. 372 # generator before the exception.
349 elif (self.stopframe and frame is not self.stopframe and 373 elif (
350 self.stopframe.f_code.co_flags & inspect.CO_GENERATOR and 374 self.stopframe and
351 arg[0] in (StopIteration, GeneratorExit)): 375 frame is not self.stopframe and
376 (self.stopframe.f_code.co_flags &
377 GENERATOR_AND_COROUTINE_FLAGS) and
378 arg[0] in (StopIteration, GeneratorExit)
379 ):
352 self.user_exception(arg) 380 self.user_exception(arg)
353 return None 381 return None
354 382
355 if event == 'c_call': 383 if event == 'c_call':
356 return None 384 return None
360 return None 388 return None
361 389
362 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING_M801__ 390 print('DebugBase.trace_dispatch:' # __IGNORE_WARNING_M801__
363 ' unknown debugging event: ', 391 ' unknown debugging event: ',
364 repr(event)) 392 repr(event))
393
365 return self.trace_dispatch 394 return self.trace_dispatch
366 395
367 def set_trace(self, frame=None): 396 def set_trace(self, frame=None):
368 """ 397 """
369 Public method to start debugging from 'frame'. 398 Public method to start debugging from 'frame'.
381 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__ 410 stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__
382 411
383 frame.f_trace = self.trace_dispatch 412 frame.f_trace = self.trace_dispatch
384 while frame.f_back is not None: 413 while frame.f_back is not None:
385 # stop at eric's debugger frame or a threading bootstrap 414 # stop at eric's debugger frame or a threading bootstrap
386 if (frame.f_back.f_code == stopOnHandleCommand): 415 if frame.f_back.f_code == stopOnHandleCommand:
387 frame.f_trace = self.trace_dispatch 416 frame.f_trace = self.trace_dispatch
388 break 417 break
389 418
390 frame = frame.f_back 419 frame = frame.f_back
391 420
469 finally: 498 finally:
470 self.quitting = True 499 self.quitting = True
471 sys.settrace(None) 500 sys.settrace(None)
472 return exitcode 501 return exitcode
473 502
474 def _set_stopinfo(self, stopframe, returnframe): 503 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
475 """ 504 """
476 Protected method to update the frame pointers. 505 Protected method to update the frame pointers.
477 506
478 @param stopframe the frame object where to stop 507 @param stopframe the frame object where to stop
479 @type frame object 508 @type frame object
480 @param returnframe the frame object where to stop on a function return 509 @param returnframe the frame object where to stop on a function return
481 @type frame object 510 @type frame object
511 @param stoplineno line number to stop at. If stoplineno is greater than
512 or equal to 0, then stop at line greater than or equal to the
513 stopline. If stoplineno is -1, then don't stop at all.
514 @type int
482 """ 515 """
483 self.stopframe = stopframe 516 self.stopframe = stopframe
484 self.returnframe = returnframe 517 self.returnframe = returnframe
518 # stoplineno >= 0 means: stop at line >= the stoplineno
519 # stoplineno -1 means: don't stop at all
520 self.stoplineno = stoplineno
521
485 if returnframe is not None: 522 if returnframe is not None:
486 # Ensure to be able to stop on the return frame 523 # Ensure to be able to stop on the return frame
487 returnframe.f_trace = self.trace_dispatch 524 returnframe.f_trace = self.trace_dispatch
488 self.stop_everywhere = False 525 self.stop_everywhere = False
489 526
494 @param special flag indicating a special continue operation 531 @param special flag indicating a special continue operation
495 @type bool 532 @type bool
496 """ 533 """
497 # Here we only set a new stop frame if it is a normal continue. 534 # Here we only set a new stop frame if it is a normal continue.
498 if not special: 535 if not special:
499 self._set_stopinfo(None, None) 536 self._set_stopinfo(None, None, -1)
500 537
501 # Disable tracing if not started in debug mode 538 # Disable tracing if not started in debug mode
502 if not self._dbgClient.debugging: 539 if not self._dbgClient.debugging:
503 sys.settrace(None) 540 sys.settrace(None)
504 sys.setprofile(None) 541 sys.setprofile(None)
542
543 def set_until(self, frame=None, lineno=None):
544 """
545 Public method to stop when the line with the lineno greater than the
546 current one is reached or when returning from current frame.
547
548 @param frame reference to the frame object
549 @type frame object
550 @param lineno line number to continue to
551 @type int
552 """
553 # the name "until" is borrowed from gdb
554 if frame is None:
555 frame = self.currentFrame
556 if lineno is None:
557 lineno = frame.f_lineno + 1
558 self._set_stopinfo(frame, frame, lineno)
505 559
506 def set_step(self): 560 def set_step(self):
507 """ 561 """
508 Public method to stop after one line of code. 562 Public method to stop after one line of code.
509 """ 563 """
723 fr.f_trace = self.trace_dispatch 777 fr.f_trace = self.trace_dispatch
724 778
725 fname = self._dbgClient.absPath(self.fix_frame_filename(fr)) 779 fname = self._dbgClient.absPath(self.fix_frame_filename(fr))
726 # Always show at least one stack frame, even if it's from eric. 780 # Always show at least one stack frame, even if it's from eric.
727 if stack and os.path.basename(fname).startswith( 781 if stack and os.path.basename(fname).startswith(
728 ("DebugBase.py", "DebugClientBase.py", 782 ("DebugBase.py", "DebugClientBase.py",
729 "ThreadExtension.py", "threading.py")): 783 "ThreadExtension.py", "threading.py")
784 ):
730 break 785 break
731 786
732 fline = tb_lineno or fr.f_lineno 787 fline = tb_lineno or fr.f_lineno
733 ffunc = fr.f_code.co_name 788 ffunc = fr.f_code.co_name
734 789
1029 else: 1084 else:
1030 exitcode = 1 1085 exitcode = 1
1031 message = str(excval) 1086 message = str(excval)
1032 1087
1033 return exitcode, message 1088 return exitcode, message
1034 1089
1035 def stop_here(self, frame): 1090 def stop_here(self, frame):
1036 """ 1091 """
1037 Public method reimplemented to filter out debugger files. 1092 Public method reimplemented to filter out debugger files.
1038 1093
1039 Tracing is turned off for files that are part of the 1094 Tracing is turned off for files that are part of the
1045 @rtype bool 1100 @rtype bool
1046 """ 1101 """
1047 if self.__skipFrame(frame): 1102 if self.__skipFrame(frame):
1048 return False 1103 return False
1049 1104
1050 return (self.stop_everywhere or 1105 if frame is self.stopframe:
1051 frame is self.stopframe or 1106 if self.stoplineno == -1:
1052 frame is self.returnframe) 1107 return False
1108 return frame.f_lineno >= self.stoplineno
1109 return self.stop_everywhere or frame is self.returnframe
1053 1110
1054 def tracePythonLibs(self, enable): 1111 def tracePythonLibs(self, enable):
1055 """ 1112 """
1056 Public method to update the settings to trace into Python libraries. 1113 Public method to update the settings to trace into Python libraries.
1057 1114

eric ide

mercurial