src/eric7/DebugClients/Python/DebugBase.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9462
e65379fdbd97
--- a/src/eric7/DebugClients/Python/DebugBase.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/DebugClients/Python/DebugBase.py	Wed Jul 13 14:55:47 2022 +0200
@@ -26,8 +26,7 @@
 
 try:
     GENERATOR_AND_COROUTINE_FLAGS = (
-        inspect.CO_GENERATOR | inspect.CO_COROUTINE |
-        inspect.CO_ASYNC_GENERATOR
+        inspect.CO_GENERATOR | inspect.CO_COROUTINE | inspect.CO_ASYNC_GENERATOR
     )
 except AttributeError:
     # Python < 3.7
@@ -37,17 +36,17 @@
 def printerr(s):
     """
     Module function used for debugging the debug client.
-    
+
     @param s data to be printed
     """
-    sys.__stderr__.write('{0!s}\n'.format(s))
+    sys.__stderr__.write("{0!s}\n".format(s))
     sys.__stderr__.flush()
 
 
 def setRecursionLimit(limit):
     """
     Module function to set the recursion limit.
-    
+
     @param limit recursion limit (integer)
     """
     global gRecursionLimit
@@ -60,55 +59,56 @@
 
     Provides methods for the 'owning' client to call to step etc.
     """
+
     lib = os.path.dirname(inspect.__file__)
     # tuple required because it's accessed a lot of times by startswith method
-    pathsToSkip = ('<', os.path.dirname(__file__), inspect.__file__[:-1])
+    pathsToSkip = ("<", os.path.dirname(__file__), inspect.__file__[:-1])
     filesToSkip = {}
 
     # cache for fixed file names
     _fnCache = {}
-    
+
     # Stop all timers, when greenlets are used
     pollTimerEnabled = True
 
     def __init__(self, dbgClient):
         """
         Constructor
-        
+
         @param dbgClient the owning client
         """
         self._dbgClient = dbgClient
-        
+
         # Some informations about the thread
         self.isMainThread = False
         self.quitting = False
         self.id = -1
-        self.name = ''
-        
+        self.name = ""
+
         self.tracePythonLibs(False)
-        
+
         # Special handling of a recursion error
         self.skipFrames = 0
-        
+
         self.isBroken = False
         self.isException = False
         self.cFrame = None
-        
+
         # current frame we are at
         self.currentFrame = None
-        
+
         # frames, where we want to stop or release debugger
         self.stopframe = None
         self.returnframe = None
         self.stop_everywhere = False
-        
+
         self.__recursionDepth = -1
         self.setRecursionDepth(inspect.currentframe())
-        
+
         # background task to periodicaly check for client interactions
         self.eventPollFlag = False
         self.timer = _thread.start_new_thread(self.__eventPollTimer, ())
-        
+
         # provide a hook to perform a hard breakpoint
         # Use it like this:
         # if hasattr(sys, 'breakpoint): sys.breakpoint()
@@ -123,27 +123,27 @@
         while DebugBase.pollTimerEnabled:
             time.sleep(0.5)
             self.eventPollFlag = True
-        
+
         self.eventPollFlag = False
-    
+
     def getCurrentFrame(self):
         """
         Public method to return the current frame.
-        
+
         @return the current frame
         @rtype frame object
         """
         # Don't show any local frames after the program was stopped
         if self.quitting:
             return None
-        
+
         return self.currentFrame
-    
+
     def getFrameLocals(self, frmnr=0):
         """
         Public method to return the locals dictionary of the current frame
         or a frame below.
-        
+
         @param frmnr distance of frame to get locals dictionary of. 0 is
             the current frame (int)
         @return locals dictionary of the frame
@@ -153,12 +153,12 @@
             f = f.f_back
             frmnr -= 1
         return f.f_locals
-    
+
     def storeFrameLocals(self, frmnr=0):
         """
         Public method to store the locals into the frame, so an access to
         frame.f_locals returns the last data.
-        
+
         @param frmnr distance of frame to store locals dictionary to. 0 is
             the current frame (int)
         """
@@ -166,21 +166,20 @@
         while cf is not None and frmnr > 0:
             cf = cf.f_back
             frmnr -= 1
