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