Continued with the multiprocess debugger. multi_processing

Thu, 13 Feb 2020 19:27:10 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 13 Feb 2020 19:27:10 +0100
branch
multi_processing
changeset 7411
6d8dcb3551b3
parent 7410
401791e6f50f
child 7412
0a995393d2ba

Continued with the multiprocess debugger.

eric6/DebugClients/Python/DebugClientBase.py file | annotate | diff | comparison | revisions
eric6/DebugClients/Python/QProcessExtension.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugServer.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugUI.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebugViewer.py file | annotate | diff | comparison | revisions
eric6/Debugger/DebuggerInterfacePython.py file | annotate | diff | comparison | revisions
eric6/Debugger/StartDebugDialog.ui file | annotate | diff | comparison | revisions
eric6/Debugger/StartDialog.py file | annotate | diff | comparison | revisions
--- a/eric6/DebugClients/Python/DebugClientBase.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/DebugClients/Python/DebugClientBase.py	Thu Feb 13 19:27:10 2020 +0100
@@ -232,6 +232,7 @@
         self.test = None
         self.debugging = False
         self.multiprocessSupport = False
+        self.noDebugList = []
         
         self.fork_auto = False
         self.fork_child = False
@@ -329,6 +330,7 @@
 
         self.debugging = False
         self.multiprocessSupport = False
+        self.noDebugList = []
         
         # make sure we close down our end of the socket
         # might be overkill as normally stdin, stdout and stderr
@@ -836,6 +838,9 @@
         elif method == "RequestShutdown":
             self.sessionClose()
         
+        elif method == "RequestSetNoDebugList":
+            self.noDebugList = params["noDebug"][:]
+        
         elif method == "RequestCompletion":
             self.__completionList(params["text"])
         
--- a/eric6/DebugClients/Python/QProcessExtension.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/DebugClients/Python/QProcessExtension.py	Thu Feb 13 19:27:10 2020 +0100
@@ -13,7 +13,6 @@
 _debugClient = None
 
 
-# TODO: extend this with first line logic
 def _isPythonProgram(program, arguments):
     """
     Protected function to check, if program is a Python interpreter and
@@ -28,7 +27,10 @@
     @rtype tuple of (bool, tuple of (str, list of str))
     """
     prog = program.lower()
-    ok = "python" in prog and arguments[0] != '-m'
+    ok = (
+        ("python" in prog and arguments[0] != '-m') or
+        "pypy" in prog
+    )
     return ok, (program, arguments[:])
 
 
@@ -132,7 +134,12 @@
                     else:
                         mode = module.QIODevice.ReadWrite
                 ok, (program, arguments) = _isPythonProgram(program, arguments)
-                if ok:
+                if (
+                    ok and (
+                        not os.path.basename(arguments[0])
+                        in _debugClient.noDebugList
+                    )
+                ):
                     newArgs = self.modifyArgs(
                         arguments, _debugClient.multiprocessSupport)
                     super(QProcessWrapper, self).start(program, newArgs, mode)
--- a/eric6/Debugger/DebugServer.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/DebugServer.py	Thu Feb 13 19:27:10 2020 +0100
@@ -262,6 +262,8 @@
         
         self.__maxVariableSize = Preferences.getDebugger("MaxVariableSize")
         
+        self.__multiprocessNoDebugList = []
+        
         self.__registerDebuggerInterfaces()
     
     def getHostAddress(self, localhost):
@@ -927,7 +929,7 @@
                    tracePython=False, autoContinue=True, forProject=False,
                    runInConsole=False, autoFork=False, forkChild=False,
                    clientType="", enableCallTrace=False,
-                   enableMultiprocess=False):
+                   enableMultiprocess=False, multiprocessNoDebug=""):
         """
         Public method to load a new program to debug.
         
@@ -967,8 +969,12 @@
         @param enableMultiprocess flag indicating to perform multiprocess
             debugging
         @type bool
+        @param multiprocessNoDebug space separated list of programs not to be
+            debugged
+        @type str
         """
         self.__autoClearShell = autoClearShell