-        
+
         with contextlib.suppress(Exception):
             if "__pypy__" in sys.builtin_module_names:
                 import __pypy__
+
                 __pypy__.locals_to_fast(cf)
                 return
-        
-        ctypes.pythonapi.PyFrame_LocalsToFast(
-            ctypes.py_object(cf),
-            ctypes.c_int(0))
-    
+
+        ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(cf), ctypes.c_int(0))
+
     def step(self, traceMode):
         """
         Public method to perform a step operation in this thread.
-        
+
         @param traceMode If it is True, then the step is a step into,
               otherwise it is a step over.
         """
@@ -188,39 +187,39 @@
             self.set_step()
         else:
             self.set_next(self.currentFrame)
-    
+
     def stepOut(self):
         """
         Public method to perform a step out of the current call.
         """
         self.set_return(self.currentFrame)
-    
+
     def go(self, special):
         """
         Public method to resume the thread.
 
         It resumes the thread stopping only at breakpoints or exceptions.
-        
+
         @param special flag indicating a special continue operation
         """
         self.set_continue(special)
-    
+
     def setRecursionDepth(self, frame):
         """
         Public method to determine the current recursion depth.
-        
+
         @param frame The current stack frame.
         """
         self.__recursionDepth = 0
         while frame is not None:
             self.__recursionDepth += 1
             frame = frame.f_back
-    
+
     def profileWithRecursion(self, frame, event, arg):
         """
         Public method used to trace some stuff independent of the debugger
         trace function.
-        
+
         @param frame current stack frame
         @type frame object
         @param event trace event
@@ -229,26 +228,27 @@
         @type depends on the previous event parameter
         @exception RuntimeError raised to indicate too many recursions
         """
-        if event == 'return':
+        if event == "return":
             self.cFrame = frame.f_back
             self.__recursionDepth -= 1
             if self._dbgClient.callTraceEnabled:
                 self.__sendCallTrace(event, frame, self.cFrame)
-        elif event == 'call':
+        elif event == "call":
             if self._dbgClient.callTraceEnabled:
                 self.__sendCallTrace(event, self.cFrame, frame)
             self.cFrame = frame
             self.__recursionDepth += 1
             if self.__recursionDepth > gRecursionLimit:
                 raise RuntimeError(
-                    'maximum recursion depth exceeded\n'
-                    '(offending frame is two down the stack)')
-    
+                    "maximum recursion depth exceeded\n"
+                    "(offending frame is two down the stack)"
+                )
+
     def profile(self, frame, event, arg):
         """
         Public method used to trace some stuff independent of the debugger
         trace function.
-        
+
         @param frame current stack frame
         @type frame object
         @param event trace event
@@ -256,15 +256,15 @@
         @param arg arguments
         @type depends on the previous event parameter
         """
-        if event == 'return':
+        if event == "return":
             self.__sendCallTrace(event, frame, frame.f_back)
-        elif event == 'call':
+        elif event == "call":
             self.__sendCallTrace(event, frame.f_back, frame)
-    
+
     def __sendCallTrace(self, event, fromFrame, toFrame):
         """
         Private method to send a call/return trace.
-        
+
         @param event trace event
         @type str
         @param fromFrame originating frame
@@ -274,27 +274,25 @@
         """
         if not self.__skipFrame(fromFrame) and not self.__skipFrame(toFrame):
             fromInfo = {
-                "filename": self._dbgClient.absPath(
-                    self.fix_frame_filename(fromFrame)),
+                "filename": self._dbgClient.absPath(self.fix_frame_filename(fromFrame)),
                 "linenumber": fromFrame.f_lineno,
                 "codename": fromFrame.f_code.co_name,
             }
             toInfo = {
-                "filename": self._dbgClient.absPath(
-                    self.fix_frame_filename(toFrame)),
+                "filename": self._dbgClient.absPath(self.fix_frame_filename(toFrame)),
                 "linenumber": toFrame.f_lineno,
                 "codename": toFrame.f_code.co_name,
             }
             self._dbgClient.sendCallTrace(event, fromInfo, toInfo)
