src/eric7/Debugger/DebuggerInterfacePython.py

branch
eric7-maintenance
changeset 10814
ba20efe10336
parent 10733
d96c69a235fc
parent 10766
d35d6f96c24b
child 10941
07cad049002c
equal deleted inserted replaced
10734:2b015db9761a 10814:ba20efe10336
14 import shlex 14 import shlex
15 import struct 15 import struct
16 import time 16 import time
17 import zlib 17 import zlib
18 18
19 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer 19 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer, pyqtSlot
20 20
21 from eric7 import Preferences, Utilities 21 from eric7 import Preferences, Utilities
22 from eric7.EricWidgets import EricMessageBox 22 from eric7.EricWidgets import EricMessageBox
23 from eric7.EricWidgets.EricApplication import ericApp 23 from eric7.EricWidgets.EricApplication import ericApp
24 from eric7.Globals import getConfig 24 from eric7.Globals import getConfig
48 48
49 self.__isNetworked = True 49 self.__isNetworked = True
50 self.__autoContinue = False 50 self.__autoContinue = False
51 self.__autoContinued = [] 51 self.__autoContinued = []
52 self.__isStepCommand = False 52 self.__isStepCommand = False
53
54 self.__ericServerDebugging = False # are we debugging via the eric-ide server?
55 try:
56 self.__ericServerDebuggerInterface = (
57 ericApp().getObject("EricServer").getServiceInterface("Debugger")
58 )
59 self.__ericServerDebuggerInterface.debugClientResponse.connect(
60 lambda jsonStr: self.handleJsonCommand(jsonStr, None)
61 )
62 self.__ericServerDebuggerInterface.debugClientDisconnected.connect(
63 self.__handleServerDebugClientDisconnected
64 )
65 self.__ericServerDebuggerInterface.lastClientExited.connect(
66 self.__handleServerLastClientExited
67 )
68 except KeyError:
69 self.__ericServerDebuggerInterface = None
53 70
54 self.debugServer = debugServer 71 self.debugServer = debugServer
55 self.passive = passive 72 self.passive = passive
56 self.process = None 73 self.process = None
57 self.__startedVenv = "" 74 self.__startedVenv = ""
87 Private method to perform the identity path translation. 104 Private method to perform the identity path translation.
88 105
89 @param fn filename to be translated 106 @param fn filename to be translated
90 @type str 107 @type str
91 @param remote2local flag indicating the direction of translation 108 @param remote2local flag indicating the direction of translation
92 (False = local to remote, True = remote to local [default]) (unused) 109 (False = local to remote, True = remote to local) (defaults to True)
93 @type bool 110 (unused)
111 @type bool (optional)
94 @return translated filename 112 @return translated filename
95 @rtype str 113 @rtype str
96 """ 114 """
97 return fn 115 return fn
98 116
101 Private method to perform the path translation. 119 Private method to perform the path translation.
102 120
103 @param fn filename to be translated 121 @param fn filename to be translated
104 @type str 122 @type str
105 @param remote2local flag indicating the direction of translation 123 @param remote2local flag indicating the direction of translation
106 (False = local to remote, True = remote to local [default]) 124 (False = local to remote, True = remote to local) (defaults to True)
107 @type bool 125 @type bool (optional)
108 @return translated filename 126 @return translated filename
109 @rtype str 127 @rtype str
110 """ 128 """
111 if remote2local: 129 if remote2local:
112 path = fn.replace(self.translateRemote, self.translateLocal) 130 path = fn.replace(self.translateRemote, self.translateLocal)
117 if not self.translateRemoteWindows: 135 if not self.translateRemoteWindows:
118 path = path.replace("\\", "/") 136 path = path.replace("\\", "/")
119 137
120 return path 138 return path
121 139
122 def __startProcess(self, program, arguments, environment=None, workingDir=None): 140 def __ericServerTranslation(self, fn, remote2local=True):
141 """
142 Private method to perform the eric-ide server path translation.
143
144 @param fn filename to be translated
145 @type str
146 @param remote2local flag indicating the direction of translation
147 (False = local to remote, True = remote to local) (defaults to True)
148 @type bool (optional)
149 @return translated filename
150 @rtype str
151 """
152 if remote2local:
153 return FileSystemUtilities.remoteFileName(fn)
154 else:
155 return FileSystemUtilities.plainFileName(fn)
156
157 def __startProcess(self, program, arguments, environment=None, workingDir=""):
123 """ 158 """
124 Private method to start the debugger client process. 159 Private method to start the debugger client process.
125 160
126 @param program name of the executable to start 161 @param program name of the executable to start
127 @type str 162 @type str
153 self, 188 self,
154 port, 189 port,
155 runInConsole, 190 runInConsole,
156 venvName, 191 venvName,
157 originalPathString, 192 originalPathString,
158 workingDir=None, 193 workingDir="",
159 configOverride=None, 194 configOverride=None,
195 startRemote=None,
160 ): 196 ):
161 """ 197 """
162 Public method to start a remote Python interpreter. 198 Public method to start a remote Python interpreter.
163 199
164 @param port port number the debug server is listening on 200 @param port port number the debug server is listening on
168 @type bool 204 @type bool
169 @param venvName name of the virtual environment to be used 205 @param venvName name of the virtual environment to be used
170 @type str 206 @type str
171 @param originalPathString original PATH environment variable 207 @param originalPathString original PATH environment variable
172 @type str 208 @type str
173 @param workingDir directory to start the debugger client in 209 @param workingDir directory to start the debugger client in (defaults to "")
174 @type str 210 @type str (optional)
175 @param configOverride dictionary containing the global config override 211 @param configOverride dictionary containing the global config override data
176 data 212 (defaults to None)
177 @type dict 213 @type dict (optional)
214 @param startRemote flag indicating to start the client via an eric-ide server
215 (defaults to None)
216 @type bool (optional)
178 @return client process object, a flag to indicate a network connection 217 @return client process object, a flag to indicate a network connection
179 and the name of the interpreter in case of a local execution 218 and the name of the interpreter in case of a local execution
180 @rtype tuple of (QProcess, bool, str) 219 @rtype tuple of (QProcess, bool, str)
181 """ 220 """
182 global origPathEnv 221 global origPathEnv
183 222
184 if not venvName: 223 if (
185 venvName = Preferences.getDebugger("Python3VirtualEnv") 224 startRemote is True
186 if venvName == self.debugServer.getProjectEnvironmentString(): 225 or (
187 project = ericApp().getObject("Project") 226 startRemote is None
188 venvName = project.getProjectVenv() 227 and (
189 execPath = project.getProjectExecPath() 228 venvName == self.debugServer.getEricServerEnvironmentString()
190 interpreter = project.getProjectInterpreter() 229 or self.__ericServerDebugging
230 )
231 )
232 ) and ericApp().getObject("EricServer").isServerConnected():
233 # TODO change this once server environment definitions are supported
234 startRemote = True
235 if venvName:
236 venvManager = ericApp().getObject("VirtualEnvManager")
237 interpreter = venvManager.getVirtualenvInterpreter(venvName)
238 else:
239 venvName = self.debugServer.getEricServerEnvironmentString()
240 interpreter = "" # use the interpreter of the server
191 else: 241 else:
192 venvManager = ericApp().getObject("VirtualEnvManager") 242 if not venvName:
193 interpreter = venvManager.getVirtualenvInterpreter(venvName) 243 venvName = Preferences.getDebugger("Python3VirtualEnv")
194 execPath = venvManager.getVirtualenvExecPath(venvName) 244 if venvName == self.debugServer.getProjectEnvironmentString():
195 if interpreter == "": 245 project = ericApp().getObject("Project")
196 # use the interpreter used to run eric for identical variants 246 venvName = project.getProjectVenv()
197 interpreter = PythonUtilities.getPythonExecutable() 247 execPath = project.getProjectExecPath()
198 if interpreter == "": 248 interpreter = project.getProjectInterpreter()
199 EricMessageBox.critical( 249 else:
200 None, 250 venvManager = ericApp().getObject("VirtualEnvManager")
201 self.tr("Start Debugger"), 251 interpreter = venvManager.getVirtualenvInterpreter(venvName)
202 self.tr("""<p>No suitable Python3 environment configured.</p>"""), 252 execPath = venvManager.getVirtualenvExecPath(venvName)
203 ) 253 if interpreter == "":
204 return None, False, "" 254 # use the interpreter used to run eric for identical variants
255 interpreter = PythonUtilities.getPythonExecutable()
256 if interpreter == "":
257 EricMessageBox.critical(
258 None,
259 self.tr("Start Debugger"),
260 self.tr("""<p>No suitable Python3 environment configured.</p>"""),
261 )
262 return None, False, ""
205 263
206 self.__inShutdown = False 264 self.__inShutdown = False
265
266 self.__ericServerDebugging = False
207 267
208 redirect = ( 268 redirect = (
209 str(configOverride["redirect"]) 269 str(configOverride["redirect"])
210 if configOverride and configOverride["enable"] 270 if configOverride and configOverride["enable"]
211 else str(Preferences.getDebugger("Python3Redirect")) 271 else str(Preferences.getDebugger("Python3Redirect"))
289 " login was given.</p>" 349 " login was given.</p>"
290 ), 350 ),
291 ) 351 )
292 return None, False, "" 352 return None, False, ""
293 353
354 elif startRemote and self.__ericServerDebuggerInterface is not None:
355 # debugging via an eric-ide server
356 self.translate = self.__ericServerTranslation
357 self.__ericServerDebugging = True
358
359 args = []
360 if noencoding:
361 args.append(noencoding)
362 if multiprocessEnabled:
363 args.append(multiprocessEnabled)
364 if callTraceOptimization:
365 args.append(callTraceOptimization)
366 self.__ericServerDebuggerInterface.startClient(
367 interpreter,
368 originalPathString,
369 args,
370 workingDir=workingDir,
371 )
372 self.__startedVenv = venvName
373
374 return None, self.__isNetworked, ""
375
294 else: 376 else:
295 # local debugging code below 377 # local debugging code below
296 debugClient = self.__determineDebugClient() 378 debugClient = self.__determineDebugClient()
297 379
298 # set translation function 380 # set translation function
397 runInConsole, 479 runInConsole,
398 venvName, 480 venvName,
399 originalPathString, 481 originalPathString,
400 workingDir=None, 482 workingDir=None,
401 configOverride=None, 483 configOverride=None,
484 startRemote=False,
402 ): 485 ):
403 """ 486 """
404 Public method to start a remote Python interpreter for a project. 487 Public method to start a remote Python interpreter for a project.
405 488
406 @param port port number the debug server is listening on 489 @param port port number the debug server is listening on
415 @param workingDir directory to start the debugger client in 498 @param workingDir directory to start the debugger client in
416 @type str 499 @type str
417 @param configOverride dictionary containing the global config override 500 @param configOverride dictionary containing the global config override
418 data 501 data
419 @type dict 502 @type dict
503 @param startRemote flag indicating to start the client via an eric-ide server
504 (defaults to False)
505 @type bool (optional)
420 @return client process object, a flag to indicate a network connection 506 @return client process object, a flag to indicate a network connection
421 and the name of the interpreter in case of a local execution 507 and the name of the interpreter in case of a local execution
422 @rtype tuple of (QProcess, bool, str) 508 @rtype tuple of (QProcess, bool, str)
423 """ 509 """
424 global origPathEnv 510 global origPathEnv
441 "--call-trace-optimization" 527 "--call-trace-optimization"
442 if Preferences.getDebugger("PythonCallTraceOptimization") 528 if Preferences.getDebugger("PythonCallTraceOptimization")
443 else "" 529 else ""
444 ) 530 )
445 531
446 if venvName and venvName != self.debugServer.getProjectEnvironmentString(): 532 if (
447 venvManager = ericApp().getObject("VirtualEnvManager") 533 startRemote is True
448 interpreter = venvManager.getVirtualenvInterpreter(venvName) 534 or (
449 execPath = venvManager.getVirtualenvExecPath(venvName) 535 startRemote is None
536 and (
537 venvName == self.debugServer.getEricServerEnvironmentString()
538 or self.__ericServerDebugging
539 )
540 )
541 ) and ericApp().getObject("EricServer").isServerConnected():
542 # TODO change this once server environment definitions are supported
543 startRemote = True
544 if venvName and venvName != self.debugServer.getProjectEnvironmentString():
545 venvManager = ericApp().getObject("VirtualEnvManager")
546 interpreter = venvManager.getVirtualenvInterpreter(venvName)
547 else:
548 venvName = project.getProjectVenv()
549 interpreter = project.getProjectInterpreter()
550 if not venvName:
551 venvName = self.debugServer.getEricServerEnvironmentString()
552 interpreter = "" # use the interpreter of the server
450 else: 553 else:
451 venvName = project.getProjectVenv() 554 if venvName and venvName != self.debugServer.getProjectEnvironmentString():
452 execPath = project.getProjectExecPath() 555 venvManager = ericApp().getObject("VirtualEnvManager")
453 interpreter = project.getProjectInterpreter() 556 interpreter = venvManager.getVirtualenvInterpreter(venvName)
454 if interpreter == "": 557 execPath = venvManager.getVirtualenvExecPath(venvName)
455 EricMessageBox.critical( 558 else:
456 None, 559 venvName = project.getProjectVenv()
457 self.tr("Start Debugger"), 560 execPath = project.getProjectExecPath()
458 self.tr("""<p>No suitable Python3 environment configured.</p>"""), 561 interpreter = project.getProjectInterpreter()
459 ) 562 if interpreter == "":
460 return None, self.__isNetworked, "" 563 EricMessageBox.critical(
564 None,
565 self.tr("Start Debugger"),
566 self.tr("""<p>No suitable Python3 environment configured.</p>"""),
567 )
568 return None, self.__isNetworked, ""
461 569
462 self.__inShutdown = False 570 self.__inShutdown = False
571
572 self.__ericServerDebugging = False
463 573
464 if project.getDebugProperty("REMOTEDEBUGGER"): 574 if project.getDebugProperty("REMOTEDEBUGGER"):
465 # remote debugging code 575 # remote debugging code
466 ipaddr = self.debugServer.getHostAddress(False) 576 ipaddr = self.debugServer.getHostAddress(False)
467 rexec = project.getDebugProperty("REMOTECOMMAND") 577 rexec = project.getDebugProperty("REMOTECOMMAND")
516 return process, self.__isNetworked, "" 626 return process, self.__isNetworked, ""
517 else: 627 else:
518 # remote shell command is missing 628 # remote shell command is missing
519 return None, self.__isNetworked, "" 629 return None, self.__isNetworked, ""
520 630
631 elif startRemote and self.__ericServerDebuggerInterface is not None:
632 # debugging via an eric-ide server
633 self.translate = self.__ericServerTranslation
634 self.__ericServerDebugging = True
635
636 args = []
637 if noencoding:
638 args.append(noencoding)
639 if multiprocessEnabled:
640 args.append(multiprocessEnabled)
641 if callTraceOptimization:
642 args.append(callTraceOptimization)
643 self.__ericServerDebuggerInterface.startClient(
644 interpreter,
645 originalPathString,
646 args,
647 workingDir=workingDir,
648 )
649 self.__startedVenv = venvName
650
651 return None, self.__isNetworked, ""
652
521 else: 653 else:
522 # local debugging code below 654 # local debugging code below
523 debugClient = project.getDebugProperty("DEBUGCLIENT") 655 debugClient = project.getDebugProperty("DEBUGCLIENT")
524 if not bool(debugClient) or not os.path.exists(debugClient): 656 if not bool(debugClient) or not os.path.exists(debugClient):
525 debugClient = self.__determineDebugClient() 657 debugClient = self.__determineDebugClient()
618 @return flag indicating success 750 @return flag indicating success
619 @rtype bool 751 @rtype bool
620 """ 752 """
621 self.__pendingConnections.append(sock) 753 self.__pendingConnections.append(sock)
622 754
623 sock.readyRead.connect(lambda: self.__parseClientLine(sock)) 755 sock.readyRead.connect(lambda: self.__receiveJson(sock))
624 sock.disconnected.connect(lambda: self.__socketDisconnected(sock)) 756 sock.disconnected.connect(lambda: self.__socketDisconnected(sock))
625 757
626 return True 758 return True
627 759
628 def __assignDebuggerId(self, sock, debuggerId): 760 def __assignDebuggerId(self, sock, debuggerId):
633 @param sock reference to the socket object 765 @param sock reference to the socket object
634 @type QTcpSocket 766 @type QTcpSocket
635 @param debuggerId id of the connected debug client 767 @param debuggerId id of the connected debug client
636 @type str 768 @type str
637 """ 769 """
638 if sock in self.__pendingConnections: 770 if sock and sock in self.__pendingConnections:
639 self.__connections[debuggerId] = sock 771 self.__connections[debuggerId] = sock
640 self.__pendingConnections.remove(sock) 772 self.__pendingConnections.remove(sock)
641 773
642 if self.__mainDebugger is None: 774 if self.__mainDebugger is None:
643 self.__mainDebugger = debuggerId 775 self.__mainDebugger = debuggerId
644 # Get the remote clients capabilities 776 # Get the remote clients capabilities
645 self.remoteCapabilities(debuggerId) 777 self.remoteCapabilities(debuggerId)
646 778
647 self.debugServer.signalClientDebuggerId(debuggerId) 779 self.debugServer.signalClientDebuggerId(debuggerId)
648 780
649 if debuggerId == self.__mainDebugger: 781 if debuggerId == self.__mainDebugger:
650 self.__flush() 782 self.__flush()
651 self.debugServer.mainClientConnected() 783 self.debugServer.mainClientConnected()
652 784
653 self.debugServer.initializeClient(debuggerId) 785 self.debugServer.initializeClient(debuggerId)
654 786
655 # perform auto-continue except for main 787 # perform auto-continue except for main
656 if ( 788 if (
657 debuggerId != self.__mainDebugger 789 debuggerId != self.__mainDebugger
658 and self.__autoContinue 790 and self.__autoContinue
659 and not self.__isStepCommand 791 and not self.__isStepCommand
660 ): 792 ):
661 QTimer.singleShot(0, lambda: self.remoteContinue(debuggerId)) 793 QTimer.singleShot(0, lambda: self.remoteContinue(debuggerId))
662 794
663 def __socketDisconnected(self, sock): 795 def __socketDisconnected(self, sock):
664 """ 796 """
665 Private slot handling a socket disconnecting. 797 Private slot handling a socket disconnecting.
666 798
668 @type QTcpSocket 800 @type QTcpSocket
669 """ 801 """
670 for debuggerId in list(self.__connections): 802 for debuggerId in list(self.__connections):
671 if self.__connections[debuggerId] is sock: 803 if self.__connections[debuggerId] is sock:
672 del self.__connections[debuggerId] 804 del self.__connections[debuggerId]
673 if debuggerId == self.__mainDebugger: 805 self.__handleServerDebugClientDisconnected(debuggerId)
674 self.__mainDebugger = None
675 if debuggerId in self.__autoContinued:
676 self.__autoContinued.remove(debuggerId)
677 if not self.__inShutdown:
678 with contextlib.suppress(RuntimeError):
679 # can be ignored during a shutdown
680 self.debugServer.signalClientDisconnected(debuggerId)
681 break 806 break
682 else: 807 else:
683 if sock in self.__pendingConnections: 808 if sock in self.__pendingConnections:
684 self.__pendingConnections.remove(sock) 809 self.__pendingConnections.remove(sock)
685 810
686 if not self.__connections: 811 if not self.__connections:
687 # no active connections anymore 812 # no active connections anymore
813 self.__handleServerLastClientExited()
814
815 @pyqtSlot(str)
816 def __handleServerDebugClientDisconnected(self, debuggerId):
817 """
818 Private slot handling the disconnect of a debug client.
819
820 @param debuggerId ID of the disconnected debugger
821 @type str
822 """
823 if debuggerId == self.__mainDebugger:
824 self.__mainDebugger = None
825 if debuggerId in self.__autoContinued:
826 self.__autoContinued.remove(debuggerId)
827 if not self.__inShutdown:
688 with contextlib.suppress(RuntimeError): 828 with contextlib.suppress(RuntimeError):
689 # debug server object might have been deleted already 829 # can be ignored during a shutdown
690 # ignore this 830 self.debugServer.signalClientDisconnected(debuggerId)
831
832 @pyqtSlot()
833 def __handleServerLastClientExited(self):
834 """
835 Private slot to handle the exit of the last debug client connected.
836 """
837 with contextlib.suppress(RuntimeError):
838 # debug server object might have been deleted already
839 # ignore this
840 self.__autoContinued.clear()
841 if not self.__inShutdown:
691 self.debugServer.signalLastClientExited() 842 self.debugServer.signalLastClientExited()
692 self.__autoContinued.clear() 843 self.debugServer.startClient()
693 if not self.__inShutdown:
694 self.debugServer.startClient()
695 844
696 def getDebuggerIds(self): 845 def getDebuggerIds(self):
697 """ 846 """
698 Public method to return the IDs of the connected debugger backends. 847 Public method to return the IDs of the connected debugger backends.
699 848
706 """ 855 """
707 Private slot to flush the queue. 856 Private slot to flush the queue.
708 """ 857 """
709 if self.__mainDebugger: 858 if self.__mainDebugger:
710 # Send commands that were waiting for the connection. 859 # Send commands that were waiting for the connection.
711 conn = self.__connections[self.__mainDebugger] 860 if self.__ericServerDebugging:
712 for jsonStr in self.__commandQueue: 861 for jsonStr in self.__commandQueue:
713 self.__writeJsonCommandToSocket(jsonStr, conn) 862 self.__ericServerDebuggerInterface.sendClientCommand(
863 self.__mainDebugger, jsonStr
864 )
865 else:
866 conn = self.__connections[self.__mainDebugger]
867 for jsonStr in self.__commandQueue:
868 self.__writeJsonCommandToSocket(jsonStr, conn)
714 869
715 self.__commandQueue.clear() 870 self.__commandQueue.clear()
716 871
717 def shutdown(self): 872 def shutdown(self):
718 """ 873 """
731 self.__shutdownSocket(sock) 886 self.__shutdownSocket(sock)
732 887
733 while self.__pendingConnections: 888 while self.__pendingConnections:
734 sock = self.__pendingConnections.pop() 889 sock = self.__pendingConnections.pop()
735 self.__shutdownSocket(sock) 890 self.__shutdownSocket(sock)
891
892 self.__ericServerDebuggerInterface.stopClient()
736 893
737 # reinitialize 894 # reinitialize
738 self.__commandQueue.clear() 895 self.__commandQueue.clear()
739 896
740 self.__mainDebugger = None 897 self.__mainDebugger = None
764 Public method to test, if a debug client has connected. 921 Public method to test, if a debug client has connected.
765 922
766 @return flag indicating the connection status 923 @return flag indicating the connection status
767 @rtype bool 924 @rtype bool
768 """ 925 """
769 return bool(self.__connections) 926 return bool(self.__connections) or self.__ericServerDebugging
770 927
771 def remoteEnvironment(self, env): 928 def remoteEnvironment(self, env):
772 """ 929 """
773 Public method to set the environment for a program to debug, run, ... 930 Public method to set the environment for a program to debug, run, ...
774 931
809 @type bool 966 @type bool
810 @param reportAllExceptions flag indicating to report all exceptions 967 @param reportAllExceptions flag indicating to report all exceptions
811 instead of unhandled exceptions only 968 instead of unhandled exceptions only
812 @type bool 969 @type bool
813 """ 970 """
971 if FileSystemUtilities.isPlainFileName(fn):
972 fn = os.path.abspath(fn)
973
814 self.__autoContinue = autoContinue 974 self.__autoContinue = autoContinue
815 self.__scriptName = os.path.abspath(fn) 975 self.__scriptName = fn
816 self.__isStepCommand = False 976 self.__isStepCommand = False
817 977
818 wd = self.translate(wd, False) 978 wd = self.translate(wd, False)
819 fn = self.translate(os.path.abspath(fn), False) 979 fn = self.translate(fn, False)
820 self.__sendJsonCommand( 980 self.__sendJsonCommand(
821 "RequestLoad", 981 "RequestLoad",
822 { 982 {
823 "workdir": wd, 983 "workdir": wd,
824 "filename": fn, 984 "filename": fn,
839 @param argv list of command line arguments to pass to the program 999 @param argv list of command line arguments to pass to the program
840 @type list of str 1000 @type list of str
841 @param wd working directory for the program 1001 @param wd working directory for the program
842 @type str 1002 @type str
843 """ 1003 """
844 self.__scriptName = os.path.abspath(fn) 1004 if FileSystemUtilities.isPlainFileName(fn):
1005 fn = os.path.abspath(fn)
1006
1007 self.__scriptName = fn
845 1008
846 wd = self.translate(wd, False) 1009 wd = self.translate(wd, False)
847 fn = self.translate(os.path.abspath(fn), False) 1010 fn = self.translate(fn, False)
848 self.__sendJsonCommand( 1011 self.__sendJsonCommand(
849 "RequestRun", 1012 "RequestRun",
850 { 1013 {
851 "workdir": wd, 1014 "workdir": wd,
852 "filename": fn, 1015 "filename": fn,
867 @type str 1030 @type str
868 @param erase flag indicating that coverage info should be 1031 @param erase flag indicating that coverage info should be
869 cleared first 1032 cleared first
870 @type bool 1033 @type bool
871 """ 1034 """
872 self.__scriptName = os.path.abspath(fn) 1035 if FileSystemUtilities.isPlainFileName(fn):
1036 fn = os.path.abspath(fn)
1037
1038 self.__scriptName = fn
873 1039
874 wd = self.translate(wd, False) 1040 wd = self.translate(wd, False)
875 fn = self.translate(os.path.abspath(fn), False) 1041 fn = self.translate(fn, False)
876 self.__sendJsonCommand( 1042 self.__sendJsonCommand(
877 "RequestCoverage", 1043 "RequestCoverage",
878 { 1044 {
879 "workdir": wd, 1045 "workdir": wd,
880 "filename": fn, 1046 "filename": fn,
896 @type str 1062 @type str
897 @param erase flag indicating that timing info should be cleared 1063 @param erase flag indicating that timing info should be cleared
898 first 1064 first
899 @type bool 1065 @type bool
900 """ 1066 """
901 self.__scriptName = os.path.abspath(fn) 1067 if FileSystemUtilities.isPlainFileName(fn):
1068 fn = os.path.abspath(fn)
1069
1070 self.__scriptName = fn
902 1071
903 wd = self.translate(wd, False) 1072 wd = self.translate(wd, False)
904 fn = self.translate(os.path.abspath(fn), False) 1073 fn = self.translate(fn, False)
905 self.__sendJsonCommand( 1074 self.__sendJsonCommand(
906 "RequestProfile", 1075 "RequestProfile",
907 { 1076 {
908 "workdir": wd, 1077 "workdir": wd,
909 "filename": fn, 1078 "filename": fn,
1041 @param cond condition of the breakpoint 1210 @param cond condition of the breakpoint
1042 @type str 1211 @type str
1043 @param temp flag indicating a temporary breakpoint 1212 @param temp flag indicating a temporary breakpoint
1044 @type bool 1213 @type bool
1045 """ 1214 """
1046 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1215 if debuggerId:
1216 debuggerList = [debuggerId]
1217 elif self.__ericServerDebugging:
1218 debuggerList = ["<<all>>"]
1219 else:
1220 debuggerList = list(self.__connections)
1047 for debuggerId in debuggerList: 1221 for debuggerId in debuggerList:
1048 self.__sendJsonCommand( 1222 self.__sendJsonCommand(
1049 "RequestBreakpoint", 1223 "RequestBreakpoint",
1050 { 1224 {
1051 "filename": self.translate(fn, False), 1225 "filename": self.translate(fn, False),
1068 @param line line number of the breakpoint 1242 @param line line number of the breakpoint
1069 @type int 1243 @type int
1070 @param enable flag indicating enabling or disabling a breakpoint 1244 @param enable flag indicating enabling or disabling a breakpoint
1071 @type bool 1245 @type bool
1072 """ 1246 """
1073 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1247 if debuggerId:
1248 debuggerList = [debuggerId]
1249 elif self.__ericServerDebugging:
1250 debuggerList = ["<<all>>"]
1251 else:
1252 debuggerList = list(self.__connections)
1074 for debuggerId in debuggerList: 1253 for debuggerId in debuggerList:
1075 self.__sendJsonCommand( 1254 self.__sendJsonCommand(
1076 "RequestBreakpointEnable", 1255 "RequestBreakpointEnable",
1077 { 1256 {
1078 "filename": self.translate(fn, False), 1257 "filename": self.translate(fn, False),
1093 @param line line number of the breakpoint 1272 @param line line number of the breakpoint
1094 @type int 1273 @type int
1095 @param count number of occurrences to ignore 1274 @param count number of occurrences to ignore
1096 @type int 1275 @type int
1097 """ 1276 """
1098 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1277 if debuggerId:
1278 debuggerList = [debuggerId]
1279 elif self.__ericServerDebugging:
1280 debuggerList = ["<<all>>"]
1281 else:
1282 debuggerList = list(self.__connections)
1099 for debuggerId in debuggerList: 1283 for debuggerId in debuggerList:
1100 self.__sendJsonCommand( 1284 self.__sendJsonCommand(
1101 "RequestBreakpointIgnore", 1285 "RequestBreakpointIgnore",
1102 { 1286 {
1103 "filename": self.translate(fn, False), 1287 "filename": self.translate(fn, False),
1118 @param setWatch flag indicating setting or resetting a watch expression 1302 @param setWatch flag indicating setting or resetting a watch expression
1119 @type bool 1303 @type bool
1120 @param temp flag indicating a temporary watch expression 1304 @param temp flag indicating a temporary watch expression
1121 @type bool 1305 @type bool
1122 """ 1306 """
1123 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1307 if debuggerId:
1308 debuggerList = [debuggerId]
1309 elif self.__ericServerDebugging:
1310 debuggerList = ["<<all>>"]
1311 else:
1312 debuggerList = list(self.__connections)
1124 for debuggerId in debuggerList: 1313 for debuggerId in debuggerList:
1125 # cond is combination of cond and special (s. watch expression 1314 # cond is combination of cond and special (s. watch expression
1126 # viewer) 1315 # viewer)
1127 self.__sendJsonCommand( 1316 self.__sendJsonCommand(
1128 "RequestWatch", 1317 "RequestWatch",
1143 @param cond expression of the watch expression 1332 @param cond expression of the watch expression
1144 @type str 1333 @type str
1145 @param enable flag indicating enabling or disabling a watch expression 1334 @param enable flag indicating enabling or disabling a watch expression
1146 @type bool 1335 @type bool
1147 """ 1336 """
1148 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1337 if debuggerId:
1338 debuggerList = [debuggerId]
1339 elif self.__ericServerDebugging:
1340 debuggerList = ["<<all>>"]
1341 else:
1342 debuggerList = list(self.__connections)
1149 for debuggerId in debuggerList: 1343 for debuggerId in debuggerList:
1150 # cond is combination of cond and special (s. watch expression 1344 # cond is combination of cond and special (s. watch expression
1151 # viewer) 1345 # viewer)
1152 self.__sendJsonCommand( 1346 self.__sendJsonCommand(
1153 "RequestWatchEnable", 1347 "RequestWatchEnable",
1168 @param cond expression of the watch expression 1362 @param cond expression of the watch expression
1169 @type str 1363 @type str
1170 @param count number of occurrences to ignore 1364 @param count number of occurrences to ignore
1171 @type int 1365 @type int
1172 """ 1366 """
1173 debuggerList = [debuggerId] if debuggerId else list(self.__connections) 1367 if debuggerId:
1368 debuggerList = [debuggerId]
1369 elif self.__ericServerDebugging:
1370 debuggerList = ["<<all>>"]
1371 else:
1372 debuggerList = list(self.__connections)
1174 for debuggerId in debuggerList: 1373 for debuggerId in debuggerList:
1175 # cond is combination of cond and special (s. watch expression 1374 # cond is combination of cond and special (s. watch expression
1176 # viewer) 1375 # viewer)
1177 self.__sendJsonCommand( 1376 self.__sendJsonCommand(
1178 "RequestWatchIgnore", 1377 "RequestWatchIgnore",
1395 "text": text, 1594 "text": text,
1396 }, 1595 },
1397 debuggerId, 1596 debuggerId,
1398 ) 1597 )
1399 1598
1400 def __parseClientLine(self, sock): 1599 def __receiveJson(self, sock):
1401 """ 1600 """
1402 Private method to handle data from the client. 1601 Private method to handle data from the client.
1403 1602
1404 @param sock reference to the socket to read data from 1603 @param sock reference to the socket to read data from
1405 @type QTcpSocket 1604 @type QTcpSocket
1432 # corrupted data -> discard and continue 1631 # corrupted data -> discard and continue
1433 continue 1632 continue
1434 1633
1435 jsonStr = data.decode("utf-8", "backslashreplace") 1634 jsonStr = data.decode("utf-8", "backslashreplace")
1436 1635
1437 logging.debug("<Debug-Server> %s", jsonStr) 1636 logging.getLogger(__name__).debug("<Debug-Server> %s", jsonStr)
1438 ##print("Server: ", jsonStr) ## debug # __IGNORE_WARNING_M891__ 1637 ##print("Server: ", jsonStr) ## debug # __IGNORE_WARNING_M891__
1439 1638
1440 self.__handleJsonCommand(jsonStr, sock) 1639 self.handleJsonCommand(jsonStr, sock)
1441 1640
1442 def __handleJsonCommand(self, jsonStr, sock): 1641 def handleJsonCommand(self, jsonStr, sock):
1443 """ 1642 """
1444 Private method to handle a command or response serialized as a 1643 Public method to handle a command or response serialized as a
1445 JSON string. 1644 JSON string.
1446 1645
1447 @param jsonStr string containing the command or response received 1646 @param jsonStr string containing the command or response received
1448 from the debug backend 1647 from the debug backend
1449 @type str 1648 @type str
1565 1764
1566 elif method == "RequestRaw": 1765 elif method == "RequestRaw":
1567 self.debugServer.signalClientRawInput( 1766 self.debugServer.signalClientRawInput(
1568 params["prompt"], params["echo"], params["debuggerId"] 1767 params["prompt"], params["echo"], params["debuggerId"]
1569 ) 1768 )
1769 pass
1570 1770
1571 elif method == "ResponseBPConditionError": 1771 elif method == "ResponseBPConditionError":
1572 fn = self.translate(params["filename"], True) 1772 fn = self.translate(params["filename"], True)
1573 self.debugServer.signalClientBreakConditionError( 1773 self.debugServer.signalClientBreakConditionError(
1574 fn, params["line"], params["debuggerId"] 1774 fn, params["line"], params["debuggerId"]
1634 ) 1834 )
1635 1835
1636 elif method == "ResponseExit": 1836 elif method == "ResponseExit":
1637 self.__scriptName = "" 1837 self.__scriptName = ""
1638 self.debugServer.signalClientExit( 1838 self.debugServer.signalClientExit(
1639 params["program"], 1839 self.translate(params["program"], True),
1640 params["status"], 1840 params["status"],
1641 params["message"], 1841 params["message"],
1642 params["debuggerId"], 1842 params["debuggerId"],
1643 ) 1843 )
1644 if params["debuggerId"] == self.__mainDebugger: 1844 if params["debuggerId"] == self.__mainDebugger:
1675 "method": command, 1875 "method": command,
1676 "params": params, 1876 "params": params,
1677 } 1877 }
1678 jsonStr = json.dumps(commandDict) 1878 jsonStr = json.dumps(commandDict)
1679 1879
1680 if debuggerId and debuggerId in self.__connections: 1880 if self.__ericServerDebugging:
1681 sock = self.__connections[debuggerId] 1881 # Debugging via the eric-ide server -> pass the command on to it
1682 elif sock is None and self.__mainDebugger is not None: 1882 if self.__mainDebugger is None:
1683 sock = self.__connections[self.__mainDebugger] 1883 # debugger has not connected yet -> queue the command
1684 if sock is not None: 1884 self.__commandQueue.append(jsonStr)
1685 self.__writeJsonCommandToSocket(jsonStr, sock) 1885 else:
1886 self.__ericServerDebuggerInterface.sendClientCommand(
1887 debuggerId, jsonStr
1888 )
1686 else: 1889 else:
1687 self.__commandQueue.append(jsonStr) 1890 # Local debugging -> send the command to the client
1891 if debuggerId and debuggerId in self.__connections:
1892 sock = self.__connections[debuggerId]
1893 elif sock is None and self.__mainDebugger is not None:
1894 with contextlib.suppress(KeyError):
1895 sock = self.__connections[self.__mainDebugger]
1896 if sock is not None:
1897 self.__writeJsonCommandToSocket(jsonStr, sock)
1898 else:
1899 self.__commandQueue.append(jsonStr)
1688 1900
1689 def __writeJsonCommandToSocket(self, jsonCommand, sock): 1901 def __writeJsonCommandToSocket(self, jsonCommand, sock):
1690 """ 1902 """
1691 Private method to write a JSON command to the socket. 1903 Private method to write a JSON command to the socket.
1692 1904

eric ide

mercurial