eric6/DebugClients/Python/DebugClientBase.py

branch
maintenance
changeset 8273
698ae46f40a4
parent 8176
31965986ecd1
parent 8262
2f6310aac6cd
child 8400
b3eefd7e58d1
equal deleted inserted replaced
8190:fb0ef164f536 8273:698ae46f40a4
20 import signal 20 import signal
21 import time 21 import time
22 import types 22 import types
23 import importlib.util 23 import importlib.util
24 import fnmatch 24 import fnmatch
25 25 import contextlib
26 26
27 import DebugClientCapabilities 27 import DebugClientCapabilities
28 import DebugVariables 28 import DebugVariables
29 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__ 29 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__
30 from AsyncFile import AsyncFile, AsyncPendingWrite 30 from AsyncFile import AsyncFile, AsyncPendingWrite
52 @return result of the input() call 52 @return result of the input() call
53 @rtype str 53 @rtype str
54 """ 54 """
55 if DebugClientInstance is None or not DebugClientInstance.redirect: 55 if DebugClientInstance is None or not DebugClientInstance.redirect:
56 return DebugClientOrigInput(prompt) 56 return DebugClientOrigInput(prompt)
57 57 else:
58 return DebugClientInstance.input(prompt) 58 return DebugClientInstance.input(prompt)
59 59
60 # Use our own input(). 60 # Use our own input().
61 try: 61 try:
62 DebugClientOrigInput = __builtins__.__dict__['input'] 62 DebugClientOrigInput = __builtins__.__dict__['input']
63 __builtins__.__dict__['input'] = DebugClientInput 63 __builtins__.__dict__['input'] = DebugClientInput
75 75
76 @param fd open file descriptor to be closed (integer) 76 @param fd open file descriptor to be closed (integer)
77 """ 77 """
78 if DebugClientInstance is None: 78 if DebugClientInstance is None:
79 DebugClientOrigClose(fd) 79 DebugClientOrigClose(fd)
80 80 else:
81 DebugClientInstance.close(fd) 81 DebugClientInstance.close(fd)
82 82
83 # use our own close(). 83 # use our own close().
84 if 'close' in dir(os): 84 if 'close' in dir(os):
85 DebugClientOrigClose = os.close 85 DebugClientOrigClose = os.close
86 os.close = DebugClientClose 86 os.close = DebugClientClose
105 DebugClientSetRecursionLimit(sys.getrecursionlimit()) 105 DebugClientSetRecursionLimit(sys.getrecursionlimit())
106 106
107 ############################################################################### 107 ###############################################################################
108 108
109 109
110 class DebugClientBase(object): 110 class DebugClientBase:
111 """ 111 """
112 Class implementing the client side of the debugger. 112 Class implementing the client side of the debugger.
113 113
114 It provides access to the Python interpeter from a debugger running in 114 It provides access to the Python interpeter from a debugger running in
115 another process. 115 another process.
237 Public method to close the session with the debugger and optionally 237 Public method to close the session with the debugger and optionally
238 terminate. 238 terminate.
239 239
240 @param terminate flag indicating to terminate (boolean) 240 @param terminate flag indicating to terminate (boolean)
241 """ 241 """
242 try: 242 with contextlib.suppress(Exception):
243 self.set_quit() 243 self.set_quit()
244 except Exception: # secok
245 pass
246 244
247 self.debugging = False 245 self.debugging = False
248 self.multiprocessSupport = False 246 self.multiprocessSupport = False
249 self.noDebugList = [] 247 self.noDebugList = []
250 248
1144 1142
1145 @return client capabilities (integer) 1143 @return client capabilities (integer)
1146 """ 1144 """
1147 try: 1145 try:
1148 import PyProfile # __IGNORE_WARNING__ 1146 import PyProfile # __IGNORE_WARNING__
1149 try: 1147 with contextlib.suppress(KeyError):
1150 del sys.modules['PyProfile'] 1148 del sys.modules['PyProfile']
1151 except KeyError:
1152 pass
1153 return self.clientCapabilities 1149 return self.clientCapabilities
1154 except ImportError: 1150 except ImportError:
1155 return ( 1151 return (
1156 self.clientCapabilities & ~DebugClientCapabilities.HasProfiler) 1152 self.clientCapabilities & ~DebugClientCapabilities.HasProfiler)
1157 1153
1524 elif f.f_globals is f.f_locals: 1520 elif f.f_globals is f.f_locals:
1525 scope = -1 1521 scope = -1
1526 else: 1522 else:
1527 varDict = f.f_locals 1523 varDict = f.f_locals
1528 1524
1529 if scope == -1: 1525 varlist = [] if scope == -1 else self.__formatVariablesList(
1530 varlist = [] 1526 varDict, scope, filterList)
1531 else:
1532 varlist = self.__formatVariablesList(varDict, scope, filterList)
1533 1527
1534 self.sendJsonCommand("ResponseVariables", { 1528 self.sendJsonCommand("ResponseVariables", {
1535 "scope": scope, 1529 "scope": scope,
1536 "variables": varlist, 1530 "variables": varlist,
1537 }) 1531 })
1759 1753
1760 # XML stuff 1754 # XML stuff
1761 elif qttype == 'QDomAttr': 1755 elif qttype == 'QDomAttr':
1762 varlist.append(("name", "str", "{0}".format(value.name()))) 1756 varlist.append(("name", "str", "{0}".format(value.name())))
1763 varlist.append(("value", "str", "{0}".format(value.value()))) 1757 varlist.append(("value", "str", "{0}".format(value.value())))
1764 elif qttype == 'QDomCharacterData': 1758 elif qttype in ('QDomCharacterData', 'QDomComment', 'QDomText'):
1765 varlist.append(("data", "str", "{0}".format(value.data())))
1766 elif qttype == 'QDomComment':
1767 varlist.append(("data", "str", "{0}".format(value.data()))) 1759 varlist.append(("data", "str", "{0}".format(value.data())))
1768 elif qttype == 'QDomDocument': 1760 elif qttype == 'QDomDocument':
1769 varlist.append(("text", "str", "{0}".format(value.toString()))) 1761 varlist.append(("text", "str", "{0}".format(value.toString())))
1770 elif qttype == 'QDomElement': 1762 elif qttype == 'QDomElement':
1771 varlist.append(("tagName", "str", "{0}".format(value.tagName()))) 1763 varlist.append(("tagName", "str", "{0}".format(value.tagName())))
1772 varlist.append(("text", "str", "{0}".format(value.text()))) 1764 varlist.append(("text", "str", "{0}".format(value.text())))
1773 elif qttype == 'QDomText': 1765
1774 varlist.append(("data", "str", "{0}".format(value.data())))
1775
1776 # Networking stuff 1766 # Networking stuff
1777 elif qttype == 'QHostAddress': 1767 elif qttype == 'QHostAddress':
1778 varlist.append( 1768 varlist.append(
1779 ("address", "QHostAddress", "{0}".format(value.toString()))) 1769 ("address", "QHostAddress", "{0}".format(value.toString())))
1780 1770
1812 @rtype list of tuple of (str, str, str) 1802 @rtype list of tuple of (str, str, str)
1813 """ 1803 """
1814 filterList = [] if filterList is None else filterList[:] 1804 filterList = [] if filterList is None else filterList[:]
1815 1805
1816 varlist = [] 1806 varlist = []
1817 if scope: 1807 patternFilterObjects = (
1818 patternFilterObjects = self.globalsFilterObjects 1808 self.globalsFilterObjects
1819 else: 1809 if scope else
1820 patternFilterObjects = self.localsFilterObjects 1810 self.localsFilterObjects
1811 )
1821 if type(dict_) == dict: 1812 if type(dict_) == dict:
1822 dict_ = dict_.items() 1813 dict_ = dict_.items()
1823 1814
1824 for key, value in dict_: 1815 for key, value in dict_:
1825 # no more elements available 1816 # no more elements available
1844 rvalue = '<module builtins (built-in)>' 1835 rvalue = '<module builtins (built-in)>'
1845 valtype = 'module' 1836 valtype = 'module'
1846 if valtype in filterList: 1837 if valtype in filterList:
1847 continue 1838 continue
1848 elif ( 1839 elif (
1849 key in SpecialAttributes and 1840 (key in SpecialAttributes and
1850 "special_attributes" in filterList 1841 "special_attributes" in filterList) or
1851 ): 1842 (key == "__hash__" and
1852 continue 1843 "builtin_function_or_method" in filterList)
1853 elif (
1854 key == "__hash__" and
1855 "builtin_function_or_method" in filterList
1856 ): 1844 ):
1857 continue 1845 continue
1858 else: 1846 else:
1859 isQt = False 1847 isQt = False
1860 # valtypestr, e.g. class 'PyQt5.QtCore.QPoint' 1848 # valtypestr, e.g. class 'PyQt5.QtCore.QPoint'
1870 elif valtype == "method-wrapper": 1858 elif valtype == "method-wrapper":
1871 valtype = "builtin_function_or_method" 1859 valtype = "builtin_function_or_method"
1872 1860
1873 # valtypename, e.g. QPoint 1861 # valtypename, e.g. QPoint
1874 valtypename = type(value).__name__ 1862 valtypename = type(value).__name__
1875 if valtype in filterList: 1863 if (
1876 continue 1864 valtype in filterList or
1877 elif ( 1865 (valtype in ("sip.enumtype", "sip.wrappertype") and
1878 valtype in ("sip.enumtype", "sip.wrappertype") and 1866 'class' in filterList) or
1879 'class' in filterList 1867 (valtype in (
1868 "sip.methoddescriptor", "method_descriptor") and
1869 'method' in filterList) or
1870 (valtype in ("numpy.ndarray", "array.array") and
1871 'list' in filterList) or
1872 (valtypename == "MultiValueDict" and
1873 'dict' in filterList) or
1874 'instance' in filterList
1880 ): 1875 ):
1881 continue
1882 elif (
1883 valtype in (
1884 "sip.methoddescriptor", "method_descriptor") and
1885 'method' in filterList
1886 ):
1887 continue
1888 elif (
1889 valtype in ("numpy.ndarray", "array.array") and
1890 'list' in filterList
1891 ):
1892 continue
1893 elif valtypename == "MultiValueDict" and 'dict' in filterList:
1894 continue
1895 elif 'instance' in filterList:
1896 continue 1876 continue
1897 1877
1898 isQt = valtype.startswith(ConfigQtNames) 1878 isQt = valtype.startswith(ConfigQtNames)
1899 1879
1900 try: 1880 try:
1959 text = text[pos + 1:] 1939 text = text[pos + 1:]
1960 break 1940 break
1961 pos -= 1 1941 pos -= 1
1962 1942
1963 # Get local and global completions 1943 # Get local and global completions
1964 try: 1944 with contextlib.suppress(AttributeError):
1965 localdict = self.currentThread.getFrameLocals(self.framenr) 1945 localdict = self.currentThread.getFrameLocals(self.framenr)
1966 localCompleter = Completer(localdict).complete 1946 localCompleter = Completer(localdict).complete
1967 self.__getCompletionList(text, localCompleter, completions) 1947 self.__getCompletionList(text, localCompleter, completions)
1968 except AttributeError:
1969 pass
1970 1948
1971 cf = self.currentThread.getCurrentFrame() 1949 cf = self.currentThread.getCurrentFrame()
1972 frmnr = self.framenr 1950 frmnr = self.framenr
1973 while cf is not None and frmnr > 0: 1951 while cf is not None and frmnr > 0:
1974 cf = cf.f_back 1952 cf = cf.f_back
1975 frmnr -= 1 1953 frmnr -= 1
1976 1954
1977 if cf is None: 1955 globaldict = self.debugMod.__dict__ if cf is None else cf.f_globals
1978 globaldict = self.debugMod.__dict__
1979 else:
1980 globaldict = cf.f_globals
1981 1956
1982 globalCompleter = Completer(globaldict).complete 1957 globalCompleter = Completer(globaldict).complete
1983 self.__getCompletionList(text, globalCompleter, completions) 1958 self.__getCompletionList(text, globalCompleter, completions)
1984 1959
1985 self.sendJsonCommand("ResponseCompletion", { 1960 self.sendJsonCommand("ResponseCompletion", {
2039 host = os.getenv('ERICHOST', 'localhost') 2014 host = os.getenv('ERICHOST', 'localhost')
2040 if port is None: 2015 if port is None:
2041 port = os.getenv('ERICPORT', 42424) 2016 port = os.getenv('ERICPORT', 42424)
2042 2017
2043 remoteAddress = self.__resolveHost(host) 2018 remoteAddress = self.__resolveHost(host)
2044 if filename is not None: 2019 name = os.path.basename(filename) if filename is not None else ""
2045 name = os.path.basename(filename)
2046 else:
2047 name = ""
2048 self.connectDebugger(port, remoteAddress, redirect, name=name) 2020 self.connectDebugger(port, remoteAddress, redirect, name=name)
2049 if filename is not None: 2021 if filename is not None:
2050 self.running = os.path.abspath(filename) 2022 self.running = os.path.abspath(filename)
2051 else: 2023 else:
2052 try: 2024 try:
2169 "__spec__": modSpec, 2141 "__spec__": modSpec,
2170 "__builtins__": __builtins__, 2142 "__builtins__": __builtins__,
2171 }) 2143 })
2172 else: 2144 else:
2173 code = self.__compileFileSource(self.running) 2145 code = self.__compileFileSource(self.running)
2174 if code: 2146 res = (
2175 res = self.mainThread.run(code, self.debugMod.__dict__, debug=True) 2147 self.mainThread.run(code, self.debugMod.__dict__, debug=True)
2176 else: 2148 if code else
2177 res = 42 # should not happen 2149 42 # should not happen
2150 )
2178 return res 2151 return res
2179 2152
2180 def run_call(self, scriptname, func, *args): 2153 def run_call(self, scriptname, func, *args):
2181 """ 2154 """
2182 Public method used to start the remote debugger and call a function. 2155 Public method used to start the remote debugger and call a function.
2200 """ 2173 """
2201 try: 2174 try:
2202 host, version = host.split("@@") 2175 host, version = host.split("@@")
2203 except ValueError: 2176 except ValueError:
2204 version = 'v4' 2177 version = 'v4'
2205 if version == 'v4': 2178 family = socket.AF_INET if version == 'v4' else socket.AF_INET6
2206 family = socket.AF_INET
2207 else:
2208 family = socket.AF_INET6
2209 2179
2210 retryCount = 0 2180 retryCount = 0
2211 while retryCount < 10: 2181 while retryCount < 10:
2212 try: 2182 try:
2213 addrinfo = socket.getaddrinfo( 2183 addrinfo = socket.getaddrinfo(
2326 redirect = int(sys.argv[2]) 2296 redirect = int(sys.argv[2])
2327 except (ValueError, IndexError): 2297 except (ValueError, IndexError):
2328 redirect = True 2298 redirect = True
2329 2299
2330 ipOrHost = sys.argv[3] 2300 ipOrHost = sys.argv[3]
2331 if ':' in ipOrHost: 2301 if ':' in ipOrHost or ipOrHost[0] in '0123456789':
2332 # IPv6 address 2302 # IPv6 address or IPv4 address
2333 remoteAddress = ipOrHost
2334 elif ipOrHost[0] in '0123456789':
2335 # IPv4 address
2336 remoteAddress = ipOrHost 2303 remoteAddress = ipOrHost
2337 else: 2304 else:
2338 remoteAddress = self.__resolveHost(ipOrHost) 2305 remoteAddress = self.__resolveHost(ipOrHost)
2339 2306
2340 sys.argv = [''] 2307 sys.argv = ['']
2395 @param scriptName name of the script to check 2362 @param scriptName name of the script to check
2396 @type str 2363 @type str
2397 @return flag indicating eligibility 2364 @return flag indicating eligibility
2398 @rtype bool 2365 @rtype bool
2399 """ 2366 """
2400 for pattern in self.noDebugList: 2367 return any(fnmatch.fnmatch(scriptName, pattern)
2401 if fnmatch.fnmatch(scriptName, pattern): 2368 for pattern in self.noDebugList)
2402 return True
2403
2404 return False

eric ide

mercurial