-    
+
     def trace_dispatch(self, frame, event, arg):
         """
         Public method reimplemented from bdb.py to do some special things.
-        
+
         This specialty is to check the connection to the debug server
         for new events (i.e. new breakpoints) while we are going through
         the code.
-        
+
         @param frame The current stack frame
         @type frame object
         @param event The trace event
@@ -309,43 +307,42 @@
         if self.eventPollFlag:
             self._dbgClient.eventPoll()
             self.eventPollFlag = False
-            
+
             if self.quitting:
                 raise SystemExit
-        
-        if event == 'line':
+
+        if event == "line":
             if self.stop_here(frame) or self.break_here(frame):
                 if (
-                    self.stop_everywhere and
-                    frame.f_back and
-                    frame.f_back.f_code.co_name == "prepareJsonCommand"
+                    self.stop_everywhere
+                    and frame.f_back
+                    and frame.f_back.f_code.co_name == "prepareJsonCommand"
                 ):
                     # Just stepped into print statement, so skip these frames
                     self._set_stopinfo(None, frame.f_back)
                 else:
                     self.user_line(frame)
             return self.trace_dispatch
-        
-        if event == 'call':
+
+        if event == "call":
             if (
-                self.stop_here(frame) or
-                self.__checkBreakInFrame(frame) or
-                Watch.watches != []
+                self.stop_here(frame)
+                or self.__checkBreakInFrame(frame)
+                or Watch.watches != []
             ) or (
-                self.stopframe and
-                frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
+                self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
             ):
                 return self.trace_dispatch
             else:
                 # No need to trace this function
                 return None
-        
-        if event == 'return':
+
+        if event == "return":
             if self.stop_here(frame) or frame == self.returnframe:
                 # Ignore return events in generator except when stepping.
                 if (
-                    self.stopframe and
-                    frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
+                    self.stopframe
+                    and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
                 ):
                     return self.trace_dispatch
                 # Only true if we didn't stop in this frame, because it's
@@ -353,17 +350,17 @@
                 if self.stopframe is frame and self.stoplineno != -1:
                     self._set_stopinfo(None, frame.f_back)
             return None
-        
-        if event == 'exception':
+
+        if event == "exception":
             if not self.__skipFrame(frame):
                 # When stepping with next/until/return in a generator frame,
                 # skip the internal StopIteration exception (with no traceback)
                 # triggered by a subiterator run with the 'yield from'
                 # statement.
                 if not (
-                    frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS and
-                    arg[0] is StopIteration and
-                    arg[2] is None
+                    frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
+                    and arg[0] is StopIteration
+                    and arg[2] is None
                 ):
                     self.user_exception(arg)
             # Stop at the StopIteration or GeneratorExit exception when the
@@ -371,26 +368,26 @@
             # command, or a next/until command at the last statement in the
             # generator before the exception.
             elif (
-                self.stopframe and
-                frame is not self.stopframe and
-                (self.stopframe.f_code.co_flags &
-                 GENERATOR_AND_COROUTINE_FLAGS) and
-                arg[0] in (StopIteration, GeneratorExit)
+                self.stopframe
+                and frame is not self.stopframe
+                and (self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS)
+                and arg[0] in (StopIteration, GeneratorExit)
             ):
                 self.user_exception(arg)
             return None
 
-        if event == 'c_call':
+        if event == "c_call":
             return None
-        if event == 'c_exception':
+        if event == "c_exception":
             return None
-        if event == 'c_return':
+        if event == "c_return":
             return None
-        
-        print('DebugBase.trace_dispatch:'       # __IGNORE_WARNING_M801__
-              ' unknown debugging event: ',
-              repr(event))
-        
+
+        print(  # __IGNORE_WARNING_M801__
+            "DebugBase.trace_dispatch:" " unknown debugging event: ",
+            repr(event),
+        )
+
         return self.trace_dispatch
 
     def set_trace(self, frame=None):
@@ -400,35 +397,35 @@
         If frame is not specified, debugging starts from caller's frame.
         Because of jump optimizations it's not possible to use sys.breakpoint()
         as last instruction in a function or method.
-        
+
         @param frame frame to start debugging from
         @type frame object
         """
         if frame is None:
             frame = sys._getframe().f_back  # Skip set_trace method
-        
+
         stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__
