summaryrefslogtreecommitdiff
path: root/python/helpers/pydev/pydevd.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/helpers/pydev/pydevd.py')
-rw-r--r--python/helpers/pydev/pydevd.py240
1 files changed, 149 insertions, 91 deletions
diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py
index 1733c26b5e91..9d0da096c07d 100644
--- a/python/helpers/pydev/pydevd.py
+++ b/python/helpers/pydev/pydevd.py
@@ -1,10 +1,13 @@
#IMPORTANT: pydevd_constants must be the 1st thing defined because it'll keep a reference to the original sys._getframe
from __future__ import nested_scopes # Jython 2.1 support
+from pydevd_constants import * # @UnusedWildImport
+
+import pydev_monkey_qt
+pydev_monkey_qt.patch_qt()
import traceback
from django_debug import DjangoLineBreakpoint
-from pydevd_signature import SignatureFactory
from pydevd_frame import add_exception_to_frame
import pydev_imports
from pydevd_breakpoints import * #@UnusedWildImport
@@ -59,7 +62,8 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \
StartServer, \
InternalSetNextStatementThread, \
ReloadCodeCommand, \
- CMD_SET_PY_EXCEPTION, \
+ ID_TO_MEANING,\
+ CMD_SET_PY_EXCEPTION, \
CMD_IGNORE_THROWN_EXCEPTION_AT,\
InternalGetBreakpointException, \
InternalSendCurrExceptionTrace,\
@@ -81,14 +85,12 @@ from pydevd_custom_frames import CustomFramesContainer, CustomFramesContainerIni
import pydevd_dont_trace
import pydevd_traceproperty
-from _pydev_imps import _pydev_time as time
+from _pydev_imps import _pydev_time as time, _pydev_thread
-if USE_LIB_COPY:
- import _pydev_threading as threading
-else:
- import threading
+import _pydev_threading as threading
import os
+import atexit
threadingEnumerate = threading.enumerate
@@ -112,9 +114,11 @@ DONT_TRACE = {
'_pydev_execfile.py':1,
'_pydev_jython_execfile.py':1,
'_pydev_threading':1,
+ '_pydev_Queue':1,
'django_debug.py':1,
'django_frame.py':1,
'pydev_log.py':1,
+ 'pydev_monkey.py':1 ,
'pydevd.py':1 ,
'pydevd_additional_thread_info.py':1,
'pydevd_comm.py':1,
@@ -219,7 +223,7 @@ class PyDBCommandThread(PyDBDaemonThread):
def killAllPydevThreads():
- threads = threadingEnumerate()
+ threads = DictKeys(PyDBDaemonThread.created_pydb_daemon_threads)
for t in threads:
if hasattr(t, 'doKillPydevThread'):
t.doKillPydevThread()
@@ -233,12 +237,23 @@ class PyDBCheckAliveThread(PyDBDaemonThread):
def __init__(self, pyDb):
PyDBDaemonThread.__init__(self)
self.pyDb = pyDb
- self.setDaemon(False)
self.setName('pydevd.CheckAliveThread')
def OnRun(self):
if self.dontTraceMe:
- self.pyDb.SetTrace(None) # no debugging on this thread
+
+ disable_tracing = True
+
+ if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON and sys.hexversion <= 0x020201f0:
+ # don't run untraced threads if we're in jython 2.2.1 or lower
+ # jython bug: if we start a thread and another thread changes the tracing facility
+ # it affects other threads (it's not set only for the thread but globally)
+ # Bug: http://sourceforge.net/tracker/index.php?func=detail&aid=1870039&group_id=12867&atid=112867
+ disable_tracing = False
+
+ if disable_tracing:
+ pydevd_tracing.SetTrace(None) # no debugging on this thread
+
while not self.killReceived:
if not self.pyDb.haveAliveThreads():
try:
@@ -298,8 +313,8 @@ class PyDB:
self.django_exception_break = {}
self.readyToRun = False
- self._main_lock = threading.Lock()
- self._lock_running_thread_ids = threading.Lock()
+ self._main_lock = _pydev_thread.allocate_lock()
+ self._lock_running_thread_ids = _pydev_thread.allocate_lock()
self._py_db_command_thread_event = threading.Event()
CustomFramesContainer._py_db_command_thread_event = self._py_db_command_thread_event
self._finishDebuggingSession = False
@@ -332,7 +347,17 @@ class PyDB:
def haveAliveThreads(self):
for t in threadingEnumerate():
- if not isinstance(t, PyDBDaemonThread) and isThreadAlive(t) and not t.isDaemon():
+ if isinstance(t, PyDBDaemonThread):
+ pydev_log.error_once(
+ 'Error in debugger: Found PyDBDaemonThread through threading.enumerate().\n')
+
+ if getattr(t, 'is_pydev_daemon_thread', False):
+ #Important: Jython 2.5rc4 has a bug where a thread created with thread.start_new_thread won't be
+ #set as a daemon thread, so, we also have to check for the 'is_pydev_daemon_thread' flag.
+ #See: https://github.com/fabioz/PyDev.Debugger/issues/11
+ continue
+
+ if isThreadAlive(t) and not t.isDaemon():
return True
return False
@@ -387,11 +412,9 @@ class PyDB:
if thread_id == "*":
threads = threadingEnumerate()
for t in threads:
- thread_name = t.getName()
- if not thread_name.startswith('pydevd.') or thread_name == 'pydevd.CommandThread':
- thread_id = GetThreadId(t)
- queue = self.getInternalQueue(thread_id)
- queue.put(int_cmd)
+ thread_id = GetThreadId(t)
+ queue = self.getInternalQueue(thread_id)
+ queue.put(int_cmd)
else:
queue = self.getInternalQueue(thread_id)
@@ -442,7 +465,13 @@ class PyDB:
for t in all_threads:
thread_id = GetThreadId(t)
- if not isinstance(t, PyDBDaemonThread) and isThreadAlive(t):
+ if isinstance(t, PyDBDaemonThread):
+ pydev_log.error_once('Found PyDBDaemonThread in threading.enumerate.')
+
+ elif getattr(t, 'is_pydev_daemon_thread', False):
+ pass # I.e.: skip the DummyThreads created from pydev daemon threads
+
+ elif isThreadAlive(t):
program_threads_alive[thread_id] = t
if not DictContains(self._running_thread_ids, thread_id):
@@ -505,19 +534,18 @@ class PyDB:
threads = threadingEnumerate()
try:
for t in threads:
- if not t.getName().startswith('pydevd.'):
- # TODO: optimize so that we only actually add that tracing if it's in
- # the new breakpoint context.
- additionalInfo = None
- try:
- additionalInfo = t.additionalInfo
- except AttributeError:
- pass # that's ok, no info currently set
-
- if additionalInfo is not None:
- for frame in additionalInfo.IterFrames():
- if frame is not ignore_frame:
- self.SetTraceForFrameAndParents(frame, overwrite_prev_trace=overwrite_prev_trace)
+ # TODO: optimize so that we only actually add that tracing if it's in
+ # the new breakpoint context.
+ additionalInfo = None
+ try:
+ additionalInfo = t.additionalInfo
+ except AttributeError:
+ pass # that's ok, no info currently set
+
+ if additionalInfo is not None:
+ for frame in additionalInfo.IterFrames():
+ if frame is not ignore_frame:
+ self.SetTraceForFrameAndParents(frame, overwrite_prev_trace=overwrite_prev_trace)
finally:
frame = None
t = None
@@ -592,7 +620,7 @@ class PyDB:
it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before
probably will give better performance).
'''
- #print ID_TO_MEANING[str(cmd_id)], repr(text)
+ #print(ID_TO_MEANING[str(cmd_id)], repr(text))
self._main_lock.acquire()
try:
@@ -834,7 +862,7 @@ class PyDB:
id_to_pybreakpoint[breakpoint_id] = breakpoint
self.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints)
- self.setTracingForUntracedContexts()
+ self.setTracingForUntracedContexts(overwrite_prev_trace=True)
elif cmd_id == CMD_REMOVE_BREAK:
#command to remove some breakpoint
@@ -862,7 +890,7 @@ class PyDB:
raise NameError(breakpoint_type)
try:
- id_to_pybreakpoint = file_to_id_to_breakpoint[file]
+ id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {})
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
existing = id_to_pybreakpoint[breakpoint_id]
sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (
@@ -1319,7 +1347,7 @@ class PyDB:
if self._finishDebuggingSession and not self._terminationEventSent:
#that was not working very well because jython gave some socket errors
try:
- threads = threadingEnumerate()
+ threads = DictKeys(PyDBDaemonThread.created_pydb_daemon_threads)
for t in threads:
if hasattr(t, 'doKillPydevThread'):
t.doKillPydevThread()
@@ -1332,10 +1360,10 @@ class PyDB:
is_file_to_ignore = DictContains(DONT_TRACE, base) #we don't want to debug threading or anything related to pydevd
+ #print('trace_dispatch', base, frame.f_lineno, event, frame.f_code.co_name, is_file_to_ignore)
if is_file_to_ignore:
return None
- #print('trace_dispatch', base, frame.f_lineno, event, frame.f_code.co_name)
try:
#this shouldn't give an exception, but it could happen... (python bug)
#see http://mail.python.org/pipermail/python-bugs-list/2007-June/038796.html
@@ -1378,9 +1406,14 @@ class PyDB:
except Exception:
# Log it
- if traceback is not None:
- # This can actually happen during the interpreter shutdown in Python 2.7
- traceback.print_exc()
+ try:
+ if traceback is not None:
+ # This can actually happen during the interpreter shutdown in Python 2.7
+ traceback.print_exc()
+ except:
+ # Error logging? We're really in the interpreter shutdown...
+ # (https://github.com/fabioz/PyDev.Debugger/issues/8)
+ pass
return None
if USE_PSYCO_OPTIMIZATION:
@@ -1401,8 +1434,9 @@ class PyDB:
- def SetTraceForFrameAndParents(self, frame, also_add_to_passed_frame=True, overwrite_prev_trace=False):
- dispatch_func = self.trace_dispatch
+ def SetTraceForFrameAndParents(self, frame, also_add_to_passed_frame=True, overwrite_prev_trace=False, dispatch_func=None):
+ if dispatch_func is None:
+ dispatch_func = self.trace_dispatch
if also_add_to_passed_frame:
self.update_trace(frame, dispatch_func, overwrite_prev_trace)
@@ -1432,15 +1466,8 @@ class PyDB:
def prepareToRun(self):
''' Shared code to prepare debugging by installing traces and registering threads '''
-
- # for completeness, we'll register the pydevd.reader & pydevd.writer threads
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.reader" id="-1"/></xml>')
- self.writer.addCommand(net)
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.writer" id="-1"/></xml>')
- self.writer.addCommand(net)
-
- pydevd_tracing.SetTrace(self.trace_dispatch)
self.patch_threads()
+ pydevd_tracing.SetTrace(self.trace_dispatch)
PyDBCommandThread(self).start()
@@ -1519,6 +1546,8 @@ class PyDB:
pydev_imports.execfile(file, globals, locals) # execute the script
+ return globals
+
def exiting(self):
sys.stdout.flush()
sys.stderr.flush()
@@ -1526,6 +1555,22 @@ class PyDB:
cmd = self.cmdFactory.makeExitMessage()
self.writer.addCommand(cmd)
+ def wait_for_commands(self, globals):
+ thread = threading.currentThread()
+ import pydevd_frame_utils
+ frame = pydevd_frame_utils.Frame(None, -1, pydevd_frame_utils.FCode("Console",
+ os.path.abspath(os.path.dirname(__file__))), globals, globals)
+ thread_id = GetThreadId(thread)
+ import pydevd_vars
+ pydevd_vars.addAdditionalFrameById(thread_id, {id(frame): frame})
+
+ cmd = self.cmdFactory.makeShowConsoleMessage(thread_id, frame)
+ self.writer.addCommand(cmd)
+
+ while True:
+ self.processInternalCommands()
+ time.sleep(0.01)
+
def set_debug(setup):
setup['DEBUG_RECORD_SOCKET_READS'] = True
setup['DEBUG_TRACE_BREAKPOINTS'] = 1
@@ -1543,43 +1588,51 @@ def processCommandLine(argv):
setup['multiproc'] = False #Used by PyCharm (reuses connection: ssh tunneling)
setup['multiprocess'] = False # Used by PyDev (creates new connection to ide)
setup['save-signatures'] = False
+ setup['print-in-debugger-startup'] = False
+ setup['cmd-line'] = False
i = 0
del argv[0]
while (i < len(argv)):
- if (argv[i] == '--port'):
+ if argv[i] == '--port':
del argv[i]
setup['port'] = int(argv[i])
del argv[i]
- elif (argv[i] == '--vm_type'):
+ elif argv[i] == '--vm_type':
del argv[i]
setup['vm_type'] = argv[i]
del argv[i]
- elif (argv[i] == '--client'):
+ elif argv[i] == '--client':
del argv[i]
setup['client'] = argv[i]
del argv[i]
- elif (argv[i] == '--server'):
+ elif argv[i] == '--server':
del argv[i]
setup['server'] = True
- elif (argv[i] == '--file'):
+ elif argv[i] == '--file':
del argv[i]
setup['file'] = argv[i]
i = len(argv) # pop out, file is our last argument
- elif (argv[i] == '--DEBUG_RECORD_SOCKET_READS'):
+ elif argv[i] == '--DEBUG_RECORD_SOCKET_READS':
del argv[i]
setup['DEBUG_RECORD_SOCKET_READS'] = True
- elif (argv[i] == '--DEBUG'):
+ elif argv[i] == '--DEBUG':
del argv[i]
set_debug(setup)
- elif (argv[i] == '--multiproc'):
+ elif argv[i] == '--multiproc':
del argv[i]
setup['multiproc'] = True
- elif (argv[i] == '--multiprocess'):
+ elif argv[i] == '--multiprocess':
del argv[i]
setup['multiprocess'] = True
- elif (argv[i] == '--save-signatures'):
+ elif argv[i] == '--save-signatures':
del argv[i]
setup['save-signatures'] = True
+ elif argv[i] == '--print-in-debugger-startup':
+ del argv[i]
+ setup['print-in-debugger-startup'] = True
+ elif (argv[i] == '--cmd-line'):
+ del argv[i]
+ setup['cmd-line'] = True
else:
raise ValueError("unexpected option " + argv[i])
return setup
@@ -1590,18 +1643,6 @@ def usage(doExit=0):
if doExit:
sys.exit(0)
-def SetTraceForParents(frame, dispatch_func):
- frame = frame.f_back
- while frame:
- if frame.f_trace is None:
- frame.f_trace = dispatch_func
-
- frame = frame.f_back
- del frame
-
-def exit_hook():
- debugger = GetGlobalDebugger()
- debugger.exiting()
def initStdoutRedirect():
if not getattr(sys, 'stdoutBuf', None):
@@ -1666,7 +1707,7 @@ def settrace(
-_set_trace_lock = threading.Lock()
+_set_trace_lock = _pydev_thread.allocate_lock()
def _locked_settrace(
host,
@@ -1705,11 +1746,6 @@ def _locked_settrace(
bufferStdOutToServer = stdoutToServer
bufferStdErrToServer = stderrToServer
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.reader" id="-1"/></xml>')
- debugger.writer.addCommand(net)
- net = NetCommand(str(CMD_THREAD_CREATE), 0, '<xml><thread name="pydevd.writer" id="-1"/></xml>')
- debugger.writer.addCommand(net)
-
if bufferStdOutToServer:
initStdoutRedirect()
@@ -1748,7 +1784,9 @@ def _locked_settrace(
# As this is the first connection, also set tracing for any untraced threads
debugger.setTracingForUntracedContexts(ignore_frame=GetFrame(), overwrite_prev_trace=overwrite_prev_trace)
- sys.exitfunc = exit_hook
+ # Stop the tracing as the last thing before the actual shutdown for a clean exit.
+ atexit.register(stoptrace)
+
#Suspend as the last thing after all tracing is in place.
if suspend:
debugger.setSuspend(t, CMD_SET_BREAK)
@@ -1793,16 +1831,15 @@ def stoptrace():
from pydev_monkey import undo_patch_thread_modules
undo_patch_thread_modules()
-
+
debugger = GetGlobalDebugger()
-
+
if debugger:
- debugger.trace_dispatch = None
-
- debugger.SetTraceForFrameAndParents(GetFrame(), False)
-
+
+ debugger.SetTraceForFrameAndParents(
+ GetFrame(), also_add_to_passed_frame=True, overwrite_prev_trace=True, dispatch_func=lambda *args:None)
debugger.exiting()
-
+
killAllPydevThreads()
connected = False
@@ -1830,6 +1867,11 @@ class DispatchReader(ReaderThread):
self.dispatcher = dispatcher
ReaderThread.__init__(self, self.dispatcher.client)
+ def OnRun(self):
+ dummy_thread = threading.currentThread()
+ dummy_thread.is_pydev_daemon_thread = False
+ return ReaderThread.OnRun(self)
+
def handleExcept(self):
ReaderThread.handleExcept(self)
@@ -1893,6 +1935,7 @@ class SetupHolder:
# main
#=======================================================================================================================
if __name__ == '__main__':
+
# parse the command line. --file is our last argument that is required
try:
sys.original_argv = sys.argv[:]
@@ -1902,6 +1945,12 @@ if __name__ == '__main__':
traceback.print_exc()
usage(1)
+ if setup['print-in-debugger-startup']:
+ try:
+ pid = ' (pid: %s)' % os.getpid()
+ except:
+ pid = ''
+ sys.stderr.write("pydev debugger: starting%s\n" % pid)
fix_getpass.fixGetpass()
@@ -2010,6 +2059,12 @@ if __name__ == '__main__':
except:
pass # It's ok not having stackless there...
+ debugger = PyDB()
+
+ if setup['cmd-line']:
+ debugger.cmd_line = True
+
+
if fix_app_engine_debug:
sys.stderr.write("pydev debugger: google app engine integration enabled\n")
curr_dir = os.path.dirname(__file__)
@@ -2022,10 +2077,8 @@ if __name__ == '__main__':
sys.argv.insert(3, '--automatic_restart=no')
sys.argv.insert(4, '--max_module_instances=1')
- debugger = PyDB()
# Run the dev_appserver
debugger.run(setup['file'], None, None, set_trace=False)
-
else:
# as to get here all our imports are already resolved, the psyco module can be
# changed and we'll still get the speedups in the debugger, as those functions
@@ -2041,12 +2094,12 @@ if __name__ == '__main__':
import pydevd_psyco_stub
sys.modules['psyco'] = pydevd_psyco_stub
- debugger = PyDB()
-
if setup['save-signatures']:
if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON:
sys.stderr.write("Collecting run-time type information is not supported for Jython\n")
else:
+ # Only import it if we're going to use it!
+ from pydevd_signature import SignatureFactory
debugger.signature_factory = SignatureFactory()
try:
@@ -2058,4 +2111,9 @@ if __name__ == '__main__':
connected = True # Mark that we're connected when started from inside ide.
- debugger.run(setup['file'], None, None)
+ globals = debugger.run(setup['file'], None, None)
+
+ if setup['cmd-line']:
+ debugger.wait_for_commands(globals)
+
+