+        self.__multiprocessNoDebugList = multiprocessNoDebug.split()
         
         if clientType not in self.getSupportedLanguages():
             # a not supported client language was requested
@@ -1004,6 +1010,7 @@
         self.running = True
         self.__restoreBreakpoints()
         self.__restoreWatchpoints()
+        self.__restoreNoDebugList()
     
     def remoteRun(self, venvName, fn, argv, wd, env, autoClearShell=True,
                   forProject=False, runInConsole=False, autoFork=False,
@@ -2197,3 +2204,16 @@
         """
         self.__restoreBreakpoints(debuggerId)
         self.__restoreWatchpoints(debuggerId)
+        self.__restoreNoDebugList(debuggerId)
+    
+    def __restoreNoDebugList(self, debuggerId=""):
+        """
+        Private method to restore the watch expressions after a restart.
+        
+        @param debuggerId ID of the debugger backend to send to. If this is
+            empty, they will be broadcast to all connected backends.
+        @type str
+        """
+        if self.debugging:
+            self.debuggerInterface.remoteNoDebugList(
+                debuggerId, self.__multiprocessNoDebugList)
--- a/eric6/Debugger/DebugUI.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/DebugUI.py	Thu Feb 13 19:27:10 2020 +0100
@@ -111,6 +111,9 @@
         self.enableMultiprocess = Preferences.toBool(
             Preferences.Prefs.settings.value(
                 'DebugInfo/EnableMultiprocess', False))
+        self.multiprocessNoDebugHistory = Preferences.toList(
+            Preferences.Prefs.settings.value(
+                'DebugInfo/MultiprocessNoDebugHistory'))
         
         self.lastDebuggedFile = None
         self.lastStartAction = 0    # 0=None, 1=Script, 2=Project
@@ -918,6 +921,7 @@
         self.argvHistory = []
         self.wdHistory = []
         self.envHistory = []
+        self.multiprocessNoDebugHistory = []
         
         Preferences.Prefs.settings.setValue(
             'DebugInfo/ArgumentsHistory', self.argvHistory)
@@ -925,6 +929,9 @@
             'DebugInfo/WorkingDirectoryHistory', self.wdHistory)
         Preferences.Prefs.settings.setValue(
             'DebugInfo/EnvironmentHistory', self.envHistory)
+        Preferences.Prefs.settings.setValue(
+            'DebugInfo/MultiprocessNoDebugHistory',
+            self.multiprocessNoDebugHistory)
         
     def shutdown(self):
         """
@@ -961,6 +968,9 @@
             'DebugInfo/ForkIntoChild', self.forkIntoChild)
         Preferences.Prefs.settings.setValue(
             'DebugInfo/EnableMultiprocess', self.enableMultiprocess)
