Windows 64-bit launcher looks for bundled jre in both jre and jre64 folders
[idea/community.git] / python / helpers / pydev / pydevd_vars.py
1 """ pydevd_vars deals with variables:
2     resolution/conversion to XML.
3 """
4 import pickle
5 from django_frame import DjangoTemplateFrame
6 from pydevd_constants import * #@UnusedWildImport
7 from types import * #@UnusedWildImport
8
9 from pydevd_custom_frames import getCustomFrame
10 from pydevd_xml import *
11 from _pydev_imps import _pydev_thread
12
13 try:
14     from StringIO import StringIO
15 except ImportError:
16     from io import StringIO
17 import sys #@Reimport
18
19 import _pydev_threading as threading
20 import traceback
21 import pydevd_save_locals
22 from pydev_imports import Exec, quote, execfile
23
24 try:
25     import types
26     frame_type = types.FrameType
27 except:
28     frame_type = type(sys._getframe())
29
30
31 #-------------------------------------------------------------------------- defining true and false for earlier versions
32
33 try:
34     __setFalse = False
35 except:
36     import __builtin__
37     setattr(__builtin__, 'True', 1)
38     setattr(__builtin__, 'False', 0)
39
40 #------------------------------------------------------------------------------------------------------ class for errors
41
42 class VariableError(RuntimeError):pass
43
44 class FrameNotFoundError(RuntimeError):pass
45
46 def iterFrames(initialFrame):
47     '''NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)'''
48     #cannot use yield
49     frames = []
50
51     while initialFrame is not None:
52         frames.append(initialFrame)
53         initialFrame = initialFrame.f_back
54
55     return frames
56
57 def dumpFrames(thread_id):
58     sys.stdout.write('dumping frames\n')
59     if thread_id != GetThreadId(threading.currentThread()):
60         raise VariableError("findFrame: must execute on same thread")
61
62     curFrame = GetFrame()
63     for frame in iterFrames(curFrame):
64         sys.stdout.write('%s\n' % pickle.dumps(frame))
65
66
67 #===============================================================================
68 # AdditionalFramesContainer
69 #===============================================================================
70 class AdditionalFramesContainer:
71     lock = _pydev_thread.allocate_lock()
72     additional_frames = {} #dict of dicts
73
74
75 def addAdditionalFrameById(thread_id, frames_by_id):
76     AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id
77
78
79 def removeAdditionalFrameById(thread_id):
80     del AdditionalFramesContainer.additional_frames[thread_id]
81
82
83
84
85 def findFrame(thread_id, frame_id):
86     """ returns a frame on the thread that has a given frame_id """
87     try:
88         curr_thread_id = GetThreadId(threading.currentThread())
89         if thread_id != curr_thread_id :
90             try:
91                 return getCustomFrame(thread_id, frame_id)  #I.e.: thread_id could be a stackless frame id + thread_id.
92             except:
93                 pass
94
95             raise VariableError("findFrame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id))
96
97         lookingFor = int(frame_id)
98
99         if AdditionalFramesContainer.additional_frames:
100             if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
101                 frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
102
103                 if frame is not None:
104                     return frame
105
106         curFrame = GetFrame()
107         if frame_id == "*":
108             return curFrame  # any frame is specified with "*"
109
110         frameFound = None
111
112         for frame in iterFrames(curFrame):
113             if lookingFor == id(frame):
114                 frameFound = frame
115                 del frame
116                 break
117
118             del frame
119
120         #Important: python can hold a reference to the frame from the current context
121         #if an exception is raised, so, if we don't explicitly add those deletes
122         #we might have those variables living much more than we'd want to.
123
124         #I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
125         #need to call sys.exc_clear())
126         del curFrame
127
128         if frameFound is None:
129             msgFrames = ''
130             i = 0
131
132             for frame in iterFrames(GetFrame()):
133                 i += 1
134                 msgFrames += str(id(frame))
135                 if i % 5 == 0:
136                     msgFrames += '\n'
137                 else:
138                     msgFrames += '  -  '
139
140             errMsg = '''findFrame: frame not found.
141     Looking for thread_id:%s, frame_id:%s
142     Current     thread_id:%s, available frames:
143     %s\n
144     ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
145
146             sys.stderr.write(errMsg)
147             return None
148
149         return frameFound
150     except:
151         import traceback
152         traceback.print_exc()
153         return None
154
155 def getVariable(thread_id, frame_id, scope, attrs):
156     """
157     returns the value of a variable
158
159     :scope: can be BY_ID, EXPRESSION, GLOBAL, LOCAL, FRAME
160
161     BY_ID means we'll traverse the list of all objects alive to get the object.
162
163     :attrs: after reaching the proper scope, we have to get the attributes until we find
164             the proper location (i.e.: obj\tattr1\tattr2)
165
166     :note: when BY_ID is used, the frame_id is considered the id of the object to find and
167            not the frame (as we don't care about the frame in this case).
168     """
169     if scope == 'BY_ID':
170         if thread_id != GetThreadId(threading.currentThread()) :
171             raise VariableError("getVariable: must execute on same thread")
172
173         try:
174             import gc
175             objects = gc.get_objects()
176         except:
177             pass  #Not all python variants have it.
178         else:
179             frame_id = int(frame_id)
180             for var in objects:
181                 if id(var) == frame_id:
182                     if attrs is not None:
183                         attrList = attrs.split('\t')
184                         for k in attrList:
185                             _type, _typeName, resolver = getType(var)
186                             var = resolver.resolve(var, k)
187
188                     return var
189
190         #If it didn't return previously, we coudn't find it by id (i.e.: alrceady garbage collected).
191         sys.stderr.write('Unable to find object with id: %s\n' % (frame_id,))
192         return None
193
194     frame = findFrame(thread_id, frame_id)
195     if frame is None:
196         return {}
197
198     if attrs is not None:
199         attrList = attrs.split('\t')
200     else:
201         attrList = []
202
203     if scope == 'EXPRESSION':
204         for count in xrange(len(attrList)):
205             if count == 0:
206                 # An Expression can be in any scope (globals/locals), therefore it needs to evaluated as an expression
207                 var = evaluateExpression(thread_id, frame_id, attrList[count], False)
208             else:
209                 _type, _typeName, resolver = getType(var)
210                 var = resolver.resolve(var, attrList[count])
211     else:
212         if scope == "GLOBAL":
213             var = frame.f_globals
214             del attrList[0]  # globals are special, and they get a single dummy unused attribute
215         else:
216             var = frame.f_locals
217
218         for k in attrList:
219             _type, _typeName, resolver = getType(var)
220             var = resolver.resolve(var, k)
221
222     return var
223
224
225 def resolveCompoundVariable(thread_id, frame_id, scope, attrs):
226     """ returns the value of the compound variable as a dictionary"""
227
228     var = getVariable(thread_id, frame_id, scope, attrs)
229
230     try:
231         _type, _typeName, resolver = getType(var)
232         return resolver.getDictionary(var)
233     except:
234         sys.stderr.write('Error evaluating: thread_id: %s\nframe_id: %s\nscope: %s\nattrs: %s\n' % (
235             thread_id, frame_id, scope, attrs,))
236         traceback.print_exc()
237
238
239 def resolveVar(var, attrs):
240     attrList = attrs.split('\t')
241
242     for k in attrList:
243         type, _typeName, resolver = getType(var)
244
245         var = resolver.resolve(var, k)
246
247     try:
248         type, _typeName, resolver = getType(var)
249         return resolver.getDictionary(var)
250     except:
251         traceback.print_exc()
252
253
254 def customOperation(thread_id, frame_id, scope, attrs, style, code_or_file, operation_fn_name):
255     """
256     We'll execute the code_or_file and then search in the namespace the operation_fn_name to execute with the given var.
257
258     code_or_file: either some code (i.e.: from pprint import pprint) or a file to be executed.
259     operation_fn_name: the name of the operation to execute after the exec (i.e.: pprint)
260     """
261     expressionValue = getVariable(thread_id, frame_id, scope, attrs)
262
263     try:
264         namespace = {'__name__': '<customOperation>'}
265         if style == "EXECFILE":
266             namespace['__file__'] = code_or_file
267             execfile(code_or_file, namespace, namespace)
268         else:  # style == EXEC
269             namespace['__file__'] = '<customOperationCode>'
270             Exec(code_or_file, namespace, namespace)
271
272         return str(namespace[operation_fn_name](expressionValue))
273     except:
274         traceback.print_exc()
275
276
277 def evaluateExpression(thread_id, frame_id, expression, doExec):
278     '''returns the result of the evaluated expression
279     @param doExec: determines if we should do an exec or an eval
280     '''
281     frame = findFrame(thread_id, frame_id)
282     if frame is None:
283         return
284
285     expression = str(expression.replace('@LINE@', '\n'))
286
287
288     #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
289     #(Names not resolved in generator expression in method)
290     #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
291     updated_globals = {}
292     updated_globals.update(frame.f_globals)
293     updated_globals.update(frame.f_locals)  #locals later because it has precedence over the actual globals
294
295     try:
296
297         if doExec:
298             try:
299                 #try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
300                 #it will have whatever the user actually did)
301                 compiled = compile(expression, '<string>', 'eval')
302             except:
303                 Exec(expression, updated_globals, frame.f_locals)
304                 pydevd_save_locals.save_locals(frame)
305             else:
306                 result = eval(compiled, updated_globals, frame.f_locals)
307                 if result is not None:  #Only print if it's not None (as python does)
308                     sys.stdout.write('%s\n' % (result,))
309             return
310
311         else:
312             result = None
313             try:
314                 result = eval(expression, updated_globals, frame.f_locals)
315             except Exception:
316                 s = StringIO()
317                 traceback.print_exc(file=s)
318                 result = s.getvalue()
319
320                 try:
321                     try:
322                         etype, value, tb = sys.exc_info()
323                         result = value
324                     finally:
325                         etype = value = tb = None
326                 except:
327                     pass
328
329                 result = ExceptionOnEvaluate(result)
330
331                 # Ok, we have the initial error message, but let's see if we're dealing with a name mangling error...
332                 try:
333                     if '__' in expression:
334                         # Try to handle '__' name mangling...
335                         split = expression.split('.')
336                         curr = frame.f_locals.get(split[0])
337                         for entry in split[1:]:
338                             if entry.startswith('__') and not hasattr(curr, entry):
339                                 entry = '_%s%s' % (curr.__class__.__name__, entry)
340                             curr = getattr(curr, entry)
341
342                         result = curr
343                 except:
344                     pass
345
346
347             return result
348     finally:
349         #Should not be kept alive if an exception happens and this frame is kept in the stack.
350         del updated_globals
351         del frame
352
353 def changeAttrExpression(thread_id, frame_id, attr, expression):
354     '''Changes some attribute in a given frame.
355     '''
356     frame = findFrame(thread_id, frame_id)
357     if frame is None:
358         return
359
360     try:
361         expression = expression.replace('@LINE@', '\n')
362
363         if isinstance(frame, DjangoTemplateFrame):
364             result = eval(expression, frame.f_globals, frame.f_locals)
365             frame.changeVariable(attr, result)
366             return
367
368         if attr[:7] == "Globals":
369             attr = attr[8:]
370             if attr in frame.f_globals:
371                 frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
372                 return frame.f_globals[attr]
373         else:
374             if pydevd_save_locals.is_save_locals_available():
375                 frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
376                 pydevd_save_locals.save_locals(frame)
377                 return
378
379             #default way (only works for changing it in the topmost frame)
380             result = eval(expression, frame.f_globals, frame.f_locals)
381             Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
382             return result
383
384
385     except Exception:
386         traceback.print_exc()
387
388
389
390
391