DebugClients/Python/DebugClientBase.py

branch
debugger speed
changeset 5179
5f56410e7624
parent 5178
878ce843ca9f
child 5205
df1709f0e49f
equal deleted inserted replaced
5178:878ce843ca9f 5179:5f56410e7624
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 2
3 # Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2002 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 5
6 """ 6 """
7 Module implementing a debug client base class. 7 Module implementing a debug client base class.
8 """ 8 """
9 9
10 import sys 10 import sys
11 import socket 11 import socket
12 import select 12 import select
13 import codeop 13 import codeop
14 import codecs
14 import traceback 15 import traceback
15 import os 16 import os
16 import json 17 import json
17 import imp 18 import imp
18 import re 19 import re
24 import DebugVariables 25 import DebugVariables
25 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__ 26 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__
26 from AsyncFile import AsyncFile, AsyncPendingWrite 27 from AsyncFile import AsyncFile, AsyncPendingWrite
27 from DebugConfig import ConfigVarTypeStrings 28 from DebugConfig import ConfigVarTypeStrings
28 from FlexCompleter import Completer 29 from FlexCompleter import Completer
29 from DebugUtilities import getargvalues, formatargvalues, prepareJsonCommand 30 from DebugUtilities import prepareJsonCommand
30 from BreakpointWatch import Breakpoint, Watch 31 from BreakpointWatch import Breakpoint, Watch
31 32
33 if sys.version_info[0] == 2:
34 from inspect import getargvalues, formatargvalues
35 else:
36 unichr = chr
37 from DebugUtilities import getargvalues, formatargvalues
32 38
33 DebugClientInstance = None 39 DebugClientInstance = None
34 40
35 ############################################################################### 41 ###############################################################################
42
43
44 def DebugClientRawInput(prompt="", echo=True):
45 """
46 Replacement for the standard raw_input builtin.
47
48 This function works with the split debugger.
49
50 @param prompt prompt to be shown. (string)
51 @param echo flag indicating echoing of the input (boolean)
52 @return result of the raw_input() call
53 """
54 if DebugClientInstance is None or not DebugClientInstance.redirect:
55 return DebugClientOrigRawInput(prompt)
56
57 return DebugClientInstance.raw_input(prompt, echo)
36 58
37 59
38 def DebugClientInput(prompt="", echo=True): 60 def DebugClientInput(prompt="", echo=True):
39 """ 61 """
40 Replacement for the standard input builtin. 62 Replacement for the standard input builtin.
48 if DebugClientInstance is None or not DebugClientInstance.redirect: 70 if DebugClientInstance is None or not DebugClientInstance.redirect:
49 return DebugClientOrigInput(prompt) 71 return DebugClientOrigInput(prompt)
50 72
51 return DebugClientInstance.input(prompt, echo) 73 return DebugClientInstance.input(prompt, echo)
52 74
53 # Use our own input(). 75 # Use our own input() and on Python 2 raw_input().
54 try: 76 if sys.version_info[0] == 2:
55 DebugClientOrigInput = __builtins__.__dict__['input'] 77 try:
56 __builtins__.__dict__['input'] = DebugClientInput 78 DebugClientOrigRawInput = __builtins__.__dict__['raw_input']
57 except (AttributeError, KeyError): 79 __builtins__.__dict__['raw_input'] = DebugClientRawInput
58 import __main__ 80 except (AttributeError, KeyError):
59 DebugClientOrigInput = __main__.__builtins__.__dict__['input'] 81 import __main__
60 __main__.__builtins__.__dict__['input'] = DebugClientInput 82 DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input']
83 __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput
84
85 try:
86 DebugClientOrigInput = __builtins__.__dict__['input']
87 __builtins__.__dict__['input'] = DebugClientInput
88 except (AttributeError, KeyError):
89 import __main__
90 DebugClientOrigInput = __main__.__builtins__.__dict__['input']
91 __main__.__builtins__.__dict__['input'] = DebugClientInput
92 else:
93 try:
94 DebugClientOrigInput = __builtins__.__dict__['input']
95 __builtins__.__dict__['input'] = DebugClientRawInput
96 except (AttributeError, KeyError):
97 import __main__
98 DebugClientOrigInput = __main__.__builtins__.__dict__['input']
99 __main__.__builtins__.__dict__['input'] = DebugClientRawInput
61 100
62 ############################################################################### 101 ###############################################################################
63 102
64 103
65 def DebugClientFork(): 104 def DebugClientFork():
234 f.close() 273 f.close()
235 except IOError: 274 except IOError:
236 self.__coding = default 275 self.__coding = default
237 return 276 return
238 277
239 for l in text.splitlines(): 278 for line in text.splitlines():
240 m = self.coding_re.search(l) 279 m = self.coding_re.search(line)
241 if m: 280 if m:
242 self.__coding = m.group(1) 281 self.__coding = m.group(1)
243 return 282 return
244 self.__coding = default 283 self.__coding = default
245 284
288 self.sendJsonCommand("ResponseThreadList", { 327 self.sendJsonCommand("ResponseThreadList", {
289 "currentID": currentId, 328 "currentID": currentId,
290 "threadList": threadList, 329 "threadList": threadList,
291 }) 330 })
292 331
293 def input(self, prompt, echo=True): 332 def raw_input(self, prompt, echo):
294 """ 333 """
295 Public method to implement input() using the event loop. 334 Public method to implement raw_input() / input() using the event loop.
296 335
297 @param prompt the prompt to be shown (string) 336 @param prompt the prompt to be shown (string)
298 @param echo Flag indicating echoing of the input (boolean) 337 @param echo Flag indicating echoing of the input (boolean)
299 @return the entered string 338 @return the entered string
300 """ 339 """
303 "echo": echo, 342 "echo": echo,
304 }) 343 })
305 self.eventLoop(True) 344 self.eventLoop(True)
306 return self.rawLine 345 return self.rawLine
307 346
347 def input(self, prompt):
348 """
349 Public method to implement input() (Python 2) using the event loop.
350
351 @param prompt the prompt to be shown (string)
352 @return the entered string evaluated as a Python expresion
353 """
354 return eval(self.raw_input(prompt, True))
355
308 def sessionClose(self, exit=True): 356 def sessionClose(self, exit=True):
309 """ 357 """
310 Public method to close the session with the debugger and optionally 358 Public method to close the session with the debugger and optionally
311 terminate. 359 terminate.
312 360
336 384
337 @param filename name of the source file (string) 385 @param filename name of the source file (string)
338 @param mode kind of code to be generated (string, exec or eval) 386 @param mode kind of code to be generated (string, exec or eval)
339 @return compiled code object (None in case of errors) 387 @return compiled code object (None in case of errors)
340 """ 388 """
341 with open(filename, encoding=self.__coding) as fp: 389 with codecs.open(filename, encoding=self.__coding) as fp:
342 statement = fp.read() 390 statement = fp.read()
391
392 if sys.version_info[0] == 2:
393 lines = statement.splitlines(True)
394 for lineno, line in enumerate(lines[:2]):
395 lines[lineno] = self.coding_re.sub('', line)
396
397 statement = unicode('').join(lines) # __IGNORE_WARNING__
343 398
344 try: 399 try:
345 code = compile(statement + '\n', filename, mode) 400 code = compile(statement + '\n', filename, mode)
346 except SyntaxError: 401 except SyntaxError:
347 exctype, excval, exctb = sys.exc_info() 402 exctype, excval, exctb = sys.exc_info()
390 printerr(str(err)) 445 printerr(str(err))
391 return 446 return
392 447
393 method = commandDict["method"] 448 method = commandDict["method"]
394 params = commandDict["params"] 449 params = commandDict["params"]
450 if "filename" in params and sys.version_info[0] == 2:
451 params["filename"] = params["filename"].encode(
452 sys.getfilesystemencoding())
395 453
396 if method == "RequestVariables": 454 if method == "RequestVariables":
397 self.__dumpVariables( 455 self.__dumpVariables(
398 params["frameNumber"], params["scope"], params["filters"]) 456 params["frameNumber"], params["scope"], params["filters"])
399 457
413 self.sendJsonCommand("ResponseStack", { 471 self.sendJsonCommand("ResponseStack", {
414 "stack": stack, 472 "stack": stack,
415 }) 473 })
416 474
417 elif method == "RequestCapabilities": 475 elif method == "RequestCapabilities":
476 clientType = "Python2" if sys.version_info[0] == 2 else "Python3"
418 self.sendJsonCommand("ResponseCapabilities", { 477 self.sendJsonCommand("ResponseCapabilities", {
419 "capabilities": self.__clientCapabilities(), 478 "capabilities": self.__clientCapabilities(),
420 "clientType": "Python3" 479 "clientType": clientType
421 }) 480 })
422 481
423 elif method == "RequestBanner": 482 elif method == "RequestBanner":
424 self.sendJsonCommand("ResponseBanner", { 483 self.sendJsonCommand("ResponseBanner", {
425 "version": "Python {0}".format(sys.version), 484 "version": "Python {0}".format(sys.version),
562 621
563 if params["erase"]: 622 if params["erase"]:
564 self.cover.erase() 623 self.cover.erase()
565 sys.modules['__main__'] = self.debugMod 624 sys.modules['__main__'] = self.debugMod
566 self.debugMod.__dict__['__file__'] = sys.argv[0] 625 self.debugMod.__dict__['__file__'] = sys.argv[0]
567 fp = open(sys.argv[0], encoding=self.__coding) 626 code = self.__compileFileSource(sys.argv[0])
568 try: 627 if code:
569 script = fp.read()
570 finally:
571 fp.close()
572 if script:
573 if not script.endswith('\n'):
574 script += '\n'
575 code = compile(script, sys.argv[0], 'exec')
576 self.running = sys.argv[0] 628 self.running = sys.argv[0]
577 res = 0 629 res = 0
578 self.cover.start() 630 self.cover.start()
579 try: 631 try:
580 exec(code, self.debugMod.__dict__) 632 exec(code, self.debugMod.__dict__)
609 661
610 if params["erase"]: 662 if params["erase"]:
611 self.prof.erase() 663 self.prof.erase()
612 self.debugMod.__dict__['__file__'] = sys.argv[0] 664 self.debugMod.__dict__['__file__'] = sys.argv[0]
613 sys.modules['__main__'] = self.debugMod 665 sys.modules['__main__'] = self.debugMod
614 fp = open(sys.argv[0], encoding=self.__coding) 666 script = ''
615 try: 667 if sys.version_info[0] == 2:
616 script = fp.read() 668 script = 'execfile({0!r})'.format(sys.argv[0])
617 finally: 669 else:
618 fp.close() 670 with codecs.open(sys.argv[0], encoding=self.__coding) as fp:
671 script = fp.read()
672 if script and not script.endswith('\n'):
673 script += '\n'
674
619 if script: 675 if script:
620 if not script.endswith('\n'):
621 script += '\n'
622 self.running = sys.argv[0] 676 self.running = sys.argv[0]
623 res = 0 677 res = 0
624 try: 678 try:
625 self.prof.run(script) 679 self.prof.run(script)
626 except SystemExit as exc: 680 except SystemExit as exc:
627 res = exc.code 681 res = exc.code
628 atexit._run_exitfuncs() 682
683 atexit._run_exitfuncs()
629 self.prof.save() 684 self.prof.save()
630 self.writestream.flush() 685 self.writestream.flush()
631 self.progTerminated(res) 686 self.progTerminated(res)
632 687
633 elif method == "ExecuteStatement": 688 elif method == "ExecuteStatement":
794 else: 849 else:
795 compiledCond = params["condition"] 850 compiledCond = params["condition"]
796 flag = '' 851 flag = ''
797 852
798 try: 853 try:
799 compiledCond = compile( 854 compiledCond = compile(compiledCond, '<string>', 'eval')
800 compiledCond, '<string>', 'eval')
801 except SyntaxError: 855 except SyntaxError:
802 self.sendJsonCommand("ResponseWatchConditionError", { 856 self.sendJsonCommand("ResponseWatchConditionError", {
803 "condition": params["condition"], 857 "condition": params["condition"],
804 }) 858 })
805 return 859 return
1467 variable entry is a tuple of three elements, the variable name, 1521 variable entry is a tuple of three elements, the variable name,
1468 its type and value. 1522 its type and value.
1469 """ 1523 """
1470 varlist = [] 1524 varlist = []
1471 if qttype == 'QChar': 1525 if qttype == 'QChar':
1472 varlist.append(("", "QChar", "{0}".format(chr(value.unicode())))) 1526 varlist.append(
1527 ("", "QChar", "{0}".format(unichr(value.unicode()))))
1473 varlist.append(("", "int", "{0:d}".format(value.unicode()))) 1528 varlist.append(("", "int", "{0:d}".format(value.unicode())))
1474 elif qttype == 'QByteArray': 1529 elif qttype == 'QByteArray':
1475 varlist.append( 1530 varlist.append(
1476 ("bytes", "QByteArray", "{0}".format(bytes(value))[2:-1])) 1531 ("bytes", "QByteArray", "{0}".format(bytes(value))[2:-1]))
1477 varlist.append( 1532 varlist.append(
1478 ("hex", "QByteArray", "{0}".format(value.toHex())[2:-1])) 1533 ("hex", "QByteArray", "{0}".format(value.toHex())[2:-1]))
1479 varlist.append( 1534 varlist.append(
1480 ("base64", "QByteArray", "{0}".format(value.toBase64())[2:-1])) 1535 ("base64", "QByteArray", "{0}".format(value.toBase64())[2:-1]))
1481 varlist.append(("percent encoding", "QByteArray", 1536 varlist.append(("percent encoding", "QByteArray",
1482 "{0}".format(value.toPercentEncoding())[2:-1])) 1537 "{0}".format(value.toPercentEncoding())[2:-1]))
1538 elif qttype == 'QString':
1539 varlist.append(("", "QString", "{0}".format(value)))
1540 elif qttype == 'QStringList':
1541 for i in range(value.count()):
1542 varlist.append(
1543 ("{0:d}".format(i), "QString", "{0}".format(value[i])))
1483 elif qttype == 'QPoint': 1544 elif qttype == 'QPoint':
1484 varlist.append(("x", "int", "{0:d}".format(value.x()))) 1545 varlist.append(("x", "int", "{0:d}".format(value.x())))
1485 varlist.append(("y", "int", "{0:d}".format(value.y()))) 1546 varlist.append(("y", "int", "{0:d}".format(value.y())))
1486 elif qttype == 'QPointF': 1547 elif qttype == 'QPointF':
1487 varlist.append(("x", "float", "{0:g}".format(value.x()))) 1548 varlist.append(("x", "float", "{0:g}".format(value.x())))
1593 varlist.append( 1654 varlist.append(
1594 ("address", "QHostAddress", "{0}".format(value.toString()))) 1655 ("address", "QHostAddress", "{0}".format(value.toString())))
1595 1656
1596 return varlist 1657 return varlist
1597 1658
1598 def __formatVariablesList(self, keylist, dict, scope, filter=[], 1659 def __formatVariablesList(self, keylist, dict_, scope, filter=[],
1599 formatSequences=False): 1660 formatSequences=False):
1600 """ 1661 """
1601 Private method to produce a formated variables list. 1662 Private method to produce a formated variables list.
1602 1663
1603 The dictionary passed in to it is scanned. Variables are 1664 The dictionary passed in to it is scanned. Variables are
1605 in the filter list and their name doesn't match any of the filter 1666 in the filter list and their name doesn't match any of the filter
1606 expressions. The formated variables list (a list of tuples of 3 1667 expressions. The formated variables list (a list of tuples of 3
1607 values) is returned. 1668 values) is returned.
1608 1669
1609 @param keylist keys of the dictionary 1670 @param keylist keys of the dictionary
1610 @param dict the dictionary to be scanned 1671 @param dict_ the dictionary to be scanned
1611 @param scope 1 to filter using the globals filter, 0 using the locals 1672 @param scope 1 to filter using the globals filter, 0 using the locals
1612 filter (int). 1673 filter (int).
1613 Variables are only added to the list, if their name do not match 1674 Variables are only added to the list, if their name do not match
1614 any of the filter expressions. 1675 any of the filter expressions.
1615 @param filter the indices of variable types to be filtered. Variables 1676 @param filter the indices of variable types to be filtered. Variables
1647 # special handling for '__builtins__' (it's way too big) 1708 # special handling for '__builtins__' (it's way too big)
1648 if key == '__builtins__': 1709 if key == '__builtins__':
1649 rvalue = '<module __builtin__ (built-in)>' 1710 rvalue = '<module __builtin__ (built-in)>'
1650 valtype = 'module' 1711 valtype = 'module'
1651 else: 1712 else:
1652 value = dict[key] 1713 value = dict_[key]
1653 valtypestr = str(type(value))[1:-1] 1714 valtypestr = str(type(value))[1:-1]
1654 1715
1655 valtype = valtypestr[7:-1] 1716 _, valtype = valtypestr.split(' ', 1)
1717 valtype = valtype[1:-1]
1656 if valtype not in ConfigVarTypeStrings: 1718 if valtype not in ConfigVarTypeStrings:
1657 if ConfigVarTypeStrings.index('instance') in filter: 1719 if ConfigVarTypeStrings.index('instance') in filter:
1658 continue 1720 continue
1659 elif valtype == "sip.methoddescriptor": 1721 elif valtype == "sip.methoddescriptor":
1660 if ConfigVarTypeStrings.index( 1722 if ConfigVarTypeStrings.index(
1926 version = 'v4' 1988 version = 'v4'
1927 if version == 'v4': 1989 if version == 'v4':
1928 family = socket.AF_INET 1990 family = socket.AF_INET
1929 else: 1991 else:
1930 family = socket.AF_INET6 1992 family = socket.AF_INET6
1931 return socket.getaddrinfo(host, None, 1993 return socket.getaddrinfo(host, None, family,
1932 family, socket.SOCK_STREAM)[0][4][0] 1994 socket.SOCK_STREAM)[0][4][0]
1933 1995
1934 def main(self): 1996 def main(self):
1935 """ 1997 """
1936 Public method implementing the main method. 1998 Public method implementing the main method.
1937 """ 1999 """

eric ide

mercurial