| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 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 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 9 | from pydevd_custom_frames import getCustomFrame |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 10 | from pydevd_xml import * |
| 11 | |
| 12 | try: |
| 13 | from StringIO import StringIO |
| 14 | except ImportError: |
| 15 | from io import StringIO |
| 16 | import sys #@Reimport |
| 17 | |
| 18 | if USE_LIB_COPY: |
| 19 | import _pydev_threading as threading |
| 20 | else: |
| 21 | import threading |
| 22 | import pydevd_resolver |
| 23 | import traceback |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 24 | import pydevd_save_locals |
| 25 | from pydev_imports import Exec, quote, execfile |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 26 | |
| 27 | try: |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 28 | import types |
| 29 | frame_type = types.FrameType |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 30 | except: |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 31 | frame_type = None |
| 32 | |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 33 | |
| 34 | #-------------------------------------------------------------------------- defining true and false for earlier versions |
| 35 | |
| 36 | try: |
| 37 | __setFalse = False |
| 38 | except: |
| 39 | import __builtin__ |
| 40 | |
| 41 | setattr(__builtin__, 'True', 1) |
| 42 | setattr(__builtin__, 'False', 0) |
| 43 | |
| 44 | #------------------------------------------------------------------------------------------------------ class for errors |
| 45 | |
| 46 | class VariableError(RuntimeError): pass |
| 47 | |
| 48 | class FrameNotFoundError(RuntimeError): pass |
| 49 | |
| 50 | |
| 51 | if 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 | |
| 60 | def iterFrames(initialFrame): |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 61 | '''NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)''' |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 62 | #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 | |
| 71 | def 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 | #=============================================================================== |
| 84 | class AdditionalFramesContainer: |
| 85 | lock = threading.Lock() |
| 86 | additional_frames = {} #dict of dicts |
| 87 | |
| 88 | |
| 89 | def addAdditionalFrameById(thread_id, frames_by_id): |
| 90 | AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id |
| 91 | |
| 92 | |
| 93 | def removeAdditionalFrameById(thread_id): |
| 94 | del AdditionalFramesContainer.additional_frames[thread_id] |
| 95 | |
| 96 | |
| 97 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 98 | |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 99 | def findFrame(thread_id, frame_id): |
| 100 | """ returns a frame on the thread that has a given frame_id """ |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 101 | 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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 108 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 109 | raise VariableError("findFrame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id)) |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 110 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 111 | lookingFor = int(frame_id) |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 112 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 113 | if AdditionalFramesContainer.additional_frames: |
| 114 | if DictContains(AdditionalFramesContainer.additional_frames, thread_id): |
| 115 | frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor) |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 116 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 117 | if frame is not None: |
| 118 | return frame |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 119 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 120 | curFrame = GetFrame() |
| 121 | if frame_id == "*": |
| 122 | return curFrame # any frame is specified with "*" |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 123 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 124 | frameFound = None |
| 125 | |
| 126 | for frame in iterFrames(curFrame): |
| 127 | if lookingFor == id(frame): |
| 128 | frameFound = frame |
| 129 | del frame |
| 130 | break |
| 131 | |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 132 | del frame |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 133 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 134 | #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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 137 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 138 | #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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 141 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 142 | if frameFound is None: |
| 143 | msgFrames = '' |
| 144 | i = 0 |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 145 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 146 | 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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 153 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 154 | 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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 159 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 160 | sys.stderr.write(errMsg) |
| 161 | return None |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 162 | |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 163 | return frameFound |
| 164 | except: |
| 165 | import traceback |
| 166 | traceback.print_exc() |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 167 | return None |
| 168 | |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 169 | def 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 | |
| 199 | def 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 | |
| 214 | def evaluateExpression(thread_id, frame_id, expression, doExec): |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 215 | '''returns the result of the evaluated expression |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 216 | @param doExec: determines if we should do an exec or an eval |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 217 | ''' |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 218 | 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 Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 230 | updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 231 | |
| 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 Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 240 | pydevd_save_locals.save_locals(frame) |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 241 | 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 | |
| 274 | def changeAttrExpression(thread_id, frame_id, attr, expression): |
| Tor Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 275 | '''Changes some attribute in a given frame. |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 276 | @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 Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 279 | ''' |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 280 | 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 Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 290 | |
| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 291 | |
| 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 Norbye | c667c1f | 2014-05-28 17:06:51 -0700 | [diff] [blame^] | 299 | 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 Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame] | 304 | #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 | |