blob: de8c2415fcae82f929a4093129e560f77e0a46c7 [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
6from pydevd_constants import * #@UnusedWildImport
7from 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 *
11
12try:
13 from StringIO import StringIO
14except ImportError:
15 from io import StringIO
16import sys #@Reimport
17
18if USE_LIB_COPY:
19 import _pydev_threading as threading
20else:
21 import threading
22import pydevd_resolver
23import traceback
Tor Norbyec667c1f2014-05-28 17:06:51 -070024import pydevd_save_locals
25from pydev_imports import Exec, quote, execfile
Tor Norbye3a2425a2013-11-04 10:16:08 -080026
27try:
Tor Norbyec667c1f2014-05-28 17:06:51 -070028 import types
29 frame_type = types.FrameType
Tor Norbye3a2425a2013-11-04 10:16:08 -080030except:
Tor Norbyec667c1f2014-05-28 17:06:51 -070031 frame_type = None
32
Tor Norbye3a2425a2013-11-04 10:16:08 -080033
34#-------------------------------------------------------------------------- defining true and false for earlier versions
35
36try:
37 __setFalse = False
38except:
39 import __builtin__
40
41 setattr(__builtin__, 'True', 1)
42 setattr(__builtin__, 'False', 0)
43
44#------------------------------------------------------------------------------------------------------ class for errors
45
46class VariableError(RuntimeError): pass
47
48class FrameNotFoundError(RuntimeError): pass
49
50
51if USE_PSYCO_OPTIMIZATION:
52 try:
53 import psyco
54
55 varToXML = psyco.proxy(varToXML)
56 except ImportError:
57 if hasattr(sys, 'exc_clear'): #jython does not have it
58 sys.exc_clear() #don't keep the traceback -- clients don't want to see it
59
60def iterFrames(initialFrame):
Tor Norbyec667c1f2014-05-28 17:06:51 -070061 '''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 -080062 #cannot use yield
63 frames = []
64
65 while initialFrame is not None:
66 frames.append(initialFrame)
67 initialFrame = initialFrame.f_back
68
69 return frames
70
71def dumpFrames(thread_id):
72 sys.stdout.write('dumping frames\n')
73 if thread_id != GetThreadId(threading.currentThread()):
74 raise VariableError("findFrame: must execute on same thread")
75
76 curFrame = GetFrame()
77 for frame in iterFrames(curFrame):
78 sys.stdout.write('%s\n' % pickle.dumps(frame))
79
80
81#===============================================================================
82# AdditionalFramesContainer
83#===============================================================================
84class AdditionalFramesContainer:
85 lock = threading.Lock()
86 additional_frames = {} #dict of dicts
87
88
89def addAdditionalFrameById(thread_id, frames_by_id):
90 AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id
91
92
93def removeAdditionalFrameById(thread_id):
94 del AdditionalFramesContainer.additional_frames[thread_id]
95
96
97
Tor Norbyec667c1f2014-05-28 17:06:51 -070098
Tor Norbye3a2425a2013-11-04 10:16:08 -080099def findFrame(thread_id, frame_id):
100 """ returns a frame on the thread that has a given frame_id """
Tor Norbyec667c1f2014-05-28 17:06:51 -0700101 try:
102 curr_thread_id = GetThreadId(threading.currentThread())
103 if thread_id != curr_thread_id :
104 try:
105 return getCustomFrame(thread_id, frame_id) #I.e.: thread_id could be a stackless frame id + thread_id.
106 except:
107 pass
Tor Norbye3a2425a2013-11-04 10:16:08 -0800108
Tor Norbyec667c1f2014-05-28 17:06:51 -0700109 raise VariableError("findFrame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id))
Tor Norbye3a2425a2013-11-04 10:16:08 -0800110
Tor Norbyec667c1f2014-05-28 17:06:51 -0700111 lookingFor = int(frame_id)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800112
Tor Norbyec667c1f2014-05-28 17:06:51 -0700113 if AdditionalFramesContainer.additional_frames:
114 if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
115 frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800116
Tor Norbyec667c1f2014-05-28 17:06:51 -0700117 if frame is not None:
118 return frame
Tor Norbye3a2425a2013-11-04 10:16:08 -0800119
Tor Norbyec667c1f2014-05-28 17:06:51 -0700120 curFrame = GetFrame()
121 if frame_id == "*":
122 return curFrame # any frame is specified with "*"
Tor Norbye3a2425a2013-11-04 10:16:08 -0800123
Tor Norbyec667c1f2014-05-28 17:06:51 -0700124 frameFound = None
125
126 for frame in iterFrames(curFrame):
127 if lookingFor == id(frame):
128 frameFound = frame
129 del frame
130 break
131
Tor Norbye3a2425a2013-11-04 10:16:08 -0800132 del frame
Tor Norbye3a2425a2013-11-04 10:16:08 -0800133
Tor Norbyec667c1f2014-05-28 17:06:51 -0700134 #Important: python can hold a reference to the frame from the current context
135 #if an exception is raised, so, if we don't explicitly add those deletes
136 #we might have those variables living much more than we'd want to.
Tor Norbye3a2425a2013-11-04 10:16:08 -0800137
Tor Norbyec667c1f2014-05-28 17:06:51 -0700138 #I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
139 #need to call sys.exc_clear())
140 del curFrame
Tor Norbye3a2425a2013-11-04 10:16:08 -0800141
Tor Norbyec667c1f2014-05-28 17:06:51 -0700142 if frameFound is None:
143 msgFrames = ''
144 i = 0
Tor Norbye3a2425a2013-11-04 10:16:08 -0800145
Tor Norbyec667c1f2014-05-28 17:06:51 -0700146 for frame in iterFrames(GetFrame()):
147 i += 1
148 msgFrames += str(id(frame))
149 if i % 5 == 0:
150 msgFrames += '\n'
151 else:
152 msgFrames += ' - '
Tor Norbye3a2425a2013-11-04 10:16:08 -0800153
Tor Norbyec667c1f2014-05-28 17:06:51 -0700154 errMsg = '''findFrame: frame not found.
155 Looking for thread_id:%s, frame_id:%s
156 Current thread_id:%s, available frames:
157 %s\n
158 ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800159
Tor Norbyec667c1f2014-05-28 17:06:51 -0700160 sys.stderr.write(errMsg)
161 return None
Tor Norbye3a2425a2013-11-04 10:16:08 -0800162
Tor Norbyec667c1f2014-05-28 17:06:51 -0700163 return frameFound
164 except:
165 import traceback
166 traceback.print_exc()
Tor Norbye3a2425a2013-11-04 10:16:08 -0800167 return None
168
Tor Norbye3a2425a2013-11-04 10:16:08 -0800169def resolveCompoundVariable(thread_id, frame_id, scope, attrs):
170 """ returns the value of the compound variable as a dictionary"""
171 frame = findFrame(thread_id, frame_id)
172 if frame is None:
173 return {}
174
175 attrList = attrs.split('\t')
176
177 if scope == "GLOBAL":
178 var = frame.f_globals
179 del attrList[0] # globals are special, and they get a single dummy unused attribute
180 else:
181 var = frame.f_locals
182 type, _typeName, resolver = getType(var)
183 try:
184 resolver.resolve(var, attrList[0])
185 except:
186 var = frame.f_globals
187
188 for k in attrList:
189 type, _typeName, resolver = getType(var)
190 var = resolver.resolve(var, k)
191
192 try:
193 type, _typeName, resolver = getType(var)
194 return resolver.getDictionary(var)
195 except:
196 traceback.print_exc()
197
198
199def resolveVar(var, attrs):
200 attrList = attrs.split('\t')
201
202 for k in attrList:
203 type, _typeName, resolver = getType(var)
204
205 var = resolver.resolve(var, k)
206
207 try:
208 type, _typeName, resolver = getType(var)
209 return resolver.getDictionary(var)
210 except:
211 traceback.print_exc()
212
213
214def evaluateExpression(thread_id, frame_id, expression, doExec):
Tor Norbyec667c1f2014-05-28 17:06:51 -0700215 '''returns the result of the evaluated expression
Tor Norbye3a2425a2013-11-04 10:16:08 -0800216 @param doExec: determines if we should do an exec or an eval
Tor Norbyec667c1f2014-05-28 17:06:51 -0700217 '''
Tor Norbye3a2425a2013-11-04 10:16:08 -0800218 frame = findFrame(thread_id, frame_id)
219 if frame is None:
220 return
221
222 expression = str(expression.replace('@LINE@', '\n'))
223
224
225 #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
226 #(Names not resolved in generator expression in method)
227 #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
228 updated_globals = {}
229 updated_globals.update(frame.f_globals)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700230 updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
Tor Norbye3a2425a2013-11-04 10:16:08 -0800231
232 try:
233 if doExec:
234 try:
235 #try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
236 #it will have whatever the user actually did)
237 compiled = compile(expression, '<string>', 'eval')
238 except:
239 Exec(expression, updated_globals, frame.f_locals)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700240 pydevd_save_locals.save_locals(frame)
Tor Norbye3a2425a2013-11-04 10:16:08 -0800241 else:
242 result = eval(compiled, updated_globals, frame.f_locals)
243 if result is not None: #Only print if it's not None (as python does)
244 sys.stdout.write('%s\n' % (result,))
245 return
246
247 else:
248 result = None
249 try:
250 result = eval(expression, updated_globals, frame.f_locals)
251 except Exception:
252 s = StringIO()
253 traceback.print_exc(file=s)
254
255 result = s.getvalue()
256
257 try:
258 try:
259 etype, value, tb = sys.exc_info()
260 result = value
261 finally:
262 etype = value = tb = None
263 except:
264 pass
265
266 result = ExceptionOnEvaluate(result)
267
268 return result
269 finally:
270 #Should not be kept alive if an exception happens and this frame is kept in the stack.
271 del updated_globals
272 del frame
273
274def changeAttrExpression(thread_id, frame_id, attr, expression):
Tor Norbyec667c1f2014-05-28 17:06:51 -0700275 '''Changes some attribute in a given frame.
Tor Norbye3a2425a2013-11-04 10:16:08 -0800276 @note: it will not (currently) work if we're not in the topmost frame (that's a python
277 deficiency -- and it appears that there is no way of making it currently work --
278 will probably need some change to the python internals)
Tor Norbyec667c1f2014-05-28 17:06:51 -0700279 '''
Tor Norbye3a2425a2013-11-04 10:16:08 -0800280 frame = findFrame(thread_id, frame_id)
281 if frame is None:
282 return
283
284 if isinstance(frame, DjangoTemplateFrame):
285 result = eval(expression, frame.f_globals, frame.f_locals)
286 frame.changeVariable(attr, result)
287
288 try:
289 expression = expression.replace('@LINE@', '\n')
Tor Norbyec667c1f2014-05-28 17:06:51 -0700290
Tor Norbye3a2425a2013-11-04 10:16:08 -0800291
292
293 if attr[:7] == "Globals":
294 attr = attr[8:]
295 if attr in frame.f_globals:
296 frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
297 return frame.f_globals[attr]
298 else:
Tor Norbyec667c1f2014-05-28 17:06:51 -0700299 if pydevd_save_locals.is_save_locals_available():
300 frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
301 pydevd_save_locals.save_locals(frame)
302 return
303
Tor Norbye3a2425a2013-11-04 10:16:08 -0800304 #default way (only works for changing it in the topmost frame)
305 result = eval(expression, frame.f_globals, frame.f_locals)
306 Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
307 return result
308
309
310 except Exception:
311 traceback.print_exc()
312
313
314
315
316