-        
+
         frame.f_trace = self.trace_dispatch
         while frame.f_back is not None:
             # stop at eric's debugger frame or a threading bootstrap
             if frame.f_back.f_code == stopOnHandleCommand:
                 frame.f_trace = self.trace_dispatch
                 break
-            
+
             frame = frame.f_back
-        
+
         self.stop_everywhere = True
         sys.settrace(self.trace_dispatch)
         sys.setprofile(self._dbgClient.callTraceEnabled)
-    
+
     def bootstrap(self, target, args, kwargs):
         """
         Public method to bootstrap a thread.
-        
+
         It wraps the call to the user function to enable tracing
         before hand.
-        
+
         @param target function which is called in the new created thread
         @type function pointer
         @param args arguments to pass to target
@@ -440,7 +437,7 @@
             # Because in the initial run method the "base debug" function is
             # set up, it's also valid for the threads afterwards.
             sys.settrace(self.trace_dispatch)
-            
+
             target(*args, **kwargs)
         except Exception:
             excinfo = sys.exc_info()
@@ -448,12 +445,13 @@
         finally:
             sys.settrace(None)
             sys.setprofile(None)
-    
-    def run(self, cmd, globalsDict=None, localsDict=None, debug=True,
-            closeSession=True):
+
+    def run(
+        self, cmd, globalsDict=None, localsDict=None, debug=True, closeSession=True
+    ):
         """
         Public method to start a given command under debugger control.
-        
+
         @param cmd command / code to execute under debugger control
         @type str or CodeType
         @param globalsDict dictionary of global variables for cmd
@@ -470,23 +468,24 @@
         """
         if globalsDict is None:
             import __main__
+
             globalsDict = __main__.__dict__
-        
+
         if localsDict is None:
             localsDict = globalsDict
-        
+
         if not isinstance(cmd, types.CodeType):
             cmd = compile(cmd, "<string>", "exec")
-        
+
         if debug:
             # First time the trace_dispatch function is called, a "base debug"
             # function has to be returned, which is called at every user code
             # function call. This is ensured by setting stop_everywhere.
             self.stop_everywhere = True
             sys.settrace(self.trace_dispatch)
-        
+
         try:
-            exec(cmd, globalsDict, localsDict)      # secok
+            exec(cmd, globalsDict, localsDict)  # secok
             atexit._run_exitfuncs()
             self._dbgClient.progTerminated(0, closeSession=closeSession)
             exitcode = 0
@@ -494,8 +493,9 @@
             atexit._run_exitfuncs()
             excinfo = sys.exc_info()
             exitcode, message = self.__extractSystemExitMessage(excinfo)
-            self._dbgClient.progTerminated(exitcode, message=message,
-                                           closeSession=closeSession)
+            self._dbgClient.progTerminated(
+                exitcode, message=message, closeSession=closeSession
+            )
         except Exception:
             excinfo = sys.exc_info()
             self.user_exception(excinfo, True)
@@ -508,7 +508,7 @@
     def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
         """
         Protected method to update the frame pointers.
-        
+
         @param stopframe the frame object where to stop
         @type frame object
         @param returnframe the frame object where to stop on a function return
@@ -523,7 +523,7 @@
         # stoplineno >= 0 means: stop at line >= the stoplineno
         # stoplineno -1 means: don't stop at all
         self.stoplineno = stoplineno
-        
+
         if returnframe is not None:
             # Ensure to be able to stop on the return frame
             returnframe.f_trace = self.trace_dispatch
@@ -532,14 +532,14 @@
     def set_continue(self, special):
         """
         Public method to stop only on next breakpoint.
-        
+
         @param special flag indicating a special continue operation
         @type bool
         """
         # Here we only set a new stop frame if it is a normal continue.
         if not special:
             self._set_stopinfo(None, None, -1)
-        
+
         # Disable tracing if not started in debug mode
         if not self._dbgClient.debugging:
             sys.settrace(None)
@@ -549,7 +549,7 @@
         """
         Public method to stop when the line with the lineno greater than the
         current one is reached or when returning from current frame.
-        
+
         @param frame reference to the frame object
         @type frame object
         @param lineno line number to continue to
@@ -572,7 +572,7 @@
     def set_next(self, frame):
         """
         Public method to stop on the next line in or below the given frame.