+        Preferences.Prefs.settings.setValue(
+            'DebugInfo/MultiprocessNoDebugHistory',
+            self.multiprocessNoDebugHistory)
         
     def shutdownServer(self):
         """
@@ -1246,11 +1256,11 @@
         
         if self.lastAction != -1:
             if self.lastAction == 2:
-                self.__specialContinue()
+                self.__specialContinue(debuggerId)
             else:
-                self.debugActions[self.lastAction]()
+                self.debugActions[self.lastAction](debuggerId)
         else:
-            self.__continue()
+            self.__continue(debuggerId)
         
     def __clientSignal(self, message, filename, lineNo, funcName, funcArgs,
                        debuggerId):
@@ -1717,8 +1727,9 @@
             self.setArgvHistory("", clearHistories=True)
             self.setWdHistory("", clearHistories=True)
             self.setEnvHistory("", clearHistories=True)
+            self.setMultiprocessNoDebugHistory("", clearHistories=True)
         elif dlg.historiesModified():
-            argvHistory, wdHistory, envHistory = dlg.getHistories()
+            argvHistory, wdHistory, envHistory, _ = dlg.getHistories()
             self.setArgvHistory("", history=argvHistory)
             self.setWdHistory("", history=wdHistory)
             self.setEnvHistory("", history=envHistory)
@@ -1852,8 +1863,9 @@
             self.setArgvHistory("", clearHistories=True)
             self.setWdHistory("", clearHistories=True)
             self.setEnvHistory("", clearHistories=True)
+            self.setMultiprocessNoDebugHistory("", clearHistories=True)
         elif dlg.historiesModified():
-            argvHistory, wdHistory, envHistory = dlg.getHistories()
+            argvHistory, wdHistory, envHistory, _ = dlg.getHistories()
             self.setArgvHistory("", history=argvHistory)
             self.setWdHistory("", history=wdHistory)
             self.setEnvHistory("", history=envHistory)
@@ -1991,8 +2003,9 @@
             self.setArgvHistory("", clearHistories=True)
             self.setWdHistory("", clearHistories=True)
             self.setEnvHistory("", clearHistories=True)
+            self.setMultiprocessNoDebugHistory("", clearHistories=True)
         elif dlg.historiesModified():
-            argvHistory, wdHistory, envHistory = dlg.getHistories()
+            argvHistory, wdHistory, envHistory, _ = dlg.getHistories()
             self.setArgvHistory("", history=argvHistory)
             self.setWdHistory("", history=wdHistory)
             self.setEnvHistory("", history=envHistory)
@@ -2034,12 +2047,14 @@
             tracePython=self.tracePython, autoClearShell=self.autoClearShell,
             autoContinue=self.autoContinue, autoFork=self.forkAutomatically,
             forkChild=self.forkIntoChild,
-            enableMultiprocess=self.enableMultiprocess)
+            enableMultiprocess=self.enableMultiprocess,
+            multiprocessNoDebugHistory=self.multiprocessNoDebugHistory)
         if dlg.exec_() == QDialog.Accepted:
             (lastUsedVenvName, argv, wd, env, exceptions, clearShell,
              console) = dlg.getData()
             (tracePython, autoContinue, forkAutomatically, forkIntoChild,
-             enableMultiprocess) = dlg.getDebugData()
+             enableMultiprocess, multiprocessNoDebug,
+             ) = dlg.getDebugData()
             
             if debugProject:
                 fn = self.project.getMainScript(True)
@@ -2114,8 +2129,9 @@
             self.forkAutomatically = forkAutomatically
             self.forkIntoChild = forkIntoChild
             
-            # Save the multiprocess debugging flag
+            # Save the multiprocess debugging data
             self.enableMultiprocess = enableMultiprocess
+            self.setMultiprocessNoDebugHistory(multiprocessNoDebug)
             
             # Hide all error highlights
             self.viewmanager.unhighlight()
@@ -2143,7 +2159,8 @@
                     runInConsole=console, autoFork=forkAutomatically,
                     forkChild=forkIntoChild, clientType=self.clientType,
                     enableCallTrace=enableCallTrace,
-                    enableMultiprocess=enableMultiprocess)
+                    enableMultiprocess=enableMultiprocess,
+                    multiprocessNoDebug=multiprocessNoDebug)
                 
                 if (
                     self.debugServer.isClientProcessUp() and
@@ -2158,11 +2175,14 @@
             self.setArgvHistory("", clearHistories=True)
             self.setWdHistory("", clearHistories=True)
             self.setEnvHistory("", clearHistories=True)
+            self.setMultiprocessNoDebugHistory("", clearHistories=True)
         elif dlg.historiesModified():
-            argvHistory, wdHistory, envHistory = dlg.getHistories()
+            (argvHistory, wdHistory, envHistory,
+             noDebugHistory) = dlg.getHistories()
             self.setArgvHistory("", history=argvHistory)
             self.setWdHistory("", history=wdHistory)
             self.setEnvHistory("", history=envHistory)
+            self.setMultiprocessNoDebugHistory("", history=noDebugHistory)
     
     def __doRestart(self):
         """
