DebugClients/Python/DebugClientBase.py

branch
debugger speed
changeset 5179
5f56410e7624
parent 5178
878ce843ca9f
child 5205
df1709f0e49f
--- a/DebugClients/Python/DebugClientBase.py	Mon Sep 19 22:47:52 2016 +0200
+++ b/DebugClients/Python/DebugClientBase.py	Sat Sep 24 22:52:13 2016 +0200
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+# Copyright (c) 2002 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
 #
 
 """
@@ -11,6 +11,7 @@
 import socket
 import select
 import codeop
+import codecs
 import traceback
 import os
 import json
@@ -26,15 +27,36 @@
 from AsyncFile import AsyncFile, AsyncPendingWrite
 from DebugConfig import ConfigVarTypeStrings
 from FlexCompleter import Completer
-from DebugUtilities import getargvalues, formatargvalues, prepareJsonCommand
+from DebugUtilities import prepareJsonCommand
 from BreakpointWatch import Breakpoint, Watch
 
+if sys.version_info[0] == 2:
+    from inspect import getargvalues, formatargvalues
+else:
+    unichr = chr
+    from DebugUtilities import getargvalues, formatargvalues
 
 DebugClientInstance = None
 
 ###############################################################################
 
 
+def DebugClientRawInput(prompt="", echo=True):
+    """
+    Replacement for the standard raw_input builtin.
+    
+    This function works with the split debugger.
+    
+    @param prompt prompt to be shown. (string)
+    @param echo flag indicating echoing of the input (boolean)
+    @return result of the raw_input() call
+    """
+    if DebugClientInstance is None or not DebugClientInstance.redirect:
+        return DebugClientOrigRawInput(prompt)
+
+    return DebugClientInstance.raw_input(prompt, echo)
+
+
 def DebugClientInput(prompt="", echo=True):
     """
     Replacement for the standard input builtin.
@@ -50,14 +72,31 @@
 
     return DebugClientInstance.input(prompt, echo)
 
-# Use our own input().
-try:
-    DebugClientOrigInput = __builtins__.__dict__['input']
-    __builtins__.__dict__['input'] = DebugClientInput
-except (AttributeError, KeyError):
-    import __main__
-    DebugClientOrigInput = __main__.__builtins__.__dict__['input']
-    __main__.__builtins__.__dict__['input'] = DebugClientInput
+# Use our own input() and on Python 2 raw_input().
+if sys.version_info[0] == 2:
+    try:
+        DebugClientOrigRawInput = __builtins__.__dict__['raw_input']
+        __builtins__.__dict__['raw_input'] = DebugClientRawInput
+    except (AttributeError, KeyError):
+        import __main__
+        DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input']
+        __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput
+
+    try:
+        DebugClientOrigInput = __builtins__.__dict__['input']
+        __builtins__.__dict__['input'] = DebugClientInput
+    except (AttributeError, KeyError):
+        import __main__
+        DebugClientOrigInput = __main__.__builtins__.__dict__['input']
+        __main__.__builtins__.__dict__['input'] = DebugClientInput
+else:
+    try:
+        DebugClientOrigInput = __builtins__.__dict__['input']
+        __builtins__.__dict__['input'] = DebugClientRawInput
+    except (AttributeError, KeyError):
+        import __main__
+        DebugClientOrigInput = __main__.__builtins__.__dict__['input']
+        __main__.__builtins__.__dict__['input'] = DebugClientRawInput
 
 ###############################################################################
 
@@ -236,8 +275,8 @@
                 self.__coding = default
                 return
             
-            for l in text.splitlines():
-                m = self.coding_re.search(l)
+            for line in text.splitlines():
+                m = self.coding_re.search(line)
                 if m:
                     self.__coding = m.group(1)
                     return
@@ -290,9 +329,9 @@
             "threadList": threadList,
         })
     
-    def input(self, prompt, echo=True):
+    def raw_input(self, prompt, echo):
         """
-        Public method to implement input() using the event loop.
+        Public method to implement raw_input() / input() using the event loop.
         
         @param prompt the prompt to be shown (string)
         @param echo Flag indicating echoing of the input (boolean)
@@ -305,6 +344,15 @@
         self.eventLoop(True)
         return self.rawLine
 
+    def input(self, prompt):
+        """
+        Public method to implement input() (Python 2) using the event loop.
+        
+        @param prompt the prompt to be shown (string)
+        @return the entered string evaluated as a Python expresion
+        """
+        return eval(self.raw_input(prompt, True))
+        
     def sessionClose(self, exit=True):
         """
         Public method to close the session with the debugger and optionally
