44import  sys 
55import  os 
66from  inspect  import  CO_GENERATOR , CO_COROUTINE , CO_ASYNC_GENERATOR 
7- from  functools  import  partial 
87
98__all__  =  ["BdbQuit" , "Bdb" , "Breakpoint" ]
109
@@ -18,10 +17,25 @@ class BdbQuit(Exception):
1817E  =  sys .monitoring .events 
1918
2019class  _MonitoringTracer :
20+     EVENT_CALLBACK_MAP  =  {
21+         E .PY_START : 'call' ,
22+         E .PY_RESUME : 'call' ,
23+         E .PY_THROW : 'call' ,
24+         E .LINE : 'line' ,
25+         E .JUMP : 'jump' ,
26+         E .PY_RETURN : 'return' ,
27+         E .PY_YIELD : 'return' ,
28+         E .PY_UNWIND : 'unwind' ,
29+         E .RAISE : 'exception' ,
30+         E .STOP_ITERATION : 'exception' ,
31+         E .INSTRUCTION : 'opcode' ,
32+     }
33+ 
2134    def  __init__ (self ):
2235        self ._tool_id  =  sys .monitoring .DEBUGGER_ID 
2336        self ._name  =  'bdbtracer' 
2437        self ._tracefunc  =  None 
38+         self ._disable_current_event  =  False 
2539
2640    def  start_trace (self , tracefunc ):
2741        self ._tracefunc  =  tracefunc 
@@ -34,48 +48,49 @@ def start_trace(self, tracefunc):
3448            raise  ValueError ('Another debugger is using the monitoring tool' )
3549        E  =  sys .monitoring .events 
3650        all_events  =  0 
37-         for  event  in  (E .PY_START , E .PY_RESUME , E .PY_THROW ):
38-             sys .monitoring .register_callback (self ._tool_id , event , self .call_callback )
39-             all_events  |=  event 
40-         for  event  in  (E .LINE , ):
41-             sys .monitoring .register_callback (self ._tool_id , event , self .line_callback )
42-             all_events  |=  event 
43-         for  event  in  (E .JUMP , ):
44-             sys .monitoring .register_callback (self ._tool_id , event , self .jump_callback )
45-             all_events  |=  event 
46-         for  event  in  (E .PY_RETURN , E .PY_YIELD ):
47-             sys .monitoring .register_callback (self ._tool_id , event , self .return_callback )
48-             all_events  |=  event 
49-         for  event  in  (E .PY_UNWIND , ):
50-             sys .monitoring .register_callback (self ._tool_id , event , self .unwind_callback )
51-             all_events  |=  event 
52-         for  event  in  (E .RAISE , E .STOP_ITERATION ):
53-             sys .monitoring .register_callback (self ._tool_id , event , self .exception_callback )
54-             all_events  |=  event 
55-         for  event  in  (E .INSTRUCTION , ):
56-             sys .monitoring .register_callback (self ._tool_id , event , self .opcode_callback )
51+         for  event , cb_name  in  self .EVENT_CALLBACK_MAP .items ():
52+             callback  =  getattr (self , f'{ cb_name }  )
53+             sys .monitoring .register_callback (self ._tool_id , event , callback )
54+             if  event  !=  E .INSTRUCTION :
55+                 all_events  |=  event 
5756        self .check_trace_opcodes ()
5857        sys .monitoring .set_events (self ._tool_id , all_events )
5958
6059    def  stop_trace (self ):
6160        curr_tool  =  sys .monitoring .get_tool (self ._tool_id )
6261        if  curr_tool  !=  self ._name :
6362            return 
64-         for  event  in  (E .PY_START , E .PY_RESUME , E .PY_RETURN , E .PY_YIELD , E .RAISE , E .LINE ,
65-                       E .JUMP , E .PY_UNWIND , E .PY_THROW , E .STOP_ITERATION ):
63+         for  event  in  self .EVENT_CALLBACK_MAP .keys ():
6664            sys .monitoring .register_callback (self ._tool_id , event , None )
6765        sys .monitoring .set_events (self ._tool_id , 0 )
6866        self .check_trace_opcodes ()
6967        sys .monitoring .free_tool_id (self ._tool_id )
7068
69+     def  disable_current_event (self ):
70+         self ._disable_current_event  =  True 
71+ 
72+     def  restart_events (self ):
73+         if  sys .monitoring .get_tool (self ._tool_id ) ==  self ._name :
74+             sys .monitoring .restart_events ()
75+ 
7176    def  callback_wrapper (func ):
77+         import  functools 
78+ 
79+         @functools .wraps (func ) 
7280        def  wrapper (self , * args ):
7381            try :
7482                frame  =  sys ._getframe ().f_back 
75-                 return  func (self , frame , * args )
83+                 ret  =  func (self , frame , * args )
84+                 if  self ._disable_current_event :
85+                     return  sys .monitoring .DISABLE 
86+                 else :
87+                     return  ret 
7688            except  Exception :
7789                self .stop_trace ()
7890                raise 
91+             finally :
92+                 self ._disable_current_event  =  False 
93+ 
7994        return  wrapper 
8095
8196    @callback_wrapper  
@@ -275,6 +290,8 @@ def dispatch_line(self, frame):
275290        if  self .stop_here (frame ) or  self .break_here (frame ):
276291            self .user_line (frame )
277292            if  self .quitting : raise  BdbQuit 
293+         else :
294+             self .disable_current_event ()
278295        return  self .trace_dispatch 
279296
280297    def  dispatch_call (self , frame , arg ):
@@ -296,6 +313,7 @@ def dispatch_call(self, frame, arg):
296313        if  self .stopframe  and  frame .f_code .co_flags  &  GENERATOR_AND_COROUTINE_FLAGS :
297314            return  self .trace_dispatch 
298315        self .user_call (frame , arg )
316+         self .restart_events ()
299317        if  self .quitting : raise  BdbQuit 
300318        return  self .trace_dispatch 
301319
@@ -313,6 +331,7 @@ def dispatch_return(self, frame, arg):
313331            try :
314332                self .frame_returning  =  frame 
315333                self .user_return (frame , arg )
334+                 self .restart_events ()
316335            finally :
317336                self .frame_returning  =  None 
318337            if  self .quitting : raise  BdbQuit 
@@ -340,6 +359,7 @@ def dispatch_exception(self, frame, arg):
340359            if  not  (frame .f_code .co_flags  &  GENERATOR_AND_COROUTINE_FLAGS 
341360                    and  arg [0 ] is  StopIteration  and  arg [2 ] is  None ):
342361                self .user_exception (frame , arg )
362+                 self .restart_events ()
343363                if  self .quitting : raise  BdbQuit 
344364        # Stop at the StopIteration or GeneratorExit exception when the user 
345365        # has set stopframe in a generator by issuing a return command, or a 
@@ -349,6 +369,7 @@ def dispatch_exception(self, frame, arg):
349369                and  self .stopframe .f_code .co_flags  &  GENERATOR_AND_COROUTINE_FLAGS 
350370                and  arg [0 ] in  (StopIteration , GeneratorExit )):
351371            self .user_exception (frame , arg )
372+             self .restart_events ()
352373            if  self .quitting : raise  BdbQuit 
353374
354375        return  self .trace_dispatch 
@@ -361,6 +382,7 @@ def dispatch_opcode(self, frame, arg):
361382        """ 
362383        if  self .stop_here (frame ) or  self .break_here (frame ):
363384            self .user_opcode (frame )
385+             self .restart_events ()
364386            if  self .quitting : raise  BdbQuit 
365387        return  self .trace_dispatch 
366388
@@ -788,6 +810,16 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
788810            s  +=  f'{ lprefix }  
789811        return  s 
790812
813+     def  disable_current_event (self ):
814+         """Disable the current event.""" 
815+         if  self .backend  ==  'monitoring' :
816+             self .monitoring_tracer .disable_current_event ()
817+ 
818+     def  restart_events (self ):
819+         """Restart all events.""" 
820+         if  self .backend  ==  'monitoring' :
821+             self .monitoring_tracer .restart_events ()
822+ 
791823    # The following methods can be called by clients to use 
792824    # a debugger to debug a statement or an expression. 
793825    # Both can be given as a string, or a code object. 
0 commit comments