-        
+
         @param frame the frame object
         @type frame object
         """
@@ -582,16 +582,16 @@
     def set_return(self, frame):
         """
         Public method to stop when returning from the given frame.
-        
+
         @param frame the frame object
         @type frame object
         """
         self._set_stopinfo(None, frame.f_back)
-    
+
     def move_instruction_pointer(self, lineno):
         """
         Public method to move the instruction pointer to another line.
-        
+
         @param lineno new line number
         @type int
         """
@@ -605,7 +605,7 @@
     def set_quit(self):
         """
         Public method to quit.
-        
+
         Disables the trace functions and resets all frame pointer.
         """
         sys.setprofile(None)
@@ -613,11 +613,11 @@
         self.returnframe = None
         for debugThread in self._dbgClient.threads.values():
             debugThread.quitting = True
-    
+
     def fix_frame_filename(self, frame):
         """
         Public method used to fixup the filename for a given frame.
-        
+
         The logic employed here is that if a module was loaded
         from a .pyc file, then the correct .py to operate with
         should be in the same path as the .pyc. The reason this
@@ -628,22 +628,22 @@
         this can break debugging as the .pyc will refer to the .py
         on the original machine. Another case might be sharing
         code over a network... This logic deals with that.
-        
+
         @param frame the frame object
         @type frame object
         @return fixed up file name
         @rtype str
         """
         # get module name from __file__
-        fn = frame.f_globals.get('__file__')
+        fn = frame.f_globals.get("__file__")
         try:
             return self._fnCache[fn]
         except KeyError:
             if fn is None:
                 return frame.f_code.co_filename
-            
+
             absFilename = os.path.abspath(fn)
-            if absFilename.endswith(('.pyc', '.pyo', '.pyd')):
+            if absFilename.endswith((".pyc", ".pyo", ".pyd")):
                 fixedName = absFilename[:-1]
                 if not os.path.exists(fixedName):
                     fixedName = absFilename
@@ -657,7 +657,7 @@
         """
         Private method to check if the function / method has a line number
         which is a breakpoint.
-        
+
         @param frame the frame object
         @type frame object
         @return Flag indicating a function / method with breakpoint
@@ -665,20 +665,20 @@
         """
         try:
             return Breakpoint.breakInFrameCache[
-                frame.f_globals.get('__file__'),
-                frame.f_code.co_firstlineno]
+                frame.f_globals.get("__file__"), frame.f_code.co_firstlineno
+            ]
         except KeyError:
             filename = self.fix_frame_filename(frame)
             if filename not in Breakpoint.breakInFile:
                 Breakpoint.breakInFrameCache[
-                    frame.f_globals.get('__file__'),
-                    frame.f_code.co_firstlineno] = False
+                    frame.f_globals.get("__file__"), frame.f_code.co_firstlineno
+                ] = False
                 return False
             lineNo = frame.f_code.co_firstlineno
             lineNumbers = [lineNo]
-            
+
             co_lnotab = frame.f_code.co_lnotab[1::2]
-            
+
             # No need to handle special case if a lot of lines between
             # (e.g. closure), because the additional lines won't cause a bp
             for co_lno in co_lnotab:
@@ -686,25 +686,25 @@
                     lineNo -= 0x100
                 lineNo += co_lno
                 lineNumbers.append(lineNo)
-            
+
             for bp in Breakpoint.breakInFile[filename]:
                 if bp in lineNumbers:
                     Breakpoint.breakInFrameCache[
-                        frame.f_globals.get('__file__'),
-                        frame.f_code.co_firstlineno] = True
+                        frame.f_globals.get("__file__"), frame.f_code.co_firstlineno
+                    ] = True
                     return True
             Breakpoint.breakInFrameCache[
-                frame.f_globals.get('__file__'),
-                frame.f_code.co_firstlineno] = False
+                frame.f_globals.get("__file__"), frame.f_code.co_firstlineno
+            ] = False
             return False
-    
+
     def break_here(self, frame):
         """
         Public method reimplemented from bdb.py to fix the filename from the
         frame.
-        
+
         See fix_frame_filename for more info.
-        
+
         @param frame the frame object
         @type frame object
         @return flag indicating the break status