@@ -338,9 +386,16 @@
         @param mode kind of code to be generated (string, exec or eval)
         @return compiled code object (None in case of errors)
         """
-        with open(filename, encoding=self.__coding) as fp:
+        with codecs.open(filename, encoding=self.__coding) as fp:
             statement = fp.read()
         
+        if sys.version_info[0] == 2:
+            lines = statement.splitlines(True)
+            for lineno, line in enumerate(lines[:2]):
+                lines[lineno] = self.coding_re.sub('', line)
+
+            statement = unicode('').join(lines)  # __IGNORE_WARNING__
+        
         try:
             code = compile(statement + '\n', filename, mode)
         except SyntaxError:
@@ -392,6 +447,9 @@
         
         method = commandDict["method"]
         params = commandDict["params"]
+        if "filename" in params and sys.version_info[0] == 2:
+            params["filename"] = params["filename"].encode(
+                sys.getfilesystemencoding())
         
         if method == "RequestVariables":
             self.__dumpVariables(
@@ -415,9 +473,10 @@
                 })
         
         elif method == "RequestCapabilities":
+            clientType = "Python2" if sys.version_info[0] == 2 else "Python3"
             self.sendJsonCommand("ResponseCapabilities", {
                 "capabilities": self.__clientCapabilities(),
-                "clientType": "Python3"
+                "clientType": clientType
             })
         
         elif method == "RequestBanner":
@@ -564,15 +623,8 @@
                 self.cover.erase()
             sys.modules['__main__'] = self.debugMod
             self.debugMod.__dict__['__file__'] = sys.argv[0]
-            fp = open(sys.argv[0], encoding=self.__coding)
-            try:
-                script = fp.read()
-            finally:
-                fp.close()
-            if script:
-                if not script.endswith('\n'):
-                    script += '\n'
-                code = compile(script, sys.argv[0], 'exec')
+            code = self.__compileFileSource(sys.argv[0])
+            if code:
                 self.running = sys.argv[0]
                 res = 0
                 self.cover.start()
@@ -611,21 +663,24 @@
                 self.prof.erase()
             self.debugMod.__dict__['__file__'] = sys.argv[0]
             sys.modules['__main__'] = self.debugMod
-            fp = open(sys.argv[0], encoding=self.__coding)
-            try:
-                script = fp.read()
-            finally:
-                fp.close()
+            script = ''
+            if sys.version_info[0] == 2:
+                script = 'execfile({0!r})'.format(sys.argv[0])
+            else:
+                with codecs.open(sys.argv[0], encoding=self.__coding) as fp:
+                    script = fp.read()
+                if script and not script.endswith('\n'):
+                        script += '\n'
+            
             if script:
-                if not script.endswith('\n'):
-                    script += '\n'
                 self.running = sys.argv[0]
                 res = 0
                 try:
                     self.prof.run(script)
                 except SystemExit as exc:
                     res = exc.code
-                    atexit._run_exitfuncs()
+                    
+                atexit._run_exitfuncs()
                 self.prof.save()
                 self.writestream.flush()
                 self.progTerminated(res)
@@ -796,8 +851,7 @@
                     flag = ''
                 
                 try:
-                    compiledCond = compile(
-                        compiledCond, '<string>', 'eval')
+                    compiledCond = compile(compiledCond, '<string>', 'eval')
                 except SyntaxError:
                     self.sendJsonCommand("ResponseWatchConditionError", {
                         "condition": params["condition"],
@@ -1469,7 +1523,8 @@
         """
         varlist = []
         if qttype == 'QChar':
-            varlist.append(("", "QChar", "{0}".format(chr(value.unicode()))))
+            varlist.append(
+                ("", "QChar", "{0}".format(unichr(value.unicode()))))
             varlist.append(("", "int", "{0:d}".format(value.unicode())))
         elif qttype == 'QByteArray':
             varlist.append(
@@ -1480,6 +1535,12 @@
                 ("base64", "QByteArray", "{0}".format(value.toBase64())[2:-1]))
             varlist.append(("percent encoding", "QByteArray",
                             "{0}".format(value.toPercentEncoding())[2:-1]))
+        elif qttype == 'QString':
+            varlist.append(("", "QString", "{0}".format(value)))
+        elif qttype == 'QStringList':
+            for i in range(value.count()):
+                varlist.append(
+                    ("{0:d}".format(i), "QString", "{0}".format(value[i])))
         elif qttype == 'QPoint':
             varlist.append(("x", "int", "{0:d}".format(value.x())))
             varlist.append(("y", "int", "{0:d}".format(value.y())))
@@ -1595,7 +1656,7 @@
             
         return varlist
     
-    def __formatVariablesList(self, keylist, dict, scope, filter=[],
+    def __formatVariablesList(self, keylist, dict_, scope, filter=[],
                               formatSequences=False):
         """
         Private method to produce a formated variables list.
@@ -1607,7 +1668,7 @@
         values) is returned.
         
         @param keylist keys of the dictionary
-        @param dict the dictionary to be scanned
+        @param dict_ the dictionary to be scanned
         @param scope 1 to filter using the globals filter, 0 using the locals
             filter (int).
             Variables are only added to the list, if their name do not match
@@ -1649,10 +1710,11 @@
                 rvalue = '<module __builtin__ (built-in)>'
                 valtype = 'module'
             else:
-                value = dict[key]
+                value = dict_[key]
                 valtypestr = str(type(value))[1:-1]
                 
-                valtype = valtypestr[7:-1]
+                _, valtype = valtypestr.split(' ', 1)
+                valtype = valtype[1:-1]
                 if valtype not in ConfigVarTypeStrings:
                     if ConfigVarTypeStrings.index('instance') in filter:
                         continue
@@ -1928,8 +1990,8 @@
             family = socket.AF_INET
         else:
             family = socket.AF_INET6
-        return socket.getaddrinfo(host, None,
-                                  family, socket.SOCK_STREAM)[0][4][0]
+        return socket.getaddrinfo(host, None, family,
+                                  socket.SOCK_STREAM)[0][4][0]
     
     def main(self):
         """

eric ide

mercurial