@@ -2216,6 +2236,7 @@
                 enableCallTrace = self.debugViewer.isCallTraceEnabled()
                 self.debugViewer.clearCallTrace()
                 self.debugViewer.setCallTraceToProjectMode(forProject)
+                multiprocessNoDebug = self.multiprocessNoDebugHistory[0]
                 
                 # Ask the client to debug the new program.
                 self.debugServer.remoteLoad(
@@ -2229,7 +2250,8 @@
                     forkChild=self.forkIntoChild,
                     clientType=self.clientType,
                     enableCallTrace=enableCallTrace,
-                    enableMultiprocess=self.enableMultiprocess)
+                    enableMultiprocess=self.enableMultiprocess,
+                    multiprocessNoDebug=multiprocessNoDebug)
                 
                 # Signal that we have started a debugging session
                 self.debuggingStarted.emit(fn)
@@ -2295,59 +2317,101 @@
         # Initialize the call stack viewer
         self.debugViewer.initCallStackViewer(False)
         
-    def __continue(self):
+    def __continue(self, debuggerId=""):
         """
         Private method to handle the Continue action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 0
         self.__enterRemote()
-        self.debugServer.remoteContinue(self.getSelectedDebuggerId())
+        self.debugServer.remoteContinue(debuggerId)
 
-    def __specialContinue(self):
+    def __specialContinue(self, debuggerId=""):
         """
         Private method to handle the Special Continue action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 2
         self.__enterRemote()
-        self.debugServer.remoteContinue(self.getSelectedDebuggerId(), 1)
+        self.debugServer.remoteContinue(debuggerId, 1)
 
-    def __step(self):
+    def __step(self, debuggerId=""):
         """
         Private method to handle the Step action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 1
         self.__enterRemote()
-        self.debugServer.remoteStep(self.getSelectedDebuggerId())
+        self.debugServer.remoteStep(debuggerId)
 
-    def __stepOver(self):
+    def __stepOver(self, debuggerId=""):
         """
         Private method to handle the Step Over action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 2
         self.__enterRemote()
-        self.debugServer.remoteStepOver(self.getSelectedDebuggerId())
+        self.debugServer.remoteStepOver(debuggerId)
 
-    def __stepOut(self):
+    def __stepOut(self, debuggerId=""):
         """
         Private method to handle the Step Out action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 3
         self.__enterRemote()
-        self.debugServer.remoteStepOut(self.getSelectedDebuggerId())
+        self.debugServer.remoteStepOut(debuggerId)
 
-    def __stepQuit(self):
+    def __stepQuit(self, debuggerId=""):
         """
         Private method to handle the Step Quit action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 4
         self.__enterRemote()
-        self.debugServer.remoteStepQuit(self.getSelectedDebuggerId())
+        self.debugServer.remoteStepQuit(debuggerId)
         self.__resetUI()
 
-    def __runToCursor(self):
+    def __runToCursor(self, debuggerId=""):
         """
         Private method to handle the Run to Cursor action.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 0
         aw = self.viewmanager.activeWindow()
         line = aw.getCursorPosition()[0] + 1
@@ -2355,16 +2419,22 @@
         self.debugServer.remoteBreakpoint(
             self.getSelectedDebuggerId(),
             aw.getFileName(), line, 1, None, 1)
-        self.debugServer.remoteContinue(self.getSelectedDebuggerId())
+        self.debugServer.remoteContinue(debuggerId)
 
-    def __moveInstructionPointer(self):
+    def __moveInstructionPointer(self, debuggerId=""):
         """
         Private method to move the instruction pointer to a different line.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
         """
+        if not debuggerId:
+            debuggerId = self.getSelectedDebuggerId()
+        
         self.lastAction = 0
         aw = self.viewmanager.activeWindow()
         line = aw.getCursorPosition()[0] + 1
-        self.debugServer.remoteMoveIP(self.getSelectedDebuggerId(), line)
+        self.debugServer.remoteMoveIP(debuggerId, line)
 
     def __enterRemote(self):
         """