@@ -712,14 +712,13 @@
         """
         filename = self.fix_frame_filename(frame)
         if (filename, frame.f_lineno) in Breakpoint.breaks:
-            bp, flag = Breakpoint.effectiveBreak(
-                filename, frame.f_lineno, frame)
+            bp, flag = Breakpoint.effectiveBreak(filename, frame.f_lineno, frame)
             if bp:
                 # flag says ok to delete temp. bp
                 if flag and bp.temporary:
                     self.__do_clearBreak(filename, frame.f_lineno)
                 return True
-        
+
         if Watch.watches != []:
             bp, flag = Watch.effectiveWatch(frame)
             if bp:
@@ -727,13 +726,13 @@
                 if flag and bp.temporary:
                     self.__do_clearWatch(bp.cond)
                 return True
-        
+
         return False
 
     def __do_clearBreak(self, filename, lineno):
         """
         Private method called to clear a temporary breakpoint.
-        
+
         @param filename name of the file the bp belongs to
         @type str
         @param lineno linenumber of the bp
@@ -745,7 +744,7 @@
     def __do_clearWatch(self, cond):
         """
         Private method called to clear a temporary watch expression.
-        
+
         @param cond expression of the watch expression to be cleared
         @type str
         """
@@ -755,7 +754,7 @@
     def getStack(self, frame=None, applyTrace=False):
         """
         Public method to get the stack.
-        
+
         @param frame frame object to inspect
         @type frame object or list
         @param applyTrace flag to assign trace function to fr.f_trace
@@ -770,7 +769,7 @@
             fr, tb_lineno = frame.pop(0)
         else:
             fr = frame
-        
+
         stack = []
         while fr is not None:
             if applyTrace:
@@ -780,34 +779,38 @@
                 # but we had disabled tracing along the way via a None
                 # return from dispatch_call
                 fr.f_trace = self.trace_dispatch
-            
+
             fname = self._dbgClient.absPath(self.fix_frame_filename(fr))
             # Always show at least one stack frame, even if it's from eric.
             if stack and os.path.basename(fname).startswith(
-                ("DebugBase.py", "DebugClientBase.py",
-                 "ThreadExtension.py", "threading.py")
+                (
+                    "DebugBase.py",
+                    "DebugClientBase.py",
+                    "ThreadExtension.py",
+                    "threading.py",
+                )
             ):
                 break
-            
+
             fline = tb_lineno or fr.f_lineno
             ffunc = fr.f_code.co_name
-            
-            if ffunc == '?':
-                ffunc = ''
-            
+
+            if ffunc == "?":
+                ffunc = ""
+
             if ffunc and not ffunc.startswith("<"):
                 argInfo = getargvalues(fr)
                 try:
                     fargs = formatargvalues(
-                        argInfo.args, argInfo.varargs,
-                        argInfo.keywords, argInfo.locals)
+                        argInfo.args, argInfo.varargs, argInfo.keywords, argInfo.locals
+                    )
                 except Exception:
                     fargs = ""
             else:
                 fargs = ""
-            
+
             stack.append([fname, fline, ffunc, fargs])
-            
+
             # is it a stack frame or exception list?
             if type(frame) == list:
                 if frame != []:
@@ -816,53 +819,53 @@
                     fr = None
             else:
                 fr = fr.f_back
-        
+
         return stack
-    
+
     def user_line(self, frame):
         """
         Public method reimplemented to handle the program about to execute a
         particular line.
-        
+
         @param frame the frame object
         """
         # We never stop on line 0.
         if frame.f_lineno == 0:
             return
-        
+
         self.isBroken = True
         self.currentFrame = frame
         stack = self.getStack(frame, applyTrace=True)
-        
+
         self._dbgClient.lockClient()
         self._dbgClient.currentThread = self
         self._dbgClient.currentThreadExec = self
-        
+
         self._dbgClient.sendResponseLine(stack, self.name)
         self._dbgClient.eventLoop()
-        
+
         self.isBroken = False
         self._dbgClient.unlockClient()
-        
+
         self._dbgClient.dumpThreadList()
-    
+
     def user_exception(self, excinfo, unhandled=False):
         """
         Public method reimplemented to report an exception to the debug server.
