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
|
from pydevd_constants import *
import pydevd_tracing
import sys
import pydev_log
import pydevd_import_class
_original_excepthook = None
_handle_exceptions = None
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,
notify_on_first_raise_only,
):
exctype = _get_class(qname)
self.qname = qname
if exctype is not None:
self.name = exctype.__name__
else:
self.name = None
self.notify_on_terminate = notify_on_terminate
self.notify_always = notify_always
self.notify_on_first_raise_only = notify_on_first_raise_only
self.type = exctype
def __str__(self):
return self.qname
class LineBreakpoint:
def __init__(self, line, condition, func_name, expression):
self.line = line
self.condition = condition
self.func_name = func_name
self.expression = expression
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):
exception_full_qname = get_exception_full_qname(exctype)
exc = None
if exceptions is not None:
try:
return exceptions[exception_full_qname]
except KeyError:
for exception_breakpoint in DictIterValues(exceptions):
if exception_breakpoint.type is not None and issubclass(exctype, exception_breakpoint.type):
if exc is None or issubclass(exception_breakpoint.type, exc.type):
exc = exception_breakpoint
return exc
#=======================================================================================================================
# _excepthook
#=======================================================================================================================
def _excepthook(exctype, value, tb):
global _handle_exceptions
if _handle_exceptions:
exception_breakpoint = get_exception_breakpoint(exctype, _handle_exceptions)
else:
exception_breakpoint = None
#Always call the original excepthook before going on to call the debugger post mortem to show it.
_original_excepthook(exctype, value, tb)
if not exception_breakpoint:
return
if tb is None: #sometimes it can be None, e.g. with GTK
return
frames = []
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
debugger = GetGlobalDebugger()
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_dict=None):
'''
Should be called to register the excepthook to be used.
It's only useful for uncaught exceptions. I.e.: exceptions that go up to the excepthook.
@param handle_exceptions: dict(exception -> ExceptionBreakpoint)
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_dict
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.break_on_uncaught_exceptions:
_set_pm_excepthook(dbg.break_on_uncaught_exceptions)
else:
_restore_pm_excepthook()
def _get_class( kls ):
if IS_PY24 and "BaseException" == kls:
kls = "Exception"
try:
return eval(kls)
except:
return pydevd_import_class.ImportName(kls)
|