@@ -2415,3 +2485,25 @@
         @type bool
         """
         self.debugActGrp.setEnabled(enable)
+
+    def setMultiprocessNoDebugHistory(self, noDebugList, clearHistories=False,
+                                      history=None):
+        """
+        Public slot to initialize the no debug list history.
+        
+        @param noDebugList whitespace separated list of progframs not to be
+            debugged
+        @type str
+        @param clearHistories flag indicating, that the list should be cleared
+        @type bool
+        @param history list of history entries to be set
+        @type list of str
+        """
+        if clearHistories:
+            del self.multiprocessNoDebugHistory[1:]
+        elif history is not None:
+            self.multiprocessNoDebugHistory = history[:]
+        else:
+            if noDebugList in self.multiprocessNoDebugHistory:
+                self.multiprocessNoDebugHistory.remove(noDebugList)
+            self.multiprocessNoDebugHistory.insert(0, noDebugList)
--- a/eric6/Debugger/DebugViewer.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/DebugViewer.py	Thu Feb 13 19:27:10 2020 +0100
@@ -452,7 +452,6 @@
         @param debuggerId ID of the debugger backend
         @type str
         """
-        self.__setDebuggerIconAndState(debuggerId, "exit", "exited")
         if debuggerId == self.getSelectedDebuggerId():
             # the current client has exited
             self.globalsViewer.handleResetUI()
@@ -463,6 +462,8 @@
             self.currentStack = None
             self.stackComboBox.clear()
             self.__threadList.clear()
+        index = self.__debuggersCombo.findText(debuggerId, Qt.MatchExactly)
+        self.__debuggersCombo.removeItem(index)
     
     def __clientSyntaxError(self, message, filename, lineNo, characterNo,
                             debuggerId):
@@ -637,9 +638,6 @@
                 elif thread['broken']:
                     if debugStatus < 1:
                         debugStatus = 0
-        if not threadList:
-            # empty threadlist means 'exited'
-            debugStatus = 2
         
         if debugStatus == -1:
             icon = "mediaPlaybackStart"
@@ -647,12 +645,9 @@
         elif debugStatus == 0:
             icon = "break"
             state = "broken"
-        elif debugStatus == 1:
+        else:
             icon = "exceptions"
             state = "exception"
-        else:
-            icon = "exit"
-            state = "exited"
         self.__setDebuggerIconAndState("", icon, state)
     
     def __threadSelected(self, current, previous):
@@ -729,7 +724,7 @@
         """
         Public method to get the currently selected debugger's state.
         
-        @return selected debugger's state (broken, exception, exited, running)
+        @return selected debugger's state (broken, exception, running)
         @rtype str
         """
         return self.__debuggersCombo.currentData()
@@ -743,7 +738,7 @@
         @type str
         @param iconName name of the icon to be used
         @type str
-        @param state state of the debugger (broken, exception, exited, running)
+        @param state state of the debugger (broken, exception, running)
         @type str
         """
         if debuggerId:
--- a/eric6/Debugger/DebuggerInterfacePython.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/DebuggerInterfacePython.py	Thu Feb 13 19:27:10 2020 +0100
@@ -1131,6 +1131,22 @@
             "enable": on,
         }, debuggerId)
     
+    def remoteNoDebugList(self, debuggerId, noDebugList):
+        """
+        Public method to set a list of programs not to be debugged.
+        
+        The programs given in the list will not be run under the control
+        of the multi process debugger.
+        
+        @param debuggerId ID of the debugger backend
+        @type str
+        @param noDebugList list of Python programs not to be debugged
+        @type list of str
+        """
+        self.__sendJsonCommand("RequestSetNoDebugList", {
+            "noDebug": noDebugList,
+        }, debuggerId)
+    
     def remoteBanner(self):
         """
         Public slot to get the banner info of the remote client.
--- a/eric6/Debugger/StartDebugDialog.ui	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/StartDebugDialog.ui	Thu Feb 13 19:27:10 2020 +0100
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>550</width>
-    <height>333</height>
+    <height>332</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -158,56 +158,6 @@
    </item>
    <item>
     <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QCheckBox" name="exceptionCheckBox">
