blob: 114b8494b6541dcfa04acf043a1225ae2e600858 [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001try:
2 import StringIO
3except:
4 import io as StringIO
5import traceback
6
7try:
8 __setFalse = False
9except:
10 import __builtin__
11 setattr(__builtin__, 'True', 1)
12 setattr(__builtin__, 'False', 0)
13
14import pydevd_constants
15
16
17MAX_ITEMS_TO_HANDLE = 500
18TOO_LARGE_MSG = 'Too large to show contents. Max items to show: ' + str(MAX_ITEMS_TO_HANDLE)
19TOO_LARGE_ATTR = 'Unable to handle:'
20
21#=======================================================================================================================
22# UnableToResolveVariableException
23#=======================================================================================================================
24class UnableToResolveVariableException(Exception):
25 pass
26
27
28#=======================================================================================================================
29# InspectStub
30#=======================================================================================================================
31class InspectStub:
32 def isbuiltin(self, _args):
33 return False
34 def isroutine(self, object):
35 return False
36
37try:
38 import inspect
39except:
40 inspect = InspectStub()
41
42try:
43 import java.lang #@UnresolvedImport
44except:
45 pass
46
47#types does not include a MethodWrapperType
48try:
49 MethodWrapperType = type([].__str__)
50except:
51 MethodWrapperType = None
52
53
54#=======================================================================================================================
55# AbstractResolver
56#=======================================================================================================================
57class AbstractResolver:
58 '''
59 This class exists only for documentation purposes to explain how to create a resolver.
60
61 Some examples on how to resolve things:
62 - list: getDictionary could return a dict with index->item and use the index to resolve it later
63 - set: getDictionary could return a dict with id(object)->object and reiterate in that array to resolve it later
64 - arbitrary instance: getDictionary could return dict with attr_name->attr and use getattr to resolve it later
65 '''
66
67 def resolve(self, var, attribute):
68 '''
69 In this method, we'll resolve some child item given the string representation of the item in the key
70 representing the previously asked dictionary.
71
72 @param var: this is the actual variable to be resolved.
73 @param attribute: this is the string representation of a key previously returned in getDictionary.
74 '''
75 raise NotImplementedError
76
77 def getDictionary(self, var):
78 '''
79 @param var: this is the variable that should have its children gotten.
80
81 @return: a dictionary where each pair key, value should be shown to the user as children items
82 in the variables view for the given var.
83 '''
84 raise NotImplementedError
85
86
87#=======================================================================================================================
88# DefaultResolver
89#=======================================================================================================================
90class DefaultResolver:
91 '''
92 DefaultResolver is the class that'll actually resolve how to show some variable.
93 '''
94
95 def resolve(self, var, attribute):
96 return getattr(var, attribute)
97
98 def getDictionary(self, var):
99 if MethodWrapperType:
100 return self._getPyDictionary(var)
101 else:
102 return self._getJyDictionary(var)
103
104 def _getJyDictionary(self, obj):
105 ret = {}
106 found = java.util.HashMap()
107
108 original = obj
109 if hasattr(obj, '__class__') and obj.__class__ == java.lang.Class:
110
111 #get info about superclasses
112 classes = []
113 classes.append(obj)
114 c = obj.getSuperclass()
115 while c != None:
116 classes.append(c)
117 c = c.getSuperclass()
118
119 #get info about interfaces
120 interfs = []
121 for obj in classes:
122 interfs.extend(obj.getInterfaces())
123 classes.extend(interfs)
124
125 #now is the time when we actually get info on the declared methods and fields
126 for obj in classes:
127
128 declaredMethods = obj.getDeclaredMethods()
129 declaredFields = obj.getDeclaredFields()
130 for i in range(len(declaredMethods)):
131 name = declaredMethods[i].getName()
132 ret[name] = declaredMethods[i].toString()
133 found.put(name, 1)
134
135 for i in range(len(declaredFields)):
136 name = declaredFields[i].getName()
137 found.put(name, 1)
138 #if declaredFields[i].isAccessible():
139 declaredFields[i].setAccessible(True)
140 #ret[name] = declaredFields[i].get( declaredFields[i] )
141 try:
142 ret[name] = declaredFields[i].get(original)
143 except:
144 ret[name] = declaredFields[i].toString()
145
146 #this simple dir does not always get all the info, that's why we have the part before
147 #(e.g.: if we do a dir on String, some methods that are from other interfaces such as
148 #charAt don't appear)
149 try:
150 d = dir(original)
151 for name in d:
152 if found.get(name) is not 1:
153 ret[name] = getattr(original, name)
154 except:
155 #sometimes we're unable to do a dir
156 pass
157
158 return ret
159
160 def _getPyDictionary(self, var):
161 filterPrivate = False
162 filterSpecial = True
163 filterFunction = True
164 filterBuiltIn = True
165
166 names = dir(var)
167 if not names and hasattr(var, '__members__'):
168 names = var.__members__
169 d = {}
170
171 #Be aware that the order in which the filters are applied attempts to
172 #optimize the operation by removing as many items as possible in the
173 #first filters, leaving fewer items for later filters
174
175 if filterBuiltIn or filterFunction:
176 for n in names:
177 if filterSpecial:
178 if n.startswith('__') and n.endswith('__'):
179 continue
180
181 if filterPrivate:
182 if n.startswith('_') or n.endswith('__'):
183 continue
184
185 try:
186 attr = getattr(var, n)
187
188 #filter builtins?
189 if filterBuiltIn:
190 if inspect.isbuiltin(attr):
191 continue
192
193 #filter functions?
194 if filterFunction:
195 if inspect.isroutine(attr) or isinstance(attr, MethodWrapperType):
196 continue
197 except:
198 #if some error occurs getting it, let's put it to the user.
199 strIO = StringIO.StringIO()
200 traceback.print_exc(file=strIO)
201 attr = strIO.getvalue()
202
203 d[ n ] = attr
204
205 return d
206
207
208#=======================================================================================================================
209# DictResolver
210#=======================================================================================================================
211class DictResolver:
212
213 def resolve(self, dict, key):
214 if key == '__len__':
215 return None
216
217 if '(' not in key:
218 #we have to treat that because the dict resolver is also used to directly resolve the global and local
219 #scopes (which already have the items directly)
220 return dict[key]
221
222 #ok, we have to iterate over the items to find the one that matches the id, because that's the only way
223 #to actually find the reference from the string we have before.
224 expected_id = int(key.split('(')[-1][:-1])
225 for key, val in dict.items():
226 if id(key) == expected_id:
227 return val
228
229 raise UnableToResolveVariableException()
230
231 def keyStr(self, key):
232 if isinstance(key, str):
233 return "'%s'"%key
234 else:
235 if not pydevd_constants.IS_PY3K:
236 if isinstance(key, unicode):
237 return "u'%s'"%key
238 return key
239
240 def getDictionary(self, dict):
241 ret = {}
242
243 for key, val in dict.items():
244 #we need to add the id because otherwise we cannot find the real object to get its contents later on.
245 key = '%s (%s)' % (self.keyStr(key), id(key))
246 ret[key] = val
247
248 ret['__len__'] = len(dict)
249 return ret
250
251
252
253#=======================================================================================================================
254# TupleResolver
255#=======================================================================================================================
256class TupleResolver: #to enumerate tuples and lists
257
258 def resolve(self, var, attribute):
259 '''
260 @param var: that's the original attribute
261 @param attribute: that's the key passed in the dict (as a string)
262 '''
263 if attribute == '__len__' or attribute == TOO_LARGE_ATTR:
264 return None
265 return var[int(attribute)]
266
267 def getDictionary(self, var):
268 #return dict( [ (i, x) for i, x in enumerate(var) ] )
269 # modified 'cause jython does not have enumerate support
270 l = len(var)
271 d = {}
272
273 if l < MAX_ITEMS_TO_HANDLE:
274 format = '%0' + str(int(len(str(l)))) + 'd'
275
276
277 for i, item in zip(range(l), var):
278 d[ format % i ] = item
279 else:
280 d[TOO_LARGE_ATTR] = TOO_LARGE_MSG
281 d['__len__'] = len(var)
282 return d
283
284
285
286#=======================================================================================================================
287# SetResolver
288#=======================================================================================================================
289class SetResolver:
290 '''
291 Resolves a set as dict id(object)->object
292 '''
293
294 def resolve(self, var, attribute):
295 if attribute == '__len__':
296 return None
297
298 attribute = int(attribute)
299 for v in var:
300 if id(v) == attribute:
301 return v
302
303 raise UnableToResolveVariableException('Unable to resolve %s in %s' % (attribute, var))
304
305 def getDictionary(self, var):
306 d = {}
307 for item in var:
308 d[ id(item) ] = item
309 d['__len__'] = len(var)
310 return d
311
312
313#=======================================================================================================================
314# InstanceResolver
315#=======================================================================================================================
316class InstanceResolver:
317
318 def resolve(self, var, attribute):
319 field = var.__class__.getDeclaredField(attribute)
320 field.setAccessible(True)
321 return field.get(var)
322
323 def getDictionary(self, obj):
324 ret = {}
325
326 declaredFields = obj.__class__.getDeclaredFields()
327 for i in range(len(declaredFields)):
328 name = declaredFields[i].getName()
329 try:
330 declaredFields[i].setAccessible(True)
331 ret[name] = declaredFields[i].get(obj)
332 except:
333 traceback.print_exc()
334
335 return ret
336
337
338#=======================================================================================================================
339# JyArrayResolver
340#=======================================================================================================================
341class JyArrayResolver:
342 '''
343 This resolves a regular Object[] array from java
344 '''
345
346 def resolve(self, var, attribute):
347 if attribute == '__len__':
348 return None
349 return var[int(attribute)]
350
351 def getDictionary(self, obj):
352 ret = {}
353
354 for i in range(len(obj)):
355 ret[ i ] = obj[i]
356
357 ret['__len__'] = len(obj)
358 return ret
359
360defaultResolver = DefaultResolver()
361dictResolver = DictResolver()
362tupleResolver = TupleResolver()
363instanceResolver = InstanceResolver()
364jyArrayResolver = JyArrayResolver()
365setResolver = SetResolver()