forked from fabioz/PyDev.Debugger
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pydevd_tracing.py
136 lines (109 loc) · 4.88 KB
/
pydevd_tracing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from contextlib import contextmanager
from _pydevd_bundle.pydevd_constants import get_frame
from _pydev_imps._pydev_saved_modules import thread, threading
try:
import cStringIO as StringIO #may not always be available @UnusedImport
except:
try:
import StringIO #@Reimport
except:
import io as StringIO
import sys #@Reimport
import traceback
_original_settrace = sys.settrace
class TracingFunctionHolder:
'''This class exists just to keep some variables (so that we don't keep them in the global namespace).
'''
_original_tracing = None
_warn = True
_lock = thread.allocate_lock()
_traceback_limit = 1
_warnings_shown = {}
def get_exception_traceback_str():
exc_info = sys.exc_info()
s = StringIO.StringIO()
traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], file=s)
return s.getvalue()
def _get_stack_str(frame):
msg = '\nIf this is needed, please check: ' + \
'\nhttp://pydev.blogspot.com/2007/06/why-cant-pydev-debugger-work-with.html' + \
'\nto see how to restore the debug tracing back correctly.\n'
if TracingFunctionHolder._traceback_limit:
s = StringIO.StringIO()
s.write('Call Location:\n')
traceback.print_stack(f=frame, limit=TracingFunctionHolder._traceback_limit, file=s)
msg = msg + s.getvalue()
return msg
def _internal_set_trace(tracing_func):
if TracingFunctionHolder._warn:
frame = get_frame()
if frame is not None and frame.f_back is not None:
if not frame.f_back.f_code.co_filename.lower().endswith('threading.py'):
message = \
'\nPYDEV DEBUGGER WARNING:' + \
'\nsys.settrace() should not be used when the debugger is being used.' + \
'\nThis may cause the debugger to stop working correctly.' + \
'%s' % _get_stack_str(frame.f_back)
if message not in TracingFunctionHolder._warnings_shown:
#only warn about each message once...
TracingFunctionHolder._warnings_shown[message] = 1
sys.stderr.write('%s\n' % (message,))
sys.stderr.flush()
if TracingFunctionHolder._original_tracing:
TracingFunctionHolder._original_tracing(tracing_func)
def SetTrace(tracing_func, frame_eval_func=None, dummy_tracing_func=None):
if tracing_func is not None and frame_eval_func is not None:
# There is no need to set tracing function if frame evaluation is available
frame_eval_func()
tracing_func = dummy_tracing_func
if TracingFunctionHolder._original_tracing is None:
#This may happen before replace_sys_set_trace_func is called.
sys.settrace(tracing_func)
return
current_thread = threading.currentThread()
do_not_trace_before = getattr(current_thread, 'pydev_do_not_trace', None)
if do_not_trace_before:
return
try:
TracingFunctionHolder._lock.acquire()
current_thread.pydev_do_not_trace = True # avoid settrace reentering
TracingFunctionHolder._warn = False
_internal_set_trace(tracing_func)
TracingFunctionHolder._warn = True
finally:
TracingFunctionHolder._lock.release()
current_thread.pydev_do_not_trace = do_not_trace_before
def replace_sys_set_trace_func():
if TracingFunctionHolder._original_tracing is None:
TracingFunctionHolder._original_tracing = sys.settrace
sys.settrace = _internal_set_trace
def restore_sys_set_trace_func():
if TracingFunctionHolder._original_tracing is not None:
sys.settrace = TracingFunctionHolder._original_tracing
TracingFunctionHolder._original_tracing = None
def settrace_while_running_if_frame_eval(py_db, trace_func):
if not py_db.ready_to_run:
# do it if only debug session is started
return
if py_db.frame_eval_func is None:
return
threads = threading.enumerate()
try:
for t in threads:
if getattr(t, 'is_pydev_daemon_thread', False):
continue
additional_info = None
try:
additional_info = t.additional_info
except AttributeError:
pass # that's ok, no info currently set
if additional_info is None:
continue
for frame in additional_info.iter_frames(t):
py_db.set_trace_for_frame_and_parents(frame, overwrite_prev_trace=True, dispatch_func=trace_func)
py_db.enable_cache_frames_without_breaks(False)
# sometimes (when script enters new frames too fast), we can't enable tracing only in the appropriate
# frame. So, if breakpoint was added during run, we should disable frame evaluation forever.
py_db.do_not_use_frame_eval = True
except:
traceback.print_exc()