-       <property name="toolTip">
-        <string>Uncheck to disable exception reporting</string>
-       </property>
-       <property name="whatsThis">
-        <string>&lt;b&gt;Report exceptions&lt;/b&gt;
-&lt;p&gt;Uncheck this in order to disable exception reporting.&lt;/p&gt;</string>
-       </property>
-       <property name="text">
-        <string>Report exceptions</string>
-       </property>
-       <property name="shortcut">
-        <string>Alt+E</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QCheckBox" name="clearShellCheckBox">
-       <property name="toolTip">
-        <string>Select to clear the display of the interpreter window</string>
-       </property>
-       <property name="whatsThis">
-        <string>&lt;b&gt;Clear interpreter window&lt;/b&gt;&lt;p&gt;This clears the display of the interpreter window before starting the debug client.&lt;/p&gt;</string>
-       </property>
-       <property name="text">
-        <string>Clear interpreter window</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QCheckBox" name="consoleCheckBox">
-       <property name="toolTip">
-        <string>Select to start the debugger in a console window</string>
-       </property>
-       <property name="whatsThis">
-        <string>&lt;b&gt;Start in console&lt;/b&gt;
-&lt;p&gt;Select to start the debugger in a console window. The console command has to be configured on the Debugger-&amp;gt;General page&lt;/p&gt;</string>
-       </property>
-       <property name="text">
-        <string>Start in console</string>
-       </property>
-      </widget>
-     </item>
      <item row="2" column="0">
       <widget class="QCheckBox" name="tracePythonCheckBox">
        <property name="toolTip">
@@ -237,22 +187,115 @@
        </property>
       </widget>
      </item>
-     <item row="3" column="0">
-      <widget class="QCheckBox" name="multiprocessEnableCheckBox">
+     <item row="0" column="1">
+      <widget class="QCheckBox" name="clearShellCheckBox">
        <property name="toolTip">
-        <string>Select this enable multi process debugging.</string>
+        <string>Select to clear the display of the interpreter window</string>
+       </property>
+       <property name="whatsThis">
+        <string>&lt;b&gt;Clear interpreter window&lt;/b&gt;&lt;p&gt;This clears the display of the interpreter window before starting the debug client.&lt;/p&gt;</string>
+       </property>
+       <property name="text">
+        <string>Clear interpreter window</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QCheckBox" name="exceptionCheckBox">
+       <property name="toolTip">
+        <string>Uncheck to disable exception reporting</string>
        </property>
        <property name="whatsThis">
-        <string>&lt;b&gt;Enable Multi Process Debugging&lt;/b&gt;&lt;p&gt;This enables debugging capability for multi process programs. Each started Python program is started within a new debugger.&lt;/p&gt;</string>
+        <string>&lt;b&gt;Report exceptions&lt;/b&gt;
+&lt;p&gt;Uncheck this in order to disable exception reporting.&lt;/p&gt;</string>
        </property>
        <property name="text">
-        <string>Enable Multi Process Debugging</string>
+        <string>Report exceptions</string>
+       </property>
+       <property name="shortcut">
+        <string>Alt+E</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QCheckBox" name="consoleCheckBox">
+       <property name="toolTip">
+        <string>Select to start the debugger in a console window</string>
+       </property>
+       <property name="whatsThis">
+        <string>&lt;b&gt;Start in console&lt;/b&gt;
+&lt;p&gt;Select to start the debugger in a console window. The console command has to be configured on the Debugger-&amp;gt;General page&lt;/p&gt;</string>
+       </property>
+       <property name="text">
+        <string>Start in console</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
+    <widget class="QGroupBox" name="multiprocessGroup">
+     <property name="toolTip">
+      <string>Select this to enable multi process debugging.</string>
+     </property>
+     <property name="whatsThis">
+      <string>&lt;b&gt;Multi Process Debugging&lt;/b&gt;&lt;p&gt;This enables debugging capability for multi process programs. Each started Python program is started within a new debugger.&lt;/p&gt;</string>
+     </property>
+     <property name="title">
+      <string>Multi Process Debugging</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="TextLabel1_2">
+        <property name="text">
+         <string>Don't Debug:</string>
+        </property>
+        <property name="buddy">
+         <cstring>cmdlineCombo</cstring>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="multiprocessNoDebugCombo">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Enter the list of programs not to be debugged separated by space</string>
+        </property>
+        <property name="whatsThis">
+         <string/>
+        </property>
+        <property name="editable">
+         <bool>true</bool>
+        </property>
+        <property name="insertPolicy">
+         <enum>QComboBox::InsertAtTop</enum>
+        </property>
+        <property name="sizeAdjustPolicy">
+         <enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
+        </property>
+        <property name="duplicatesEnabled">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
       <string>Forking</string>
