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. |
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 = [''] |