-        
+
         @param excinfo details about the exception
         @type tuple(Exception, excval object, traceback frame object)
         @param unhandled flag indicating an uncaught exception
         @type bool
         """
         exctype, excval, exctb = excinfo
-        
-        if ((exctype in [GeneratorExit, StopIteration] and
-             unhandled is False) or
-                exctype == SystemExit):
+
+        if (
+            exctype in [GeneratorExit, StopIteration] and unhandled is False
+        ) or exctype == SystemExit:
             # ignore these
             return
-        
+
         if exctype in [SyntaxError, IndentationError]:
             try:
                 if type(excval) == tuple:
@@ -873,90 +876,94 @@
                     filename = excval.filename
                     lineno = excval.lineno
                     charno = excval.offset
-                
+
                 if filename is None:
                     realSyntaxError = False
                 else:
                     if charno is None:
                         charno = 0
-                    
+
                     filename = os.path.abspath(filename)
                     realSyntaxError = os.path.exists(filename)
-                
+
             except (AttributeError, ValueError):
                 message = ""
                 filename = ""
                 lineno = 0
                 charno = 0
                 realSyntaxError = True
-            
+
             if realSyntaxError:
                 self._dbgClient.sendSyntaxError(
-                    message, filename, lineno, charno, self.name)
+                    message, filename, lineno, charno, self.name
+                )
                 self._dbgClient.eventLoop()
                 return
-        
+
         self.skipFrames = 0
-        if (exctype == RuntimeError and
-                str(excval).startswith('maximum recursion depth exceeded') or
-                exctype == RecursionError):  # __IGNORE_WARNING__
-            excval = 'maximum recursion depth exceeded'
+        if (
+            exctype == RuntimeError
+            and str(excval).startswith("maximum recursion depth exceeded")
+            or exctype == RecursionError
+        ):  # __IGNORE_WARNING__
+            excval = "maximum recursion depth exceeded"
             depth = 0
             tb = exctb
             while tb:
                 tb = tb.tb_next
-                
-                if (tb and tb.tb_frame.f_code.co_name == 'trace_dispatch' and
-                        __file__.startswith(tb.tb_frame.f_code.co_filename)):
+
+                if (
+                    tb
+                    and tb.tb_frame.f_code.co_name == "trace_dispatch"
+                    and __file__.startswith(tb.tb_frame.f_code.co_filename)
+                ):
                     depth = 1
                 self.skipFrames += depth
-            
+
             # always 1 if running without debugger
             self.skipFrames = max(1, self.skipFrames)
-        
+
         exctype = self.__extractExceptionName(exctype)
-        
+
         if excval is None:
-            excval = ''
-        
+            excval = ""
+
         exctypetxt = (
-            "unhandled {0!s}".format(str(exctype))
-            if unhandled else
-            str(exctype)
+            "unhandled {0!s}".format(str(exctype)) if unhandled else str(exctype)
         )
         excvaltxt = str(excval)
-        
+
         # Don't step into libraries, which are used by our debugger methods
         if exctb is not None:
             self.stop_everywhere = False
-        
+
         self.isBroken = True
         self.isException = True
-        
+
         disassembly = None
         stack = []
         if exctb:
             frlist = self.__extract_stack(exctb)
             frlist.reverse()
             disassembly = self.__disassemble(frlist[0][0])
-            
+
             self.currentFrame = frlist[0][0]
-            stack = self.getStack(frlist[self.skipFrames:])
-        
+            stack = self.getStack(frlist[self.skipFrames :])
+
         self._dbgClient.lockClient()
         self._dbgClient.currentThread = self
         self._dbgClient.currentThreadExec = self
         self._dbgClient.sendException(exctypetxt, excvaltxt, stack, self.name)
         self._dbgClient.setDisassembly(disassembly)
         self._dbgClient.dumpThreadList()
-        
+
         if exctb is not None:
             # When polling kept enabled, it isn't possible to resume after an
             # unhandled exception without further user interaction.
             self._dbgClient.eventLoop(True)
-        
+
         self.skipFrames = 0
-        
+
         self.isBroken = False
         self.isException = False
         stop_everywhere = self.stop_everywhere
@@ -964,23 +971,23 @@
         self.eventPollFlag = False
         self._dbgClient.unlockClient()
         self.stop_everywhere = stop_everywhere
-        
+
         self._dbgClient.dumpThreadList()
-    
+
     def __extractExceptionName(self, exctype):
         """
         Private method to extract the exception name given the exception
         type object.