@@ -323,7 +366,8 @@
   <tabstop>consoleCheckBox</tabstop>
   <tabstop>tracePythonCheckBox</tabstop>
   <tabstop>autoContinueCheckBox</tabstop>
-  <tabstop>multiprocessEnableCheckBox</tabstop>
+  <tabstop>multiprocessGroup</tabstop>
+  <tabstop>multiprocessNoDebugCombo</tabstop>
   <tabstop>forkModeCheckBox</tabstop>
   <tabstop>forkChildCheckBox</tabstop>
  </tabstops>
--- a/eric6/Debugger/StartDialog.py	Wed Feb 12 20:04:31 2020 +0100
+++ b/eric6/Debugger/StartDialog.py	Thu Feb 13 19:27:10 2020 +0100
@@ -29,7 +29,8 @@
                  exceptions,
                  parent=None, dialogType=0, modfuncList=None,
                  tracePython=False, autoClearShell=True, autoContinue=True,
-                 autoFork=False, forkChild=False, enableMultiprocess=False):
+                 autoFork=False, forkChild=False, enableMultiprocess=False,
+                 multiprocessNoDebugHistory=None):
         """
         Constructor
         
@@ -74,6 +75,9 @@
         @param enableMultiprocess flag indicating the support for multi process
             debugging
         @type bool
+        @param multiprocessNoDebugHistory list of lists with programs not to be
+            debugged
+        @type list of str
         """
         super(StartDialog, self).__init__(parent)
         self.setModal(True)
@@ -135,7 +139,12 @@
             self.ui.autoContinueCheckBox.setChecked(autoContinue)
             self.ui.forkModeCheckBox.setChecked(autoFork)
             self.ui.forkChildCheckBox.setChecked(forkChild)
-            self.ui.multiprocessEnableCheckBox.setChecked(enableMultiprocess)
+            self.ui.multiprocessGroup.setChecked(enableMultiprocess)
+            self.ui.multiprocessNoDebugCombo.clear()
+            if multiprocessNoDebugHistory:
+                self.ui.multiprocessNoDebugCombo.addItems(
+                    multiprocessNoDebugHistory)
+                self.ui.multiprocessNoDebugCombo.setCurrentIndex(0)
         
         if dialogType == 1:       # start run dialog
             self.ui.forkModeCheckBox.setChecked(autoFork)
@@ -186,19 +195,22 @@
         
         @return a tuple of a flag indicating, if the Python library should be
             traced as well, a flag indicating, that the debugger should not
-            stop at the first executable line (boolean), a flag indicating,
-            that the debugger should fork automatically (boolean) and a flag
-            indicating, that the debugger should debug the child process after
-            forking automatically (boolean)
+            stop at the first executable line, a flag indicating, that the
+            debugger should fork automatically, a flag indicating, that the
+            debugger should debug the child process after forking
+            automatically, a flag indicating to support multi process debugging
+            and a space separated list of programs not to be debugged
+        @rtype tuple of (bool, bool, bool, bool, bool, str)
         """
         if self.dialogType == 0:
             return (self.ui.tracePythonCheckBox.isChecked(),
                     self.ui.autoContinueCheckBox.isChecked(),
                     self.ui.forkModeCheckBox.isChecked(),
                     self.ui.forkChildCheckBox.isChecked(),
-                    self.ui.multiprocessEnableCheckBox.isChecked())
+                    self.ui.multiprocessGroup.isChecked(),
+                    self.ui.multiprocessNoDebugCombo.currentText())
         else:
-            return (False, False, False, False, False)
+            return (False, False, False, False, False, [])
         
     def getRunData(self):
         """
