blob: 592a96900c7336a0226e0bcb7afd62d54f5ab1c0 [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001''' pydevd - a debugging daemon
2This is the daemon you launch for python remote debugging.
3
4Protocol:
5each command has a format:
6 id\tsequence-num\ttext
7 id: protocol command number
8 sequence-num: each request has a sequence number. Sequence numbers
9 originating at the debugger are odd, sequence numbers originating
10 at the daemon are even. Every response uses the same sequence number
11 as the request.
12 payload: it is protocol dependent. When response is a complex structure, it
13 is returned as XML. Each attribute value is urlencoded, and then the whole
14 payload is urlencoded again to prevent stray characters corrupting protocol/xml encodings
15
16 Commands:
17
18 NUMBER NAME FROM* ARGUMENTS RESPONSE NOTE
19100 series: program execution
20 101 RUN JAVA - -
21 102 LIST_THREADS JAVA RETURN with XML listing of all threads
22 103 THREAD_CREATE PYDB - XML with thread information
23 104 THREAD_KILL JAVA id (or * to exit) kills the thread
24 PYDB id nofies JAVA that thread was killed
25 105 THREAD_SUSPEND JAVA XML of the stack, suspends the thread
26 reason for suspension
27 PYDB id notifies JAVA that thread was suspended
28
29 106 CMD_THREAD_RUN JAVA id resume the thread
30 PYDB id \t reason notifies JAVA that thread was resumed
31
32 107 STEP_INTO JAVA thread_id
33 108 STEP_OVER JAVA thread_id
34 109 STEP_RETURN JAVA thread_id
35
36 110 GET_VARIABLE JAVA thread_id \t frame_id \t GET_VARIABLE with XML of var content
37 FRAME|GLOBAL \t attributes*
38
39 111 SET_BREAK JAVA file/line of the breakpoint
40 112 REMOVE_BREAK JAVA file/line of the return
41 113 CMD_EVALUATE_EXPRESSION JAVA expression result of evaluating the expression
42 114 CMD_GET_FRAME JAVA request for frame contents
43 115 CMD_EXEC_EXPRESSION JAVA
44 116 CMD_WRITE_TO_CONSOLE PYDB
45 117 CMD_CHANGE_VARIABLE
46 118 CMD_RUN_TO_LINE
47 119 CMD_RELOAD_CODE
48 120 CMD_GET_COMPLETIONS JAVA
49
50500 series diagnostics/ok
51 501 VERSION either Version string (1.0) Currently just used at startup
52 502 RETURN either Depends on caller -
53
54900 series: errors
55 901 ERROR either - This is reserved for unexpected errors.
56
57 * JAVA - remote debugger, the java end
58 * PYDB - pydevd, the python end
59'''
60from pydevd_constants import * #@UnusedWildImport
61
62import sys
63
64if USE_LIB_COPY:
65 import _pydev_time as time
66 import _pydev_threading as threading
67 try:
68 import _pydev_thread as thread
69 except ImportError:
70 import _thread as thread #Py3K changed it.
71 import _pydev_Queue as _queue
72 from _pydev_socket import socket
73 from _pydev_socket import AF_INET, SOCK_STREAM
74 from _pydev_socket import SHUT_RD, SHUT_WR
75else:
76 import time
77 import threading
78 try:
79 import thread
80 except ImportError:
81 import _thread as thread #Py3K changed it.
82
83 try:
84 import Queue as _queue
85 except ImportError:
86 import queue as _queue
87 from socket import socket
88 from socket import AF_INET, SOCK_STREAM
89 from socket import SHUT_RD, SHUT_WR
90
91try:
92 from urllib import quote
93except:
94 from urllib.parse import quote #@Reimport @UnresolvedImport
95
96import pydevd_vars
97import pydev_log
98import pydevd_tracing
99import pydevd_vm_type
100import pydevd_file_utils
101import traceback
102from pydevd_utils import *
103from pydevd_utils import quote_smart as quote
104
105
106from pydevd_tracing import GetExceptionTracebackStr
107import pydevconsole
108
109try:
110 _Thread_stop = threading.Thread._Thread__stop
111except AttributeError:
112 _Thread_stop = threading.Thread._stop # _stop in Python 3
113
114
115
116CMD_RUN = 101
117CMD_LIST_THREADS = 102
118CMD_THREAD_CREATE = 103
119CMD_THREAD_KILL = 104
120CMD_THREAD_SUSPEND = 105
121CMD_THREAD_RUN = 106
122CMD_STEP_INTO = 107
123CMD_STEP_OVER = 108
124CMD_STEP_RETURN = 109
125CMD_GET_VARIABLE = 110
126CMD_SET_BREAK = 111
127CMD_REMOVE_BREAK = 112
128CMD_EVALUATE_EXPRESSION = 113
129CMD_GET_FRAME = 114
130CMD_EXEC_EXPRESSION = 115
131CMD_WRITE_TO_CONSOLE = 116
132CMD_CHANGE_VARIABLE = 117
133CMD_RUN_TO_LINE = 118
134CMD_RELOAD_CODE = 119
135CMD_GET_COMPLETIONS = 120
136CMD_CONSOLE_EXEC = 121
137CMD_ADD_EXCEPTION_BREAK = 122
138CMD_REMOVE_EXCEPTION_BREAK = 123
139CMD_LOAD_SOURCE = 124
140CMD_ADD_DJANGO_EXCEPTION_BREAK = 125
141CMD_REMOVE_DJANGO_EXCEPTION_BREAK = 126
142CMD_SET_NEXT_STATEMENT = 127
143CMD_SMART_STEP_INTO = 128
144CMD_EXIT = 129
145CMD_SIGNATURE_CALL_TRACE = 130
146CMD_VERSION = 501
147CMD_RETURN = 502
148CMD_ERROR = 901
149
150ID_TO_MEANING = {
151 '101':'CMD_RUN',
152 '102':'CMD_LIST_THREADS',
153 '103':'CMD_THREAD_CREATE',
154 '104':'CMD_THREAD_KILL',
155 '105':'CMD_THREAD_SUSPEND',
156 '106':'CMD_THREAD_RUN',
157 '107':'CMD_STEP_INTO',
158 '108':'CMD_STEP_OVER',
159 '109':'CMD_STEP_RETURN',
160 '110':'CMD_GET_VARIABLE',
161 '111':'CMD_SET_BREAK',
162 '112':'CMD_REMOVE_BREAK',
163 '113':'CMD_EVALUATE_EXPRESSION',
164 '114':'CMD_GET_FRAME',
165 '115':'CMD_EXEC_EXPRESSION',
166 '116':'CMD_WRITE_TO_CONSOLE',
167 '117':'CMD_CHANGE_VARIABLE',
168 '118':'CMD_RUN_TO_LINE',
169 '119':'CMD_RELOAD_CODE',
170 '120':'CMD_GET_COMPLETIONS',
171 '121':'CMD_CONSOLE_EXEC',
172 '122':'CMD_ADD_EXCEPTION_BREAK',
173 '123':'CMD_REMOVE_EXCEPTION_BREAK',
174 '124':'CMD_LOAD_SOURCE',
175 '125':'CMD_ADD_DJANGO_EXCEPTION_BREAK',
176 '126':'CMD_REMOVE_DJANGO_EXCEPTION_BREAK',
177 '127':'CMD_SET_NEXT_STATEMENT',
178 '128':'CMD_SMART_STEP_INTO',
179 '129': 'CMD_EXIT',
180 '130': 'CMD_SIGNATURE_CALL_TRACE',
181 '501':'CMD_VERSION',
182 '502':'CMD_RETURN',
183 '901':'CMD_ERROR',
184 }
185
186MAX_IO_MSG_SIZE = 1000 #if the io is too big, we'll not send all (could make the debugger too non-responsive)
187#this number can be changed if there's need to do so
188
189VERSION_STRING = "@@BUILD_NUMBER@@"
190
191
192#--------------------------------------------------------------------------------------------------- UTILITIES
193
194#=======================================================================================================================
195# PydevdLog
196#=======================================================================================================================
197def PydevdLog(level, *args):
198 """ levels are:
199 0 most serious warnings/errors
200 1 warnings/significant events
201 2 informational trace
202 """
203 if level <= DebugInfoHolder.DEBUG_TRACE_LEVEL:
204 #yes, we can have errors printing if the console of the program has been finished (and we're still trying to print something)
205 try:
206 sys.stderr.write('%s\n' % (args,))
207 except:
208 pass
209
210#=======================================================================================================================
211# GlobalDebuggerHolder
212#=======================================================================================================================
213class GlobalDebuggerHolder:
214 '''
215 Holder for the global debugger.
216 '''
217 globalDbg = None
218
219#=======================================================================================================================
220# GetGlobalDebugger
221#=======================================================================================================================
222def GetGlobalDebugger():
223 return GlobalDebuggerHolder.globalDbg
224
225#=======================================================================================================================
226# SetGlobalDebugger
227#=======================================================================================================================
228def SetGlobalDebugger(dbg):
229 GlobalDebuggerHolder.globalDbg = dbg
230
231
232#------------------------------------------------------------------- ACTUAL COMM
233
234#=======================================================================================================================
235# PyDBDaemonThread
236#=======================================================================================================================
237class PyDBDaemonThread(threading.Thread):
238
239 def __init__(self):
240 threading.Thread.__init__(self)
241 self.setDaemon(True)
242 self.killReceived = False
243 self.dontTraceMe = True
244
245 def run(self):
246 if sys.platform.startswith("java"):
247 import org.python.core as PyCore #@UnresolvedImport
248 ss = PyCore.PySystemState()
249 # Note: Py.setSystemState() affects only the current thread.
250 PyCore.Py.setSystemState(ss)
251
252 self.OnRun()
253
254 def OnRun(self):
255 raise NotImplementedError('Should be reimplemented by: %s' % self.__class__)
256
257 def doKillPydevThread(self):
258 #that was not working very well because jython gave some socket errors
259 self.killReceived = True
260
261 def stop(self):
262 _Thread_stop(self)
263
264 def stopTrace(self):
265 if self.dontTraceMe:
266 pydevd_tracing.SetTrace(None) # no debugging on this thread
267
268
269#=======================================================================================================================
270# ReaderThread
271#=======================================================================================================================
272class ReaderThread(PyDBDaemonThread):
273 """ reader thread reads and dispatches commands in an infinite loop """
274
275 def __init__(self, sock):
276 PyDBDaemonThread.__init__(self)
277 self.sock = sock
278 self.setName("pydevd.Reader")
279
280
281 def doKillPydevThread(self):
282 #We must close the socket so that it doesn't stay halted there.
283 self.killReceived = True
284 try:
285 self.sock.shutdown(SHUT_RD) #shotdown the socket for read
286 except:
287 #just ignore that
288 pass
289
290 def OnRun(self):
291 self.stopTrace()
292 buffer = ""
293 try:
294
295 while not self.killReceived:
296 try:
297 r = self.sock.recv(1024)
298 except:
299 if not self.killReceived:
300 self.handleExcept()
301 return #Finished communication.
302 if IS_PY3K:
303 r = r.decode('utf-8')
304
305 buffer += r
306 if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS:
307 pydev_log.debug('received >>%s<<\n' % (buffer,))
308
309 if len(buffer) == 0:
310 self.handleExcept()
311 break
312 while buffer.find('\n') != -1:
313 command, buffer = buffer.split('\n', 1)
314 pydev_log.debug('Received command: >>%s<<\n' % (command,))
315 args = command.split('\t', 2)
316 try:
317 self.processCommand(int(args[0]), int(args[1]), args[2])
318 except:
319 traceback.print_exc()
320 sys.stderr.write("Can't process net command: %s\n" % command)
321 sys.stderr.flush()
322
323 except:
324 traceback.print_exc()
325 self.handleExcept()
326
327
328 def handleExcept(self):
329 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
330
331 def processCommand(self, cmd_id, seq, text):
332 GlobalDebuggerHolder.globalDbg.processNetCommand(cmd_id, seq, text)
333
334
335#----------------------------------------------------------------------------------- SOCKET UTILITIES - WRITER
336#=======================================================================================================================
337# WriterThread
338#=======================================================================================================================
339class WriterThread(PyDBDaemonThread):
340 """ writer thread writes out the commands in an infinite loop """
341 def __init__(self, sock):
342 PyDBDaemonThread.__init__(self)
343 self.setDaemon(False) #writer isn't daemon to be able to deliver all messages after main thread terminated
344 self.sock = sock
345 self.setName("pydevd.Writer")
346 self.cmdQueue = _queue.Queue()
347 if pydevd_vm_type.GetVmType() == 'python':
348 self.timeout = 0
349 else:
350 self.timeout = 0.1
351
352 def addCommand(self, cmd):
353 """ cmd is NetCommand """
354 if not self.killReceived: #we don't take new data after everybody die
355 self.cmdQueue.put(cmd)
356
357 def OnRun(self):
358 """ just loop and write responses """
359
360 self.stopTrace()
361 try:
362 while True:
363 try:
364 try:
365 cmd = self.cmdQueue.get(1, 0.1)
366 except _queue.Empty:
367 if self.killReceived:
368 try:
369 self.sock.shutdown(SHUT_WR)
370 self.sock.close()
371 except:
372 pass
373 self.stop() #mark thread as stopped to unblock joined threads for sure (they can hang otherwise)
374
375 return #break if queue is empty and killReceived
376 else:
377 continue
378 except:
379 #PydevdLog(0, 'Finishing debug communication...(1)')
380 #when liberating the thread here, we could have errors because we were shutting down
381 #but the thread was still not liberated
382 return
383 out = cmd.getOutgoing()
384
385 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
386 out_message = 'sending cmd: '
387 out_message += ID_TO_MEANING.get(out[:3], 'UNKNOWN')
388 out_message += ' '
389 out_message += out
390 try:
391 sys.stderr.write('%s\n' % (out_message,))
392 except:
393 pass
394
395 if IS_PY3K:
396 out = bytearray(out, 'utf-8')
397 self.sock.send(out) #TODO: this does not guarantee that all message are sent (and jython does not have a send all)
398 if cmd.id == CMD_EXIT:
399 break
400 if time is None:
401 break #interpreter shutdown
402 time.sleep(self.timeout)
403 except Exception:
404 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
405 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0:
406 traceback.print_exc()
407
408
409
410
411#--------------------------------------------------- CREATING THE SOCKET THREADS
412
413#=======================================================================================================================
414# StartServer
415#=======================================================================================================================
416def StartServer(port):
417 """ binds to a port, waits for the debugger to connect """
418 s = socket(AF_INET, SOCK_STREAM)
419 s.bind(('', port))
420 s.listen(1)
421 newSock, _addr = s.accept()
422 return newSock
423
424#=======================================================================================================================
425# StartClient
426#=======================================================================================================================
427def StartClient(host, port):
428 """ connects to a host/port """
429 PydevdLog(1, "Connecting to ", host, ":", str(port))
430
431 s = socket(AF_INET, SOCK_STREAM)
432
433 MAX_TRIES = 3
434 i = 0
435 while i<MAX_TRIES:
436 try:
437 s.connect((host, port))
438 except:
439 i+=1
440 time.sleep(0.2)
441 continue
442 PydevdLog(1, "Connected.")
443 return s
444
445 sys.stderr.write("Could not connect to %s: %s\n" % (host, port))
446 sys.stderr.flush()
447 traceback.print_exc()
448 sys.exit(1) #TODO: is it safe?
449
450
451
452#------------------------------------------------------------------------------------ MANY COMMUNICATION STUFF
453
454#=======================================================================================================================
455# NetCommand
456#=======================================================================================================================
457class NetCommand:
458 """ Commands received/sent over the network.
459
460 Command can represent command received from the debugger,
461 or one to be sent by daemon.
462 """
463 next_seq = 0 # sequence numbers
464
465 def __init__(self, id, seq, text):
466 """ smart handling of paramaters
467 if sequence is 0, new sequence will be generated
468 if text has carriage returns they'll be replaced"""
469 self.id = id
470 if (seq == 0): seq = self.getNextSeq()
471 self.seq = seq
472 self.text = text
473 self.outgoing = self.makeMessage(id, seq, text)
474
475 def getNextSeq(self):
476 """ returns next sequence number """
477 NetCommand.next_seq += 2
478 return NetCommand.next_seq
479
480 def getOutgoing(self):
481 """ returns the outgoing message"""
482 return self.outgoing
483
484 def makeMessage(self, cmd, seq, payload):
485 encoded = quote(to_string(payload), '/<>_=" \t')
486 return str(cmd) + '\t' + str(seq) + '\t' + encoded + "\n"
487
488#=======================================================================================================================
489# NetCommandFactory
490#=======================================================================================================================
491class NetCommandFactory:
492
493 def __init_(self):
494 self.next_seq = 0
495
496 def threadToXML(self, thread):
497 """ thread information as XML """
498 name = pydevd_vars.makeValidXmlValue(thread.getName())
499 cmdText = '<thread name="%s" id="%s" />' % (quote(name), GetThreadId(thread))
500 return cmdText
501
502 def makeErrorMessage(self, seq, text):
503 cmd = NetCommand(CMD_ERROR, seq, text)
504 if DebugInfoHolder.DEBUG_TRACE_LEVEL > 2:
505 sys.stderr.write("Error: %s" % (text,))
506 return cmd
507
508 def makeThreadCreatedMessage(self, thread):
509 cmdText = "<xml>" + self.threadToXML(thread) + "</xml>"
510 return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
511
512 def makeListThreadsMessage(self, seq):
513 """ returns thread listing as XML """
514 try:
515 t = threading.enumerate()
516 cmdText = "<xml>"
517 for i in t:
518 if t.isAlive():
519 cmdText += self.threadToXML(i)
520 cmdText += "</xml>"
521 return NetCommand(CMD_RETURN, seq, cmdText)
522 except:
523 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
524
525 def makeVariableChangedMessage(self, seq, payload):
526 # notify debugger that value was changed successfully
527 return NetCommand(CMD_RETURN, seq, payload)
528
529 def makeIoMessage(self, v, ctx, dbg=None):
530 '''
531 @param v: the message to pass to the debug server
532 @param ctx: 1 for stdio 2 for stderr
533 @param dbg: If not none, add to the writer
534 '''
535
536 try:
537 if len(v) > MAX_IO_MSG_SIZE:
538 v = v[0:MAX_IO_MSG_SIZE]
539 v += '...'
540
541 v = pydevd_vars.makeValidXmlValue(quote(v, '/>_= \t'))
542 net = NetCommand(str(CMD_WRITE_TO_CONSOLE), 0, '<xml><io s="%s" ctx="%s"/></xml>' % (v, ctx))
543 except:
544 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
545
546 if dbg:
547 dbg.writer.addCommand(net)
548
549 return net
550
551 def makeVersionMessage(self, seq):
552 try:
553 return NetCommand(CMD_VERSION, seq, VERSION_STRING)
554 except:
555 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
556
557 def makeThreadKilledMessage(self, id):
558 try:
559 return NetCommand(CMD_THREAD_KILL, 0, str(id))
560 except:
561 return self.makeErrorMessage(0, GetExceptionTracebackStr())
562
563 def makeThreadSuspendMessage(self, thread_id, frame, stop_reason, message):
564
565 """ <xml>
566 <thread id="id" stop_reason="reason">
567 <frame id="id" name="functionName " file="file" line="line">
568 <var variable stuffff....
569 </frame>
570 </thread>
571 """
572 try:
573 cmdTextList = ["<xml>"]
574
575 if message:
576 message = pydevd_vars.makeValidXmlValue(str(message))
577
578 cmdTextList.append('<thread id="%s" stop_reason="%s" message="%s">' % (thread_id, stop_reason, message))
579
580 curFrame = frame
581 try:
582 while curFrame:
583 #print cmdText
584 myId = str(id(curFrame))
585 #print "id is ", myId
586
587 if curFrame.f_code is None:
588 break #Iron Python sometimes does not have it!
589
590 myName = curFrame.f_code.co_name #method name (if in method) or ? if global
591 if myName is None:
592 break #Iron Python sometimes does not have it!
593
594 #print "name is ", myName
595
596 filename, base = pydevd_file_utils.GetFilenameAndBase(curFrame)
597
598 myFile = pydevd_file_utils.NormFileToClient(filename)
599
600 #print "file is ", myFile
601 #myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
602
603 myLine = str(curFrame.f_lineno)
604 #print "line is ", myLine
605
606 #the variables are all gotten 'on-demand'
607 #variables = pydevd_vars.frameVarsToXML(curFrame.f_locals)
608
609 variables = ''
610 cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
611 cmdTextList.append('file="%s" line="%s">"' % (quote(myFile, '/>_= \t'), myLine))
612 cmdTextList.append(variables)
613 cmdTextList.append("</frame>")
614 curFrame = curFrame.f_back
615 except :
616 traceback.print_exc()
617
618 cmdTextList.append("</thread></xml>")
619 cmdText = ''.join(cmdTextList)
620 return NetCommand(CMD_THREAD_SUSPEND, 0, cmdText)
621 except:
622 return self.makeErrorMessage(0, GetExceptionTracebackStr())
623
624 def makeThreadRunMessage(self, id, reason):
625 try:
626 return NetCommand(CMD_THREAD_RUN, 0, str(id) + "\t" + str(reason))
627 except:
628 return self.makeErrorMessage(0, GetExceptionTracebackStr())
629
630 def makeGetVariableMessage(self, seq, payload):
631 try:
632 return NetCommand(CMD_GET_VARIABLE, seq, payload)
633 except Exception:
634 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
635
636 def makeGetFrameMessage(self, seq, payload):
637 try:
638 return NetCommand(CMD_GET_FRAME, seq, payload)
639 except Exception:
640 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
641
642
643 def makeEvaluateExpressionMessage(self, seq, payload):
644 try:
645 return NetCommand(CMD_EVALUATE_EXPRESSION, seq, payload)
646 except Exception:
647 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
648
649 def makeGetCompletionsMessage(self, seq, payload):
650 try:
651 return NetCommand(CMD_GET_COMPLETIONS, seq, payload)
652 except Exception:
653 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
654
655 def makeLoadSourceMessage(self, seq, source, dbg=None):
656 try:
657 net = NetCommand(CMD_LOAD_SOURCE, seq, '%s' % source)
658
659 except:
660 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
661
662 if dbg:
663 dbg.writer.addCommand(net)
664 return net
665
666 def makeExitMessage(self):
667 try:
668 net = NetCommand(CMD_EXIT, 0, '')
669
670 except:
671 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
672
673 return net
674
675INTERNAL_TERMINATE_THREAD = 1
676INTERNAL_SUSPEND_THREAD = 2
677
678
679#=======================================================================================================================
680# InternalThreadCommand
681#=======================================================================================================================
682class InternalThreadCommand:
683 """ internal commands are generated/executed by the debugger.
684
685 The reason for their existence is that some commands have to be executed
686 on specific threads. These are the InternalThreadCommands that get
687 get posted to PyDB.cmdQueue.
688 """
689
690 def canBeExecutedBy(self, thread_id):
691 '''By default, it must be in the same thread to be executed
692 '''
693 return self.thread_id == thread_id
694
695 def doIt(self, dbg):
696 raise NotImplementedError("you have to override doIt")
697
698#=======================================================================================================================
699# InternalTerminateThread
700#=======================================================================================================================
701class InternalTerminateThread(InternalThreadCommand):
702 def __init__(self, thread_id):
703 self.thread_id = thread_id
704
705 def doIt(self, dbg):
706 PydevdLog(1, "killing ", str(self.thread_id))
707 cmd = dbg.cmdFactory.makeThreadKilledMessage(self.thread_id)
708 dbg.writer.addCommand(cmd)
709
710
711#=======================================================================================================================
712# InternalRunThread
713#=======================================================================================================================
714class InternalRunThread(InternalThreadCommand):
715 def __init__(self, thread_id):
716 self.thread_id = thread_id
717
718 def doIt(self, dbg):
719 t = PydevdFindThreadById(self.thread_id)
720 if t:
721 t.additionalInfo.pydev_step_cmd = None
722 t.additionalInfo.pydev_step_stop = None
723 t.additionalInfo.pydev_state = STATE_RUN
724
725
726#=======================================================================================================================
727# InternalStepThread
728#=======================================================================================================================
729class InternalStepThread(InternalThreadCommand):
730 def __init__(self, thread_id, cmd_id):
731 self.thread_id = thread_id
732 self.cmd_id = cmd_id
733
734 def doIt(self, dbg):
735 t = PydevdFindThreadById(self.thread_id)
736 if t:
737 t.additionalInfo.pydev_step_cmd = self.cmd_id
738 t.additionalInfo.pydev_state = STATE_RUN
739
740#=======================================================================================================================
741# InternalSetNextStatementThread
742#=======================================================================================================================
743class InternalSetNextStatementThread(InternalThreadCommand):
744 def __init__(self, thread_id, cmd_id, line, func_name):
745 self.thread_id = thread_id
746 self.cmd_id = cmd_id
747 self.line = line
748 self.func_name = func_name
749
750 def doIt(self, dbg):
751 t = PydevdFindThreadById(self.thread_id)
752 if t:
753 t.additionalInfo.pydev_step_cmd = self.cmd_id
754 t.additionalInfo.pydev_next_line = int(self.line)
755 t.additionalInfo.pydev_func_name = self.func_name
756 t.additionalInfo.pydev_state = STATE_RUN
757
758
759#=======================================================================================================================
760# InternalGetVariable
761#=======================================================================================================================
762class InternalGetVariable(InternalThreadCommand):
763 """ gets the value of a variable """
764 def __init__(self, seq, thread_id, frame_id, scope, attrs):
765 self.sequence = seq
766 self.thread_id = thread_id
767 self.frame_id = frame_id
768 self.scope = scope
769 self.attributes = attrs
770
771 def doIt(self, dbg):
772 """ Converts request into python variable """
773 try:
774 xml = "<xml>"
775 valDict = pydevd_vars.resolveCompoundVariable(self.thread_id, self.frame_id, self.scope, self.attributes)
776 if valDict is None:
777 valDict = {}
778
779 keys = valDict.keys()
780 if hasattr(keys, 'sort'):
781 keys.sort(compare_object_attrs) #Python 3.0 does not have it
782 else:
783 if IS_PY3K:
784 keys = sorted(keys, key=cmp_to_key(compare_object_attrs)) #Jython 2.1 does not have it (and all must be compared as strings).
785 else:
786 keys = sorted(keys, cmp=compare_object_attrs) #Jython 2.1 does not have it (and all must be compared as strings).
787
788 for k in keys:
789 xml += pydevd_vars.varToXML(valDict[k], to_string(k))
790
791 xml += "</xml>"
792 cmd = dbg.cmdFactory.makeGetVariableMessage(self.sequence, xml)
793 dbg.writer.addCommand(cmd)
794 except Exception:
795 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving variables " + GetExceptionTracebackStr())
796 dbg.writer.addCommand(cmd)
797
798
799#=======================================================================================================================
800# InternalChangeVariable
801#=======================================================================================================================
802class InternalChangeVariable(InternalThreadCommand):
803 """ changes the value of a variable """
804 def __init__(self, seq, thread_id, frame_id, scope, attr, expression):
805 self.sequence = seq
806 self.thread_id = thread_id
807 self.frame_id = frame_id
808 self.scope = scope
809 self.attr = attr
810 self.expression = expression
811
812 def doIt(self, dbg):
813 """ Converts request into python variable """
814 try:
815 result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression)
816 xml = "<xml>"
817 xml += pydevd_vars.varToXML(result, "")
818 xml += "</xml>"
819 cmd = dbg.cmdFactory.makeVariableChangedMessage(self.sequence, xml)
820 dbg.writer.addCommand(cmd)
821 except Exception:
822 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error changing variable attr:%s expression:%s traceback:%s" % (self.attr, self.expression, GetExceptionTracebackStr()))
823 dbg.writer.addCommand(cmd)
824
825
826#=======================================================================================================================
827# InternalGetFrame
828#=======================================================================================================================
829class InternalGetFrame(InternalThreadCommand):
830 """ gets the value of a variable """
831 def __init__(self, seq, thread_id, frame_id):
832 self.sequence = seq
833 self.thread_id = thread_id
834 self.frame_id = frame_id
835
836 def doIt(self, dbg):
837 """ Converts request into python variable """
838 try:
839 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
840 if frame is not None:
841 xml = "<xml>"
842 xml += pydevd_vars.frameVarsToXML(frame.f_locals)
843 del frame
844 xml += "</xml>"
845 cmd = dbg.cmdFactory.makeGetFrameMessage(self.sequence, xml)
846 dbg.writer.addCommand(cmd)
847 else:
848 #pydevd_vars.dumpFrames(self.thread_id)
849 #don't print this error: frame not found: means that the client is not synchronized (but that's ok)
850 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id))
851 dbg.writer.addCommand(cmd)
852 except:
853 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving frame: %s from thread: %s" % (self.frame_id, self.thread_id))
854 dbg.writer.addCommand(cmd)
855
856
857#=======================================================================================================================
858# InternalEvaluateExpression
859#=======================================================================================================================
860class InternalEvaluateExpression(InternalThreadCommand):
861 """ gets the value of a variable """
862
863 def __init__(self, seq, thread_id, frame_id, expression, doExec, doTrim):
864 self.sequence = seq
865 self.thread_id = thread_id
866 self.frame_id = frame_id
867 self.expression = expression
868 self.doExec = doExec
869 self.doTrim = doTrim
870
871 def doIt(self, dbg):
872 """ Converts request into python variable """
873 try:
874 result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
875 xml = "<xml>"
876 xml += pydevd_vars.varToXML(result, "", self.doTrim)
877 xml += "</xml>"
878 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
879 dbg.writer.addCommand(cmd)
880 except:
881 exc = GetExceptionTracebackStr()
882 sys.stderr.write('%s\n' % (exc,))
883 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc)
884 dbg.writer.addCommand(cmd)
885
886#=======================================================================================================================
887# InternalConsoleExec
888#=======================================================================================================================
889class InternalConsoleExec(InternalThreadCommand):
890 """ gets the value of a variable """
891
892 def __init__(self, seq, thread_id, frame_id, expression):
893 self.sequence = seq
894 self.thread_id = thread_id
895 self.frame_id = frame_id
896 self.expression = expression
897
898 def doIt(self, dbg):
899 """ Converts request into python variable """
900 pydev_start_new_thread = None
901 try:
902 try:
903 pydev_start_new_thread = thread.start_new_thread
904
905 thread.start_new_thread = thread._original_start_new_thread #don't trace new threads created by console command
906 thread.start_new = thread._original_start_new_thread
907
908 result = pydevconsole.consoleExec(self.thread_id, self.frame_id, self.expression)
909 xml = "<xml>"
910 xml += pydevd_vars.varToXML(result, "")
911 xml += "</xml>"
912 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
913 dbg.writer.addCommand(cmd)
914 except:
915 exc = GetExceptionTracebackStr()
916 sys.stderr.write('%s\n' % (exc,))
917 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating console expression " + exc)
918 dbg.writer.addCommand(cmd)
919 finally:
920 thread.start_new_thread = pydev_start_new_thread
921 thread.start_new = pydev_start_new_thread
922 sys.stderr.flush()
923 sys.stdout.flush()
924
925#=======================================================================================================================
926# InternalGetCompletions
927#=======================================================================================================================
928class InternalGetCompletions(InternalThreadCommand):
929 """ Gets the completions in a given scope """
930
931 def __init__(self, seq, thread_id, frame_id, act_tok):
932 self.sequence = seq
933 self.thread_id = thread_id
934 self.frame_id = frame_id
935 self.act_tok = act_tok
936
937
938 def doIt(self, dbg):
939 """ Converts request into completions """
940 try:
941 remove_path = None
942 try:
943 import _completer
944 except:
945 try:
946 path = os.environ['PYDEV_COMPLETER_PYTHONPATH']
947 except :
948 path = os.path.dirname(__file__)
949 sys.path.append(path)
950 remove_path = path
951 try:
952 import _completer
953 except :
954 pass
955
956 try:
957
958 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
959 if frame is not None:
960
961 #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
962 #(Names not resolved in generator expression in method)
963 #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
964 updated_globals = {}
965 updated_globals.update(frame.f_globals)
966 updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
967 locals = frame.f_locals
968 else:
969 updated_globals = {}
970 locals = {}
971
972
973 if pydevconsole.IPYTHON:
974 completions = pydevconsole.get_completions(self.act_tok, self.act_tok, updated_globals, locals)
975 else:
976 try:
977 completer = _completer.Completer(updated_globals, None)
978 #list(tuple(name, descr, parameters, type))
979 completions = completer.complete(self.act_tok)
980 except :
981 completions = []
982
983
984 def makeValid(s):
985 return pydevd_vars.makeValidXmlValue(pydevd_vars.quote(s, '/>_= \t'))
986
987 msg = "<xml>"
988
989 for comp in completions:
990 msg += '<comp p0="%s" p1="%s" p2="%s" p3="%s"/>' % (makeValid(comp[0]), makeValid(comp[1]), makeValid(comp[2]), makeValid(comp[3]),)
991 msg += "</xml>"
992
993 cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg)
994 dbg.writer.addCommand(cmd)
995
996 finally:
997 if remove_path is not None:
998 sys.path.remove(remove_path)
999
1000 except:
1001 exc = GetExceptionTracebackStr()
1002 sys.stderr.write('%s\n' % (exc,))
1003 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error getting completion " + exc)
1004 dbg.writer.addCommand(cmd)
1005
1006
1007#=======================================================================================================================
1008# PydevdFindThreadById
1009#=======================================================================================================================
1010def PydevdFindThreadById(thread_id):
1011 try:
1012 # there was a deadlock here when I did not remove the tracing function when thread was dead
1013 threads = threading.enumerate()
1014 for i in threads:
1015 if thread_id == GetThreadId(i):
1016 return i
1017
1018 sys.stderr.write("Could not find thread %s\n" % thread_id)
1019 sys.stderr.write("Available: %s\n" % [GetThreadId(t) for t in threads])
1020 sys.stderr.flush()
1021 except:
1022 traceback.print_exc()
1023
1024 return None
1025