-        
+
         @param exctype type of the exception
         @return exception name (string)
         """
         return str(exctype).replace("<class '", "").replace("'>", "")
-    
+
     def __extract_stack(self, exctb):
         """
         Private member to return a list of stack frames.
-        
+
         @param exctb exception traceback
         @return list of stack frames
         """
@@ -995,7 +1002,7 @@
     def __disassemble(self, frame):
         """
         Private method to generate a disassembly of the given code object.
-        
+
         @param frame frame object to be disassembled
         @type code
         @return dictionary containing the disassembly information
@@ -1007,12 +1014,11 @@
             "firstlineno": co.co_firstlineno,
             "instructions": [],
         }
-        
+
         # 1. disassembly info
         for instr in dis.get_instructions(co):
             instrDict = {
-                "lineno":
-                    0 if instr.starts_line is None else instr.starts_line,
+                "lineno": 0 if instr.starts_line is None else instr.starts_line,
                 "isJumpTarget": instr.is_jump_target,
                 "offset": instr.offset,
                 "opname": instr.opname,
@@ -1020,7 +1026,7 @@
                 "argrepr": instr.argrepr,
             }
             disDict["instructions"].append(instrDict)
-        
+
         # 2. code info
         # Note: keep in sync with PythonDisViewer.__createCodeInfo()
         disDict["codeinfo"] = {
@@ -1043,13 +1049,13 @@
         except AttributeError:
             # does not exist prior to 3.8.0
             disDict["codeinfo"]["posonlyargcount"] = 0
-        
+
         return disDict
-    
+
     def __extractSystemExitMessage(self, excinfo):
         """
         Private method to get the SystemExit code and message.
-        
+
         @param excinfo details about the SystemExit exception
         @type tuple(Exception, excval object, traceback frame object)
         @return SystemExit code and message
@@ -1088,16 +1094,16 @@
         else:
             exitcode = 1
             message = str(excval)
-        
+
         return exitcode, message
-    
+
     def stop_here(self, frame):
         """
         Public method reimplemented to filter out debugger files.
-        
+
         Tracing is turned off for files that are part of the
         debugger that are called from the application being debugged.
-        
+
         @param frame the frame object
         @type frame object
         @return flag indicating whether the debugger should stop here
@@ -1105,7 +1111,7 @@
         """
         if self.__skipFrame(frame):
             return False
-        
+
         if frame is self.stopframe:
             if self.stoplineno == -1:
                 return False
@@ -1115,30 +1121,37 @@
     def tracePythonLibs(self, enable):
         """
         Public method to update the settings to trace into Python libraries.
-        
+
         @param enable flag to debug into Python libraries
         @type bool
         """
         pathsToSkip = list(self.pathsToSkip)
         # don't trace into Python library?
         if enable:
-            pathsToSkip = [x for x in pathsToSkip if not x.endswith(
-                ("site-packages", "dist-packages", self.lib))]
+            pathsToSkip = [
+                x
+                for x in pathsToSkip
+                if not x.endswith(("site-packages", "dist-packages", self.lib))
+            ]
         else:
             pathsToSkip.append(self.lib)
-            localLib = [x for x in sys.path if x.endswith(("site-packages",
-                        "dist-packages")) and not x.startswith(self.lib)]
+            localLib = [
+                x
+                for x in sys.path
+                if x.endswith(("site-packages", "dist-packages"))
+                and not x.startswith(self.lib)
+            ]
             pathsToSkip.extend(localLib)
-        
+
         self.pathsToSkip = tuple(set(pathsToSkip))
 
     def __skipFrame(self, frame):
         """
         Private method to filter out debugger files.
-        
+
         Tracing is turned off for files that are part of the
         debugger that are called from the application being debugged.
-        
+
         @param frame the frame object
         @type frame object
         @return flag indicating whether the debugger should skip this frame

eric ide

mercurial