@@ -259,6 +271,11 @@
         self.ui.cmdlineCombo.addItem(cmdLine)
         self.ui.workdirPicker.addItem(workdir)
         self.ui.environmentCombo.addItem(environment)
+        
+        if self.dialogType == 0:
+            noDebugList = self.ui.multiprocessNoDebugCombo.currentText()
+            self.ui.multiprocessNoDebugCombo.clear()
+            self.ui.multiprocessNoDebugCombo.addItem(noDebugList)
     
     def __editHistory(self):
         """
@@ -270,6 +287,15 @@
             self.tr("Working Directory"),
             self.tr("Environment"),
         ]
+        combos = [
+            None,
+            self.ui.cmdlineCombo,
+            self.ui.workdirPicker,
+            self.ui.environmentCombo,
+        ]
+        if self.dialogType == 0:
+            histories.append(self.tr("No Debug Programs"))
+            combos.append(self.ui.multiprocessNoDebugCombo)
         historyKind, ok = QInputDialog.getItem(
             self,
             self.tr("Edit History"),
@@ -277,32 +303,27 @@
             histories,
             0, False)
         if ok and historyKind:
+            history = []
             historiesIndex = histories.index(historyKind)
             if historiesIndex == 2:
                 history = self.ui.workdirPicker.getPathItems()
             else:
-                history = []
-                if historiesIndex == 1:
-                    combo = self.ui.cmdlineCombo
-                else:
-                    combo = self.ui.environmentCombo
-                for index in range(combo.count()):
-                    history.append(combo.itemText(index))
+                combo = combos[historiesIndex]
+                if combo:
+                    for index in range(combo.count()):
+                        history.append(combo.itemText(index))
             
-            from .StartHistoryEditDialog import StartHistoryEditDialog
-            dlg = StartHistoryEditDialog(history, self)
-            if dlg.exec_() == QDialog.Accepted:
-                history = dlg.getHistory()
-                if historiesIndex == 1:
-                    combo = self.ui.cmdlineCombo
-                elif historiesIndex == 2:
-                    combo = self.ui.workdirPicker
-                else:
-                    combo = self.ui.environmentCombo
-                combo.clear()
-                combo.addItems(history)
-                
-                self.__historiesModified = True
+            if history:
+                from .StartHistoryEditDialog import StartHistoryEditDialog
+                dlg = StartHistoryEditDialog(history, self)
+                if dlg.exec_() == QDialog.Accepted:
+                    history = dlg.getHistory()
+                    combo = combos[historiesIndex]
+                    if combo:
+                        combo.clear()
+                        combo.addItems(history)
+                        
+                        self.__historiesModified = True
     
     def historiesModified(self):
         """
@@ -327,15 +348,24 @@
         Public method to get the lists of histories.
         
         @return tuple containing the histories of command line arguments,
-            working directories, environment settings and interpreters
+            working directories, environment settings and no debug programs
+            lists
         @rtype tuple of four list of str
         """
+        if self.dialogType == 0:
+            noDebugHistory = [
+                self.ui.multiprocessNoDebugCombo.itemText(index)
+                for index in range(self.ui.multiprocessNoDebugCombo.count())
+            ]
+        else:
+            noDebugHistory = None
         return (
             [self.ui.cmdlineCombo.itemText(index) for index in range(
                 self.ui.cmdlineCombo.count())],
             self.ui.workdirPicker.getPathItems(),
             [self.ui.environmentCombo.itemText(index) for index in range(
                 self.ui.environmentCombo.count())],
+            noDebugHistory,
         )
     
     def on_buttonBox_clicked(self, button):

eric ide

mercurial