-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexception_viewer.py
206 lines (165 loc) · 6.71 KB
/
exception_viewer.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
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
199
200
201
202
203
204
205
# Exception Test
import sys
import traceback
from collections import namedtuple
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
def connect(signal, slot):
signal.connect(slot)
class ConsoleFunctions:
"""Functions to be used in console for convience"""
@staticmethod
def clear():
"""Clears console"""
#_app_.processEvents()
_exceptConsole_.clearExceptions()
#_app_.processEvents()
@staticmethod
def show():
"""Shows console"""
_exceptConsole_.show()
_exceptConsole_.raise_()
#_app_.processEvents()
@staticmethod
def hide():
"""Hides console"""
_exceptConsole_.hide()
#_app_.processEvents()
@staticmethod
def doc(object):
"""Prints docstring of object
for now just prints to console.
TODO: make a widget that displays docstring"""
color = '\033[36m'
endColor = '\033[0m'
print(color + str(object.__doc__) + endColor)
class ViewerWidget(QWidget):
"""Viewer widget that displays exception detailed
information preformatted and with convience set methods.
Expected to show format:
label -> title text like: str(cls.__name__)+': '+str(err)
textBrowser -> shows traceback text
"""
def __init__(self, parent=None):
super(ViewerWidget, self).__init__(parent)
# Declare and intilize component widgets
self.label = QLabel()
self.textBrowser = QTextBrowser()
# Configure component widgets
font = self.label.font()
font.setPointSize(15)
self.label.setFont(font)
self.label.setWordWrap(True)
# Configure layout
self.layout = QVBoxLayout()
self.layout.addWidget(self.label)
self.layout.addWidget(self.textBrowser)
self.setLayout(self.layout)
def setText(self, title='', body=''):
self.label.setText(title)
self.textBrowser.setText(body)
def clear(self):
"""Convience method"""
self.setText()
class ExceptionWindow(QMainWindow):
"""Exception console to be used in Interactive Environment.
Used in conjunction with custom except hook in startup file,
where except hook calls addException to add and exception
to the listWidget, and user can viewer each one of these
in for more detail instead of traceback filling up entire
dam output.
(excepthook will print atleast exception type and error
in console)"""
ExceptionDataRole = Qt.UserRole + 1
ExceptionData = namedtuple('ExceptionData', ['cls', 'err', 'tb'])
#ExceptionClsRole = Qt.UserRole + 1
#ExceptionErrRole = Qt.UserRole + 2
#xceptionTbRole = Qt.UserRole + 3
def __init__(self, parent=None):
super(ExceptionWindow, self).__init__(parent)
self.setWindowTitle("Exception Console")
self.setUnifiedTitleAndToolBarOnMac(True)
# Declare and initilze component widgets
self.listWidget = QListWidget()
self.viewerWidget = ViewerWidget()
self.toolbar = QToolBar()
## Actions
self.actionClear = QAction("Clear", self)
self.actionClear.triggered.connect(self.clearExceptions)
#TODO: add behavior for clear enabled/disabled handling
# (make another connection from currentItemChanged to handling method)
# (and if set based on if current item is None or not)
#TODO: add checkable toolbar action for always show on top
#TODO: fix splitter resize handling
#TODO: fix margin on listWidget and containter
#TODO: add title or placeholder label when viewer is empty
# Configure component widgets
self.toolbar.setMovable(False)
self.toolbar.setFloatable(False)
self.toolbar.addAction(self.actionClear)
self.addToolBar(self.toolbar)
self.listWidget.setAttribute(Qt.WA_MacShowFocusRect, False)
##
# Configure layout
self.splitter = QSplitter()
self.splitter.addWidget(self.listWidget)
self.splitter.addWidget(self.viewerWidget)
self.setCentralWidget(self.splitter)
# Make Connections
connect(self.listWidget.currentItemChanged, self.showCurrentItem)
# Aditional config + logic setup
self.tbReverse = True
self.counter = 1
def addException(self, cls, err, tb):
errorMessage = str(self.counter)+' '+cls+': '+err
exceptionData = ExceptionWindow.ExceptionData(cls, err, tb)
item = QListWidgetItem(errorMessage)
item.setData(ExceptionWindow.ExceptionDataRole, exceptionData)
self.listWidget.insertItem(0, item)
#self.listWidget.scrollToItem(item)
self.listWidget.setCurrentItem(item)
self.counter += 1 # increament after added
def clearExceptions(self):
self.listWidget.clear()
self.counter = 1
def showCurrentItem(self, current, previous):
if current is None:
# Set self.textBrowser text to '' ''
self.viewerWidget.clear()
else:
# Get the current item's data
exceptionData = current.data(ExceptionWindow.ExceptionDataRole)
titleText = exceptionData.cls+': '+exceptionData.err
tb = list(exceptionData.tb)
if self.tbReverse is True:
tb.reverse()
bodyText = "".join(tb)
# Then set the new text of the viewerWidget
self.viewerWidget.setText(titleText, bodyText)
def excepthook(self, cls, err, tb):
CLS = str(cls.__name__)
ERR = str(err)
TBLIST = list(traceback.format_tb(tb))
# print minimal error code for console
print('\033[91m'+CLS+'\033[0m: \033[92m'+ERR+'\033[0m')
self.addException(CLS, ERR, TBLIST)
if __name__ == '__main__':
app = QApplication(sys.argv)
_app_ = app # save originals incase user modifies
exceptConsole = ExceptionWindow()
_exceptConsole_ = exceptConsole # save originals
exceptConsole.show()
exceptConsole.raise_()
# Provide name console functions
clear = ConsoleFunctions.clear
show = ConsoleFunctions.show
hide = ConsoleFunctions.hide
doc = ConsoleFunctions.doc
#TODO: ps Colors might be breaking previous command up arrow
#sys.ps1 = '\033[92m>>> \033[0m'
#sys.ps2 = '\033[42m \033[0m '
sys.excepthook = exceptConsole.excepthook
print('Try making exceptions and testing console.')
print("Traceback for exceptions will appear in the 'exceptConsole'")
print('TODO: add clear button in console')