DebugClients/Python/DebugVariables.py

branch
debugger speed
changeset 5178
878ce843ca9f
parent 5171
f1e9eebd5469
child 5239
27f56dc07b5b
equal deleted inserted replaced
5174:8c48f5e0cd92 5178:878ce843ca9f
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing classes and functions to dump variable contents.
8 """
9
10 #
11 # This code was inspired by pydevd.
12 #
13
14 MaxItemsToHandle = 300
15 TooLargeMessage = ("Too large to show contents. Max items to show: " +
16 str(MaxItemsToHandle))
17 TooLargeAttribute = "Too large to be handled."
18
19 ############################################################
20 ## Classes implementing resolvers for various compund types
21 ############################################################
22
23
24 class BaseResolver(object):
25 """
26 Base class of the resolver class tree.
27 """
28 def resolve(self, var, attribute):
29 """
30 Public method to get an attribute from a variable.
31
32 @param var variable to extract an attribute or value from
33 @type any
34 @param attribute name of the attribute to extract
35 @type str
36 @return value of the attribute
37 @rtype any
38 @exception NotImplementedError raised to indicate a missing
39 implementation
40 """ # __IGNORE_WARNING_D235__
41 raise NotImplementedError
42
43 def getDictionary(self, var):
44 """
45 Public method to get the attributes of a variable as a dictionary.
46
47 @param var variable to be converted
48 @type any
49 @return dictionary containing the variable attributes
50 @rtype dict
51 @exception NotImplementedError raised to indicate a missing
52 implementation
53 """ # __IGNORE_WARNING_D235__
54 raise NotImplementedError
55
56
57 class DefaultResolver(BaseResolver):
58 """
59 Class used to resolve the default way.
60 """
61 def resolve(self, var, attribute):
62 """
63 Public method to get an attribute from a variable.
64
65 @param var variable to extract an attribute or value from
66 @type any
67 @param attribute name of the attribute to extract
68 @type str
69 @return value of the attribute
70 @rtype any
71 """
72 return getattr(var, attribute)
73
74 def getDictionary(self, var):
75 """
76 Public method to get the attributes of a variable as a dictionary.
77
78 @param var variable to be converted
79 @type any
80 @return dictionary containing the variable attributes
81 @rtype dict
82 """
83 names = dir(var)
84 if not names and hasattr(var, "__members__"):
85 names = var.__members__
86
87 d = {}
88 for name in names:
89 try:
90 attribute = getattr(var, name)
91 d[name] = attribute
92 except Exception:
93 pass # if we can't get it, simply ignore it
94
95 return d
96
97
98 class DictResolver(BaseResolver):
99 """
100 Class used to resolve from a dictionary.
101 """
102 def resolve(self, var, attribute):
103 """
104 Public method to get an attribute from a variable.
105
106 @param var variable to extract an attribute or value from
107 @type dict
108 @param attribute name of the attribute to extract
109 @type str
110 @return value of the attribute
111 @rtype any
112 """
113 if attribute in ('___len___', TooLargeAttribute):
114 return None
115
116 if "(ID:" not in attribute:
117 try:
118 return var[attribute]
119 except Exception:
120 return getattr(var, attribute)
121
122 expectedID = int(attribute.split("(ID:")[-1][:-1])
123 for key, value in var.items():
124 if id(key) == expectedID:
125 return value
126
127 return None
128
129 def __keyToStr(self, key):
130 """
131 Private method to get a string representation for a key.
132
133 @param key key to be converted
134 @type any
135 @return string representation of the given key
136 @rtype str
137 """
138 if isinstance(key, str):
139 return repr(key)
140 else:
141 return key
142
143 def getDictionary(self, var):
144 """
145 Public method to get the attributes of a variable as a dictionary.
146
147 @param var variable to be converted
148 @type any
149 @return dictionary containing the variable attributes
150 @rtype dict
151 """
152 d = {}
153 count = 0
154 for key, value in var.items():
155 count += 1
156 key = "{0} (ID:{1})".format(self.__keyToStr(key), id(key))
157 d[key] = value
158 if count > MaxItemsToHandle:
159 d[TooLargeAttribute] = TooLargeMessage
160 break
161
162 d["___len___"] = len(var)
163
164 # in case it has additional fields
165 additionals = defaultResolver.getDictionary(var)
166 d.update(additionals)
167
168 return d
169
170
171 class ListResolver(BaseResolver):
172 """
173 Class used to resolve from a tuple or list.
174 """
175 def resolve(self, var, attribute):
176 """
177 Public method to get an attribute from a variable.
178
179 @param var variable to extract an attribute or value from
180 @type tuple or list
181 @param attribute name of the attribute to extract
182 @type str
183 @return value of the attribute
184 @rtype any
185 """
186 if attribute in ('___len___', TooLargeAttribute):
187 return None
188
189 try:
190 return var[int(attribute)]
191 except Exception:
192 return getattr(var, attribute)
193
194 def getDictionary(self, var):
195 """
196 Public method to get the attributes of a variable as a dictionary.
197
198 @param var variable to be converted
199 @type any
200 @return dictionary containing the variable attributes
201 @rtype dict
202 """
203 d = {}
204 count = 0
205 for value in var:
206 d[str(count)] = value
207 count += 1
208 if count > MaxItemsToHandle:
209 d[TooLargeAttribute] = TooLargeMessage
210 break
211
212 d["___len___"] = len(var)
213
214 # in case it has additional fields
215 additionals = defaultResolver.getDictionary(var)
216 d.update(additionals)
217
218 return d
219
220
221 class SetResolver(BaseResolver):
222 """
223 Class used to resolve from a set or frozenset.
224 """
225 def resolve(self, var, attribute):
226 """
227 Public method to get an attribute from a variable.
228
229 @param var variable to extract an attribute or value from
230 @type tuple or list
231 @param attribute id of the value to extract
232 @type str
233 @return value of the attribute
234 @rtype any
235 """
236 if attribute in ('___len___', TooLargeAttribute):
237 return None
238
239 if attribute.startswith("ID:"):
240 attribute = attribute.split(None, 1)[1]
241 try:
242 attribute = int(attribute)
243 except Exception:
244 return getattr(var, attribute)
245
246 for v in var:
247 if id(v) == attribute:
248 return v
249
250 return None
251
252 def getDictionary(self, var):
253 """
254 Public method to get the attributes of a variable as a dictionary.
255
256 @param var variable to be converted
257 @type any
258 @return dictionary containing the variable attributes
259 @rtype dict
260 """
261 d = {}
262 count = 0
263 for value in var:
264 count += 1
265 d["ID: " + str(id(value))] = value
266 if count > MaxItemsToHandle:
267 d[TooLargeAttribute] = TooLargeMessage
268 break
269
270 d["___len___"] = len(var)
271
272 # in case it has additional fields
273 additionals = defaultResolver.getDictionary(var)
274 d.update(additionals)
275
276 return d
277
278
279 defaultResolver = DefaultResolver()
280 dictResolver = DictResolver()
281 listResolver = ListResolver()
282 setResolver = SetResolver()
283
284 # TODO: add resolver for numpy arrays
285 # TODO: add resolver for Django MultiValueDict
286 # TODO: add resolver for collections.deque
287
288 ############################################################
289 ## Methods to determine the type of a variable and the
290 ## resolver class to use
291 ############################################################
292
293 _TypeMap = None
294
295
296 def _initTypeMap():
297 """
298 Protected function to initialize the type map.
299 """
300 global _TypeMap
301
302 _TypeMap = [
303 (type(None), None,),
304 (int, None),
305 (float, None),
306 (complex, None),
307 (str, None),
308 (tuple, listResolver),
309 (list, listResolver),
310 (dict, dictResolver),
311 ]
312
313 try:
314 _TypeMap.append((long, None)) # __IGNORE_WARNING__
315 except Exception:
316 pass # not available on all python versions
317
318 try:
319 _TypeMap.append((unicode, None)) # __IGNORE_WARNING__
320 except Exception:
321 pass # not available on all python versions
322
323 try:
324 _TypeMap.append((set, setResolver)) # __IGNORE_WARNING__
325 except Exception:
326 pass # not available on all python versions
327
328 try:
329 _TypeMap.append((frozenset, setResolver)) # __IGNORE_WARNING__
330 except Exception:
331 pass # not available on all python versions
332
333
334 def getType(obj):
335 """
336 Public method to get the type information for an object.
337
338 @param obj object to get type information for
339 @type any
340 @return tuple containing the type, type name, type string and resolver
341 @rtype tuple of type, str, str, BaseResolver
342 """
343 typeObject = type(obj)
344 typeName = typeObject.__name__
345 typeStr = str(typeObject)[8:-2]
346
347 if typeStr.startswith(("PyQt5.", "PyQt4.")):
348 resolver = None
349 else:
350 if _TypeMap is None:
351 _initTypeMap()
352
353 for typeData in _TypeMap:
354 if isinstance(obj, typeData[0]):
355 resolver = typeData[1]
356 break
357 else:
358 resolver = defaultResolver
359
360 return typeObject, typeName, typeStr, resolver
361
362 #
363 # eflag: noqa = M702

eric ide

mercurial