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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
from pydevd_constants import *
import pydevd_tracing
import sys
import pydev_log
_original_excepthook = None
_handle_exceptions = None
NOTIFY_ALWAYS="NOTIFY_ALWAYS"
NOTIFY_ON_TERMINATE="NOTIFY_ON_TERMINATE"
if USE_LIB_COPY:
import _pydev_threading as threading
else:
import threading
threadingCurrentThread = threading.currentThread
from pydevd_comm import GetGlobalDebugger
class ExceptionBreakpoint:
def __init__(self, qname, notify_always, notify_on_terminate):
exctype = get_class(qname)
self.qname = qname
if exctype is not None:
self.name = exctype.__name__
else:
self.name = None
self.notify_on_terminate = int(notify_on_terminate) == 1
self.notify_always = int(notify_always) > 0
self.notify_on_first_raise_only = int(notify_always) == 2
self.type = exctype
self.notify = {NOTIFY_ALWAYS: self.notify_always, NOTIFY_ON_TERMINATE: self.notify_on_terminate}
def __str__(self):
return self.qname
class LineBreakpoint:
def __init__(self, type, flag, condition, func_name, expression):
self.type = type
self.condition = condition
self.func_name = func_name
self.expression = expression
def get_break_dict(self, breakpoints, file):
if DictContains(breakpoints, file):
breakDict = breakpoints[file]
else:
breakDict = {}
breakpoints[file] = breakDict
return breakDict
def trace(self, file, line, func_name):
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name))
sys.stderr.flush()
def add(self, breakpoints, file, line, func_name):
self.trace(file, line, func_name)
breakDict = self.get_break_dict(breakpoints, file)
breakDict[line] = self
def get_exception_full_qname(exctype):
if not exctype:
return None
return str(exctype.__module__) + '.' + exctype.__name__
def get_exception_name(exctype):
if not exctype:
return None
return exctype.__name__
def get_exception_breakpoint(exctype, exceptions, notify_class):
name = get_exception_full_qname(exctype)
exc = None
if exceptions is not None:
for k, e in exceptions.items():
if e.notify[notify_class]:
if name == k:
return e
if (e.type is not None and issubclass(exctype, e.type)):
if exc is None or issubclass(e.type, exc.type):
exc = e
return exc
#=======================================================================================================================
# excepthook
#=======================================================================================================================
def excepthook(exctype, value, tb):
global _handle_exceptions
if _handle_exceptions is not None:
exception_breakpoint = get_exception_breakpoint(exctype, _handle_exceptions, NOTIFY_ON_TERMINATE)
else:
exception_breakpoint = None
if exception_breakpoint is None:
return _original_excepthook(exctype, value, tb)
#Always call the original excepthook before going on to call the debugger post mortem to show it.
_original_excepthook(exctype, value, tb)
if tb is None: #sometimes it can be None, e.g. with GTK
return
frames = []
traceback = tb
while tb:
frames.append(tb.tb_frame)
tb = tb.tb_next
thread = threadingCurrentThread()
frames_byid = dict([(id(frame),frame) for frame in frames])
frame = frames[-1]
thread.additionalInfo.exception = (exctype, value, tb)
thread.additionalInfo.pydev_force_stop_at_exception = (frame, frames_byid)
thread.additionalInfo.message = exception_breakpoint.qname
#sys.exc_info = lambda : (exctype, value, traceback)
debugger = GetGlobalDebugger()
debugger.force_post_mortem_stop += 1
pydevd_tracing.SetTrace(None) #no tracing from here
pydev_log.debug('Handling post-mortem stop on exception breakpoint %s'% exception_breakpoint.qname)
debugger.handle_post_mortem_stop(thread.additionalInfo, thread)
#=======================================================================================================================
# set_pm_excepthook
#=======================================================================================================================
def set_pm_excepthook(handle_exceptions_arg=None):
'''
Should be called to register the excepthook to be used.
It's only useful for uncaucht exceptions. I.e.: exceptions that go up to the excepthook.
Can receive a parameter to stop only on some exceptions.
E.g.:
register_excepthook((IndexError, ValueError))
or
register_excepthook(IndexError)
if passed without a parameter, will break on any exception
@param handle_exceptions: exception or tuple(exceptions)
The exceptions that should be handled.
'''
global _handle_exceptions
global _original_excepthook
if sys.excepthook != excepthook:
#Only keep the original if it's not our own excepthook (if called many times).
_original_excepthook = sys.excepthook
_handle_exceptions = handle_exceptions_arg
sys.excepthook = excepthook
def restore_pm_excepthook():
global _original_excepthook
if _original_excepthook:
sys.excepthook = _original_excepthook
_original_excepthook = None
def update_exception_hook(dbg):
if dbg.exception_set:
set_pm_excepthook(dict(dbg.exception_set))
else:
restore_pm_excepthook()
def get_class( kls ):
if IS_PY24 and "BaseException" == kls:
kls = "Exception"
parts = kls.split('.')
module = ".".join(parts[:-1])
if module == "":
if IS_PY3K:
module = "builtins"
else:
module = "__builtin__"
try:
m = __import__( module )
for comp in parts[-1:]:
if m is None:
return None
m = getattr(m, comp, None)
return m
except ImportError:
return None
|