blob: 3baea5b61b99f97f6a1b45889fae788d624458c5 [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001""" pydevd_vars deals with variables:
2 resolution/conversion to XML.
3"""
4import pickle
5from django_frame import DjangoTemplateFrame
Tor Norbyec3d3a902014-09-04 13:24:04 -07006from pydevd_constants import * #@UnusedWildImport
Tor Norbye3a2425a2013-11-04 10:16:08 -08007from types import * #@UnusedWildImport
8
Tor Norbyec667c1f2014-05-28 17:06:51 -07009from pydevd_custom_frames import getCustomFrame
Tor Norbye3a2425a2013-11-04 10:16:08 -080010from pydevd_xml import *
Tor Norbyec3d3a902014-09-04 13:24:04 -070011from _pydev_imps import _pydev_thread
Tor Norbye3a2425a2013-11-04 10:16:08 -080012
13try:
14 from StringIO import StringIO
15except ImportError:
16 from io import StringIO
17import sys #@Reimport
18
Tor Norbyec3d3a902014-09-04 13:24:04 -070019import _pydev_threading as threading
Tor Norbye3a2425a2013-11-04 10:16:08 -080020import traceback
Tor Norbyec667c1f2014-05-28 17:06:51 -070021import pydevd_save_locals
Tor Norbyec3d3a902014-09-04 13:24:04 -070022from pydev_imports import Exec, quote, execfile
Tor Norbye3a2425a2013-11-04 10:16:08 -080023
24try:
Tor Norbyec667c1f2014-05-28 17:06:51 -070025 import types
26 frame_type = types.FrameType
Tor Norbye3a2425a2013-11-04 10:16:08 -080027except:
Tor Norbye1aa2e092014-08-20 17:01:23 -070028 frame_type = type(sys._getframe())
Tor Norbyec667c1f2014-05-28 17:06:51 -070029
Tor Norbye3a2425a2013-11-04 10:16:08 -080030
31#-------------------------------------------------------------------------- defining true and false for earlier versions
32
33try:
34 __setFalse = False
35except:
36 import __builtin__
Tor Norbye3a2425a2013-11-04 10:16:08 -080037 setattr(__builtin__, 'True', 1)
38 setattr(__builtin__, 'False', 0)
39
40#------------------------------------------------------------------------------------------------------ class for errors
41
Tor Norbye1aa2e092014-08-20 17:01:23 -070042class VariableError(RuntimeError):pass
Tor Norbye3a2425a2013-11-04 10:16:08 -080043
Tor Norbye1aa2e092014-08-20 17:01:23 -070044class FrameNotFoundError(RuntimeError):pass
Tor Norbye3a2425a2013-11-04 10:16:08 -080045
46def iterFrames(initialFrame):
Tor Norbyec667c1f2014-05-28 17:06:51 -070047 '''NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)'''
Tor Norbye3a2425a2013-11-04 10:16:08 -080048 #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
57def 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#===============================================================================
70class AdditionalFramesContainer:
Tor Norbyec3d3a902014-09-04 13:24:04 -070071 lock = _pydev_thread.allocate_lock()
Tor Norbye3a2425a2013-11-04 10:16:08 -080072 additional_frames = {} #dict of dicts
73
74
75def addAdditionalFrameById(thread_id, frames_by_id):
76 AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id
77
78
79def removeAdditionalFrameById(thread_id):
80 del AdditionalFramesContainer.additional_frames[thread_id]
81
82
83
Tor Norbyec667c1f2014-05-28 17:06:51 -070084
Tor Norbye3a2425a2013-11-04 10:16:08 -080085def findFrame(thread_id, frame_id):
86 """ returns a frame on the thread that has a given frame_id """
Tor Norbyec667c1f2014-05-28 17:06:51 -070087 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
Tor Norbye3a2425a2013-11-04 10:16:08 -080094
Tor Norbyec667c1f2014-05-28 17:06:51 -070095 raise VariableError("findFrame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id))
Tor Norbye3a2425a2013-11-04 10:16:08 -080096
Tor Norbyec667c1f2014-05-28 17:06:51 -070097 lookingFor = int(frame_id)
Tor Norbye3a2425a2013-11-04 10:16:08 -080098
Tor Norbyec667c1f2014-05-28 17:06:51 -070099 if AdditionalFramesContainer.additional_frames:
100 if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
101 frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800102
Tor Norbyec667c1f2014-05-28 17:06:51 -0700103 if frame is not None:
104 return frame
Tor Norbye3a2425a2013-11-04 10:16:08 -0800105
Tor Norbyec667c1f2014-05-28 17:06:51 -0700106 curFrame = GetFrame()
107 if frame_id == "*":
108 return curFrame # any frame is specified with "*"
Tor Norbye3a2425a2013-11-04 10:16:08 -0800109
Tor Norbyec667c1f2014-05-28 17:06:51 -0700110 frameFound = None
111
112 for frame in iterFrames(curFrame):
113 if lookingFor == id(frame):
114 frameFound = frame
115 del frame
116 break
117
Tor Norbye3a2425a2013-11-04 10:16:08 -0800118 del frame
Tor Norbye3a2425a2013-11-04 10:16:08 -0800119
Tor Norbyec667c1f2014-05-28 17:06:51 -0700120 #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.
Tor Norbye3a2425a2013-11-04 10:16:08 -0800123
Tor Norbyec667c1f2014-05-28 17:06:51 -0700124 #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
Tor Norbye3a2425a2013-11-04 10:16:08 -0800127
Tor Norbyec667c1f2014-05-28 17:06:51 -0700128 if frameFound is None:
129 msgFrames = ''
130 i = 0
Tor Norbye3a2425a2013-11-04 10:16:08 -0800131
Tor Norbyec667c1f2014-05-28 17:06:51 -0700132 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 += ' - '
Tor Norbye3a2425a2013-11-04 10:16:08 -0800139
Tor Norbyec667c1f2014-05-28 17:06:51 -0700140 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)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800145
Tor Norbyec667c1f2014-05-28 17:06:51 -0700146 sys.stderr.write(errMsg)
147 return None
Tor Norbye3a2425a2013-11-04 10:16:08 -0800148
Tor Norbyec667c1f2014-05-28 17:06:51 -0700149 return frameFound
150 except:
151 import traceback
152 traceback.print_exc()
Tor Norbye3a2425a2013-11-04 10:16:08 -0800153 return None
154
Tor Norbye1aa2e092014-08-20 17:01:23 -0700155def 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
Tor Norbye3a2425a2013-11-04 10:16:08 -0800194 frame = findFrame(thread_id, frame_id)
195 if frame is None:
196 return {}
197
Tor Norbye1aa2e092014-08-20 17:01:23 -0700198 if attrs is not None:
199 attrList = attrs.split('\t')
Tor Norbye3a2425a2013-11-04 10:16:08 -0800200 else:
Tor Norbye1aa2e092014-08-20 17:01:23 -0700201 attrList = []
Tor Norbye3a2425a2013-11-04 10:16:08 -0800202
Tor Norbye1aa2e092014-08-20 17:01:23 -0700203 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
225def 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)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800229
230 try:
Tor Norbye1aa2e092014-08-20 17:01:23 -0700231 _type, _typeName, resolver = getType(var)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800232 return resolver.getDictionary(var)
233 except:
Tor Norbye1aa2e092014-08-20 17:01:23 -0700234 sys.stderr.write('Error evaluating: thread_id: %s\nframe_id: %s\nscope: %s\nattrs: %s\n' % (
235 thread_id, frame_id, scope, attrs,))
Tor Norbye3a2425a2013-11-04 10:16:08 -0800236 traceback.print_exc()
Tor Norbye1aa2e092014-08-20 17:01:23 -0700237
238
Tor Norbye3a2425a2013-11-04 10:16:08 -0800239def resolveVar(var, attrs):
240 attrList = attrs.split('\t')
Tor Norbye1aa2e092014-08-20 17:01:23 -0700241
Tor Norbye3a2425a2013-11-04 10:16:08 -0800242 for k in attrList:
243 type, _typeName, resolver = getType(var)
Tor Norbye1aa2e092014-08-20 17:01:23 -0700244
Tor Norbye3a2425a2013-11-04 10:16:08 -0800245 var = resolver.resolve(var, k)
Tor Norbye1aa2e092014-08-20 17:01:23 -0700246
Tor Norbye3a2425a2013-11-04 10:16:08 -0800247 try:
248 type, _typeName, resolver = getType(var)
249 return resolver.getDictionary(var)
250 except:
251 traceback.print_exc()
Tor Norbye1aa2e092014-08-20 17:01:23 -0700252
253
254def 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
Tor Norbye3a2425a2013-11-04 10:16:08 -0800276
277def evaluateExpression(thread_id, frame_id, expression, doExec):
Tor Norbyec667c1f2014-05-28 17:06:51 -0700278 '''returns the result of the evaluated expression
Tor Norbye3a2425a2013-11-04 10:16:08 -0800279 @param doExec: determines if we should do an exec or an eval
Tor Norbyec667c1f2014-05-28 17:06:51 -0700280 '''
Tor Norbye3a2425a2013-11-04 10:16:08 -0800281 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)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700293 updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
Tor Norbye3a2425a2013-11-04 10:16:08 -0800294
295 try:
Tor Norbye1aa2e092014-08-20 17:01:23 -0700296
Tor Norbye3a2425a2013-11-04 10:16:08 -0800297 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)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700304 pydevd_save_locals.save_locals(frame)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800305 else:
306 result = eval(compiled, updated_globals, frame.f_locals)
Tor Norbye1aa2e092014-08-20 17:01:23 -0700307 if result is not None: #Only print if it's not None (as python does)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800308 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)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800318 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
Tor Norbye1aa2e092014-08-20 17:01:23 -0700331 # 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
Tor Norbye3a2425a2013-11-04 10:16:08 -0800347 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
353def changeAttrExpression(thread_id, frame_id, attr, expression):
Tor Norbyec667c1f2014-05-28 17:06:51 -0700354 '''Changes some attribute in a given frame.
Tor Norbyec667c1f2014-05-28 17:06:51 -0700355 '''
Tor Norbye3a2425a2013-11-04 10:16:08 -0800356 frame = findFrame(thread_id, frame_id)
357 if frame is None:
358 return
359
Tor Norbye3a2425a2013-11-04 10:16:08 -0800360 try:
361 expression = expression.replace('@LINE@', '\n')
Tor Norbyec667c1f2014-05-28 17:06:51 -0700362
Tor Norbye1aa2e092014-08-20 17:01:23 -0700363 if isinstance(frame, DjangoTemplateFrame):
364 result = eval(expression, frame.f_globals, frame.f_locals)
365 frame.changeVariable(attr, result)
366 return
Tor Norbye3a2425a2013-11-04 10:16:08 -0800367
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:
Tor Norbyec667c1f2014-05-28 17:06:51 -0700374 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
Tor Norbye3a2425a2013-11-04 10:16:08 -0800379 #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