blob: 75c857c59db71fe8c967311804c0fe2b524d05db [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)
Tor Norbye1fff8e22014-03-10 13:13:45 -0700314
Tor Norbye3a2425a2013-11-04 10:16:08 -0800315 args = command.split('\t', 2)
316 try:
Tor Norbye1fff8e22014-03-10 13:13:45 -0700317 cmd_id = int(args[0])
318 pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), command,))
319 self.processCommand(cmd_id, int(args[1]), args[2])
Tor Norbye3a2425a2013-11-04 10:16:08 -0800320 except:
321 traceback.print_exc()
322 sys.stderr.write("Can't process net command: %s\n" % command)
323 sys.stderr.flush()
324
325 except:
326 traceback.print_exc()
327 self.handleExcept()
328
329
330 def handleExcept(self):
331 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
332
333 def processCommand(self, cmd_id, seq, text):
334 GlobalDebuggerHolder.globalDbg.processNetCommand(cmd_id, seq, text)
335
336
337#----------------------------------------------------------------------------------- SOCKET UTILITIES - WRITER
338#=======================================================================================================================
339# WriterThread
340#=======================================================================================================================
341class WriterThread(PyDBDaemonThread):
342 """ writer thread writes out the commands in an infinite loop """
343 def __init__(self, sock):
344 PyDBDaemonThread.__init__(self)
345 self.setDaemon(False) #writer isn't daemon to be able to deliver all messages after main thread terminated
346 self.sock = sock
347 self.setName("pydevd.Writer")
348 self.cmdQueue = _queue.Queue()
349 if pydevd_vm_type.GetVmType() == 'python':
350 self.timeout = 0
351 else:
352 self.timeout = 0.1
353
354 def addCommand(self, cmd):
355 """ cmd is NetCommand """
356 if not self.killReceived: #we don't take new data after everybody die
357 self.cmdQueue.put(cmd)
358
359 def OnRun(self):
360 """ just loop and write responses """
361
362 self.stopTrace()
363 try:
364 while True:
365 try:
366 try:
367 cmd = self.cmdQueue.get(1, 0.1)
368 except _queue.Empty:
369 if self.killReceived:
370 try:
371 self.sock.shutdown(SHUT_WR)
372 self.sock.close()
373 except:
374 pass
375 self.stop() #mark thread as stopped to unblock joined threads for sure (they can hang otherwise)
376
377 return #break if queue is empty and killReceived
378 else:
379 continue
380 except:
381 #PydevdLog(0, 'Finishing debug communication...(1)')
382 #when liberating the thread here, we could have errors because we were shutting down
383 #but the thread was still not liberated
384 return
385 out = cmd.getOutgoing()
386
387 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
Tor Norbye1fff8e22014-03-10 13:13:45 -0700388 out_message = 'Sending cmd: '
Tor Norbye3a2425a2013-11-04 10:16:08 -0800389 out_message += ID_TO_MEANING.get(out[:3], 'UNKNOWN')
390 out_message += ' '
391 out_message += out
392 try:
393 sys.stderr.write('%s\n' % (out_message,))
394 except:
395 pass
396
397 if IS_PY3K:
398 out = bytearray(out, 'utf-8')
399 self.sock.send(out) #TODO: this does not guarantee that all message are sent (and jython does not have a send all)
400 if cmd.id == CMD_EXIT:
401 break
402 if time is None:
403 break #interpreter shutdown
404 time.sleep(self.timeout)
405 except Exception:
406 GlobalDebuggerHolder.globalDbg.FinishDebuggingSession()
407 if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0:
408 traceback.print_exc()
409
410
411
412
413#--------------------------------------------------- CREATING THE SOCKET THREADS
414
415#=======================================================================================================================
416# StartServer
417#=======================================================================================================================
418def StartServer(port):
419 """ binds to a port, waits for the debugger to connect """
420 s = socket(AF_INET, SOCK_STREAM)
421 s.bind(('', port))
422 s.listen(1)
423 newSock, _addr = s.accept()
424 return newSock
425
426#=======================================================================================================================
427# StartClient
428#=======================================================================================================================
429def StartClient(host, port):
430 """ connects to a host/port """
431 PydevdLog(1, "Connecting to ", host, ":", str(port))
432
433 s = socket(AF_INET, SOCK_STREAM)
434
Tor Norbyea3e39ab2014-04-10 10:54:17 -0700435 MAX_TRIES = 20
Tor Norbye3a2425a2013-11-04 10:16:08 -0800436 i = 0
437 while i<MAX_TRIES:
438 try:
439 s.connect((host, port))
440 except:
441 i+=1
442 time.sleep(0.2)
443 continue
444 PydevdLog(1, "Connected.")
445 return s
446
447 sys.stderr.write("Could not connect to %s: %s\n" % (host, port))
448 sys.stderr.flush()
449 traceback.print_exc()
450 sys.exit(1) #TODO: is it safe?
451
452
453
454#------------------------------------------------------------------------------------ MANY COMMUNICATION STUFF
455
456#=======================================================================================================================
457# NetCommand
458#=======================================================================================================================
459class NetCommand:
460 """ Commands received/sent over the network.
461
462 Command can represent command received from the debugger,
463 or one to be sent by daemon.
464 """
465 next_seq = 0 # sequence numbers
466
467 def __init__(self, id, seq, text):
468 """ smart handling of paramaters
469 if sequence is 0, new sequence will be generated
470 if text has carriage returns they'll be replaced"""
471 self.id = id
472 if (seq == 0): seq = self.getNextSeq()
473 self.seq = seq
474 self.text = text
475 self.outgoing = self.makeMessage(id, seq, text)
476
477 def getNextSeq(self):
478 """ returns next sequence number """
479 NetCommand.next_seq += 2
480 return NetCommand.next_seq
481
482 def getOutgoing(self):
483 """ returns the outgoing message"""
484 return self.outgoing
485
486 def makeMessage(self, cmd, seq, payload):
487 encoded = quote(to_string(payload), '/<>_=" \t')
488 return str(cmd) + '\t' + str(seq) + '\t' + encoded + "\n"
489
490#=======================================================================================================================
491# NetCommandFactory
492#=======================================================================================================================
493class NetCommandFactory:
494
495 def __init_(self):
496 self.next_seq = 0
497
498 def threadToXML(self, thread):
499 """ thread information as XML """
500 name = pydevd_vars.makeValidXmlValue(thread.getName())
501 cmdText = '<thread name="%s" id="%s" />' % (quote(name), GetThreadId(thread))
502 return cmdText
503
504 def makeErrorMessage(self, seq, text):
505 cmd = NetCommand(CMD_ERROR, seq, text)
506 if DebugInfoHolder.DEBUG_TRACE_LEVEL > 2:
507 sys.stderr.write("Error: %s" % (text,))
508 return cmd
509
510 def makeThreadCreatedMessage(self, thread):
511 cmdText = "<xml>" + self.threadToXML(thread) + "</xml>"
512 return NetCommand(CMD_THREAD_CREATE, 0, cmdText)
513
514 def makeListThreadsMessage(self, seq):
515 """ returns thread listing as XML """
516 try:
517 t = threading.enumerate()
518 cmdText = "<xml>"
519 for i in t:
520 if t.isAlive():
521 cmdText += self.threadToXML(i)
522 cmdText += "</xml>"
523 return NetCommand(CMD_RETURN, seq, cmdText)
524 except:
525 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
526
527 def makeVariableChangedMessage(self, seq, payload):
528 # notify debugger that value was changed successfully
529 return NetCommand(CMD_RETURN, seq, payload)
530
531 def makeIoMessage(self, v, ctx, dbg=None):
532 '''
533 @param v: the message to pass to the debug server
534 @param ctx: 1 for stdio 2 for stderr
535 @param dbg: If not none, add to the writer
536 '''
537
538 try:
539 if len(v) > MAX_IO_MSG_SIZE:
540 v = v[0:MAX_IO_MSG_SIZE]
541 v += '...'
542
543 v = pydevd_vars.makeValidXmlValue(quote(v, '/>_= \t'))
544 net = NetCommand(str(CMD_WRITE_TO_CONSOLE), 0, '<xml><io s="%s" ctx="%s"/></xml>' % (v, ctx))
545 except:
546 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
547
548 if dbg:
549 dbg.writer.addCommand(net)
550
551 return net
552
553 def makeVersionMessage(self, seq):
554 try:
555 return NetCommand(CMD_VERSION, seq, VERSION_STRING)
556 except:
557 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
558
559 def makeThreadKilledMessage(self, id):
560 try:
561 return NetCommand(CMD_THREAD_KILL, 0, str(id))
562 except:
563 return self.makeErrorMessage(0, GetExceptionTracebackStr())
564
565 def makeThreadSuspendMessage(self, thread_id, frame, stop_reason, message):
566
567 """ <xml>
568 <thread id="id" stop_reason="reason">
569 <frame id="id" name="functionName " file="file" line="line">
570 <var variable stuffff....
571 </frame>
572 </thread>
573 """
574 try:
575 cmdTextList = ["<xml>"]
576
577 if message:
578 message = pydevd_vars.makeValidXmlValue(str(message))
579
580 cmdTextList.append('<thread id="%s" stop_reason="%s" message="%s">' % (thread_id, stop_reason, message))
581
582 curFrame = frame
583 try:
584 while curFrame:
585 #print cmdText
586 myId = str(id(curFrame))
587 #print "id is ", myId
588
589 if curFrame.f_code is None:
590 break #Iron Python sometimes does not have it!
591
592 myName = curFrame.f_code.co_name #method name (if in method) or ? if global
593 if myName is None:
594 break #Iron Python sometimes does not have it!
595
596 #print "name is ", myName
597
598 filename, base = pydevd_file_utils.GetFilenameAndBase(curFrame)
599
600 myFile = pydevd_file_utils.NormFileToClient(filename)
601
602 #print "file is ", myFile
603 #myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
604
605 myLine = str(curFrame.f_lineno)
606 #print "line is ", myLine
607
608 #the variables are all gotten 'on-demand'
609 #variables = pydevd_vars.frameVarsToXML(curFrame.f_locals)
610
611 variables = ''
612 cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
613 cmdTextList.append('file="%s" line="%s">"' % (quote(myFile, '/>_= \t'), myLine))
614 cmdTextList.append(variables)
615 cmdTextList.append("</frame>")
616 curFrame = curFrame.f_back
617 except :
618 traceback.print_exc()
619
620 cmdTextList.append("</thread></xml>")
621 cmdText = ''.join(cmdTextList)
622 return NetCommand(CMD_THREAD_SUSPEND, 0, cmdText)
623 except:
624 return self.makeErrorMessage(0, GetExceptionTracebackStr())
625
626 def makeThreadRunMessage(self, id, reason):
627 try:
628 return NetCommand(CMD_THREAD_RUN, 0, str(id) + "\t" + str(reason))
629 except:
630 return self.makeErrorMessage(0, GetExceptionTracebackStr())
631
632 def makeGetVariableMessage(self, seq, payload):
633 try:
634 return NetCommand(CMD_GET_VARIABLE, seq, payload)
635 except Exception:
636 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
637
638 def makeGetFrameMessage(self, seq, payload):
639 try:
640 return NetCommand(CMD_GET_FRAME, seq, payload)
641 except Exception:
642 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
643
644
645 def makeEvaluateExpressionMessage(self, seq, payload):
646 try:
647 return NetCommand(CMD_EVALUATE_EXPRESSION, seq, payload)
648 except Exception:
649 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
650
651 def makeGetCompletionsMessage(self, seq, payload):
652 try:
653 return NetCommand(CMD_GET_COMPLETIONS, seq, payload)
654 except Exception:
655 return self.makeErrorMessage(seq, GetExceptionTracebackStr())
656
657 def makeLoadSourceMessage(self, seq, source, dbg=None):
658 try:
659 net = NetCommand(CMD_LOAD_SOURCE, seq, '%s' % source)
660
661 except:
662 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
663
664 if dbg:
665 dbg.writer.addCommand(net)
666 return net
667
668 def makeExitMessage(self):
669 try:
670 net = NetCommand(CMD_EXIT, 0, '')
671
672 except:
673 net = self.makeErrorMessage(0, GetExceptionTracebackStr())
674
675 return net
676
677INTERNAL_TERMINATE_THREAD = 1
678INTERNAL_SUSPEND_THREAD = 2
679
680
681#=======================================================================================================================
682# InternalThreadCommand
683#=======================================================================================================================
684class InternalThreadCommand:
685 """ internal commands are generated/executed by the debugger.
686
687 The reason for their existence is that some commands have to be executed
688 on specific threads. These are the InternalThreadCommands that get
689 get posted to PyDB.cmdQueue.
690 """
691
692 def canBeExecutedBy(self, thread_id):
693 '''By default, it must be in the same thread to be executed
694 '''
695 return self.thread_id == thread_id
696
697 def doIt(self, dbg):
698 raise NotImplementedError("you have to override doIt")
699
700#=======================================================================================================================
701# InternalTerminateThread
702#=======================================================================================================================
703class InternalTerminateThread(InternalThreadCommand):
704 def __init__(self, thread_id):
705 self.thread_id = thread_id
706
707 def doIt(self, dbg):
708 PydevdLog(1, "killing ", str(self.thread_id))
709 cmd = dbg.cmdFactory.makeThreadKilledMessage(self.thread_id)
710 dbg.writer.addCommand(cmd)
711
712
713#=======================================================================================================================
714# InternalRunThread
715#=======================================================================================================================
716class InternalRunThread(InternalThreadCommand):
717 def __init__(self, thread_id):
718 self.thread_id = thread_id
719
720 def doIt(self, dbg):
721 t = PydevdFindThreadById(self.thread_id)
722 if t:
723 t.additionalInfo.pydev_step_cmd = None
724 t.additionalInfo.pydev_step_stop = None
725 t.additionalInfo.pydev_state = STATE_RUN
726
727
728#=======================================================================================================================
729# InternalStepThread
730#=======================================================================================================================
731class InternalStepThread(InternalThreadCommand):
732 def __init__(self, thread_id, cmd_id):
733 self.thread_id = thread_id
734 self.cmd_id = cmd_id
735
736 def doIt(self, dbg):
737 t = PydevdFindThreadById(self.thread_id)
738 if t:
739 t.additionalInfo.pydev_step_cmd = self.cmd_id
740 t.additionalInfo.pydev_state = STATE_RUN
741
742#=======================================================================================================================
743# InternalSetNextStatementThread
744#=======================================================================================================================
745class InternalSetNextStatementThread(InternalThreadCommand):
746 def __init__(self, thread_id, cmd_id, line, func_name):
747 self.thread_id = thread_id
748 self.cmd_id = cmd_id
749 self.line = line
750 self.func_name = func_name
751
752 def doIt(self, dbg):
753 t = PydevdFindThreadById(self.thread_id)
754 if t:
755 t.additionalInfo.pydev_step_cmd = self.cmd_id
756 t.additionalInfo.pydev_next_line = int(self.line)
757 t.additionalInfo.pydev_func_name = self.func_name
758 t.additionalInfo.pydev_state = STATE_RUN
759
760
761#=======================================================================================================================
762# InternalGetVariable
763#=======================================================================================================================
764class InternalGetVariable(InternalThreadCommand):
765 """ gets the value of a variable """
766 def __init__(self, seq, thread_id, frame_id, scope, attrs):
767 self.sequence = seq
768 self.thread_id = thread_id
769 self.frame_id = frame_id
770 self.scope = scope
771 self.attributes = attrs
772
773 def doIt(self, dbg):
774 """ Converts request into python variable """
775 try:
776 xml = "<xml>"
777 valDict = pydevd_vars.resolveCompoundVariable(self.thread_id, self.frame_id, self.scope, self.attributes)
778 if valDict is None:
779 valDict = {}
780
781 keys = valDict.keys()
782 if hasattr(keys, 'sort'):
783 keys.sort(compare_object_attrs) #Python 3.0 does not have it
784 else:
785 if IS_PY3K:
786 keys = sorted(keys, key=cmp_to_key(compare_object_attrs)) #Jython 2.1 does not have it (and all must be compared as strings).
787 else:
788 keys = sorted(keys, cmp=compare_object_attrs) #Jython 2.1 does not have it (and all must be compared as strings).
789
790 for k in keys:
791 xml += pydevd_vars.varToXML(valDict[k], to_string(k))
792
793 xml += "</xml>"
794 cmd = dbg.cmdFactory.makeGetVariableMessage(self.sequence, xml)
795 dbg.writer.addCommand(cmd)
796 except Exception:
797 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving variables " + GetExceptionTracebackStr())
798 dbg.writer.addCommand(cmd)
799
800
801#=======================================================================================================================
802# InternalChangeVariable
803#=======================================================================================================================
804class InternalChangeVariable(InternalThreadCommand):
805 """ changes the value of a variable """
806 def __init__(self, seq, thread_id, frame_id, scope, attr, expression):
807 self.sequence = seq
808 self.thread_id = thread_id
809 self.frame_id = frame_id
810 self.scope = scope
811 self.attr = attr
812 self.expression = expression
813
814 def doIt(self, dbg):
815 """ Converts request into python variable """
816 try:
817 result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression)
818 xml = "<xml>"
819 xml += pydevd_vars.varToXML(result, "")
820 xml += "</xml>"
821 cmd = dbg.cmdFactory.makeVariableChangedMessage(self.sequence, xml)
822 dbg.writer.addCommand(cmd)
823 except Exception:
824 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error changing variable attr:%s expression:%s traceback:%s" % (self.attr, self.expression, GetExceptionTracebackStr()))
825 dbg.writer.addCommand(cmd)
826
827
828#=======================================================================================================================
829# InternalGetFrame
830#=======================================================================================================================
831class InternalGetFrame(InternalThreadCommand):
832 """ gets the value of a variable """
833 def __init__(self, seq, thread_id, frame_id):
834 self.sequence = seq
835 self.thread_id = thread_id
836 self.frame_id = frame_id
837
838 def doIt(self, dbg):
839 """ Converts request into python variable """
840 try:
841 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
842 if frame is not None:
843 xml = "<xml>"
844 xml += pydevd_vars.frameVarsToXML(frame.f_locals)
845 del frame
846 xml += "</xml>"
847 cmd = dbg.cmdFactory.makeGetFrameMessage(self.sequence, xml)
848 dbg.writer.addCommand(cmd)
849 else:
850 #pydevd_vars.dumpFrames(self.thread_id)
851 #don't print this error: frame not found: means that the client is not synchronized (but that's ok)
852 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id))
853 dbg.writer.addCommand(cmd)
854 except:
855 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving frame: %s from thread: %s" % (self.frame_id, self.thread_id))
856 dbg.writer.addCommand(cmd)
857
858
859#=======================================================================================================================
860# InternalEvaluateExpression
861#=======================================================================================================================
862class InternalEvaluateExpression(InternalThreadCommand):
863 """ gets the value of a variable """
864
865 def __init__(self, seq, thread_id, frame_id, expression, doExec, doTrim):
866 self.sequence = seq
867 self.thread_id = thread_id
868 self.frame_id = frame_id
869 self.expression = expression
870 self.doExec = doExec
871 self.doTrim = doTrim
872
873 def doIt(self, dbg):
874 """ Converts request into python variable """
875 try:
876 result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
877 xml = "<xml>"
878 xml += pydevd_vars.varToXML(result, "", self.doTrim)
879 xml += "</xml>"
880 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
881 dbg.writer.addCommand(cmd)
882 except:
883 exc = GetExceptionTracebackStr()
884 sys.stderr.write('%s\n' % (exc,))
885 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc)
886 dbg.writer.addCommand(cmd)
887
888#=======================================================================================================================
889# InternalConsoleExec
890#=======================================================================================================================
891class InternalConsoleExec(InternalThreadCommand):
892 """ gets the value of a variable """
893
894 def __init__(self, seq, thread_id, frame_id, expression):
895 self.sequence = seq
896 self.thread_id = thread_id
897 self.frame_id = frame_id
898 self.expression = expression
899
900 def doIt(self, dbg):
901 """ Converts request into python variable """
902 pydev_start_new_thread = None
903 try:
904 try:
905 pydev_start_new_thread = thread.start_new_thread
906
907 thread.start_new_thread = thread._original_start_new_thread #don't trace new threads created by console command
908 thread.start_new = thread._original_start_new_thread
909
910 result = pydevconsole.consoleExec(self.thread_id, self.frame_id, self.expression)
911 xml = "<xml>"
912 xml += pydevd_vars.varToXML(result, "")
913 xml += "</xml>"
914 cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml)
915 dbg.writer.addCommand(cmd)
916 except:
917 exc = GetExceptionTracebackStr()
918 sys.stderr.write('%s\n' % (exc,))
919 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating console expression " + exc)
920 dbg.writer.addCommand(cmd)
921 finally:
922 thread.start_new_thread = pydev_start_new_thread
923 thread.start_new = pydev_start_new_thread
924 sys.stderr.flush()
925 sys.stdout.flush()
926
927#=======================================================================================================================
928# InternalGetCompletions
929#=======================================================================================================================
930class InternalGetCompletions(InternalThreadCommand):
931 """ Gets the completions in a given scope """
932
933 def __init__(self, seq, thread_id, frame_id, act_tok):
934 self.sequence = seq
935 self.thread_id = thread_id
936 self.frame_id = frame_id
937 self.act_tok = act_tok
938
939
940 def doIt(self, dbg):
941 """ Converts request into completions """
942 try:
943 remove_path = None
944 try:
945 import _completer
946 except:
947 try:
948 path = os.environ['PYDEV_COMPLETER_PYTHONPATH']
949 except :
950 path = os.path.dirname(__file__)
951 sys.path.append(path)
952 remove_path = path
953 try:
954 import _completer
955 except :
956 pass
957
958 try:
959
960 frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
961 if frame is not None:
962
963 #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
964 #(Names not resolved in generator expression in method)
965 #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
966 updated_globals = {}
967 updated_globals.update(frame.f_globals)
968 updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
969 locals = frame.f_locals
970 else:
971 updated_globals = {}
972 locals = {}
973
974
975 if pydevconsole.IPYTHON:
976 completions = pydevconsole.get_completions(self.act_tok, self.act_tok, updated_globals, locals)
977 else:
978 try:
979 completer = _completer.Completer(updated_globals, None)
980 #list(tuple(name, descr, parameters, type))
981 completions = completer.complete(self.act_tok)
982 except :
983 completions = []
984
985
986 def makeValid(s):
987 return pydevd_vars.makeValidXmlValue(pydevd_vars.quote(s, '/>_= \t'))
988
989 msg = "<xml>"
990
991 for comp in completions:
992 msg += '<comp p0="%s" p1="%s" p2="%s" p3="%s"/>' % (makeValid(comp[0]), makeValid(comp[1]), makeValid(comp[2]), makeValid(comp[3]),)
993 msg += "</xml>"
994
995 cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg)
996 dbg.writer.addCommand(cmd)
997
998 finally:
999 if remove_path is not None:
1000 sys.path.remove(remove_path)
1001
1002 except:
1003 exc = GetExceptionTracebackStr()
1004 sys.stderr.write('%s\n' % (exc,))
1005 cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error getting completion " + exc)
1006 dbg.writer.addCommand(cmd)
1007
1008
1009#=======================================================================================================================
1010# PydevdFindThreadById
1011#=======================================================================================================================
1012def PydevdFindThreadById(thread_id):
1013 try:
1014 # there was a deadlock here when I did not remove the tracing function when thread was dead
1015 threads = threading.enumerate()
1016 for i in threads:
1017 if thread_id == GetThreadId(i):
1018 return i
1019
1020 sys.stderr.write("Could not find thread %s\n" % thread_id)
1021 sys.stderr.write("Available: %s\n" % [GetThreadId(t) for t in threads])
1022 sys.stderr.flush()
1023 except:
1024 traceback.print_exc()
1025
1026 return None
1027