Skip to content

Commit 632d739

Browse files
committed
Initial Commit
Initial commit with working concept files and startup bash/.command script for running from current folder.
1 parent d3821f6 commit 632d739

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

exception_viewer.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Exception Test
2+
import sys
3+
import traceback
4+
from collections import namedtuple
5+
from PyQt5.QtWidgets import *
6+
from PyQt5.QtCore import *
7+
8+
def connect(signal, slot):
9+
signal.connect(slot)
10+
11+
class ViewerWidget(QWidget):
12+
"""Viewer widget that displays exception detailed
13+
information preformatted and with convience set methods.
14+
15+
Expected to show format:
16+
label -> title text like: str(cls.__name__)+': '+str(err)
17+
textBrowser -> shows traceback text
18+
19+
"""
20+
def __init__(self, parent=None):
21+
super(ViewerWidget, self).__init__(parent)
22+
23+
# Declare and intilize component widgets
24+
self.label = QLabel()
25+
self.textBrowser = QTextBrowser()
26+
27+
# Configure component widgets
28+
font = self.label.font()
29+
font.setPointSize(15)
30+
self.label.setFont(font)
31+
self.label.setWordWrap(True)
32+
33+
# Configure layout
34+
self.layout = QVBoxLayout()
35+
self.layout.addWidget(self.label)
36+
self.layout.addWidget(self.textBrowser)
37+
self.setLayout(self.layout)
38+
39+
def setText(self, title='', body=''):
40+
self.label.setText(title)
41+
self.textBrowser.setText(body)
42+
43+
def clear(self):
44+
"""Convience method"""
45+
self.setText()
46+
47+
48+
class ExceptionWindow(QMainWindow):
49+
"""Exception console to be used in Interactive Environment.
50+
Used in conjunction with custom except hook in startup file,
51+
where except hook calls addException to add and exception
52+
to the listWidget, and user can viewer each one of these
53+
in for more detail instead of traceback filling up entire
54+
dam output.
55+
(excepthook will print atleast exception type and error
56+
in console)"""
57+
ExceptionDataRole = Qt.UserRole + 1
58+
ExceptionData = namedtuple('ExceptionData', ['cls', 'err', 'tb'])
59+
#ExceptionClsRole = Qt.UserRole + 1
60+
#ExceptionErrRole = Qt.UserRole + 2
61+
#xceptionTbRole = Qt.UserRole + 3
62+
63+
def __init__(self, parent=None):
64+
super(ExceptionWindow, self).__init__(parent)
65+
self.setWindowTitle("Exception Console")
66+
self.setUnifiedTitleAndToolBarOnMac(True)
67+
68+
# Declare and initilze component widgets
69+
self.listWidget = QListWidget()
70+
self.viewerWidget = ViewerWidget()
71+
self.toolbar = QToolBar()
72+
73+
## Actions
74+
self.actionClear = QAction("Clear", self)
75+
self.actionClear.triggered.connect(self.clearExceptions)
76+
#TODO: add behavior for clear enabled/disabled handling
77+
# (make another connection from currentItemChanged to handling method)
78+
# (and if set based on if current item is None or not)
79+
#TODO: add checkable toolbar action for always show on top
80+
81+
#TODO: fix splitter resize handling
82+
#TODO: fix margin on listWidget and containter
83+
#TODO: add title or placeholder label when viewer is empty
84+
85+
# Configure component widgets
86+
self.toolbar.setMovable(False)
87+
self.toolbar.setFloatable(False)
88+
self.toolbar.addAction(self.actionClear)
89+
self.addToolBar(self.toolbar)
90+
##
91+
92+
# Configure layout
93+
self.splitter = QSplitter()
94+
self.splitter.addWidget(self.listWidget)
95+
self.splitter.addWidget(self.viewerWidget)
96+
self.setCentralWidget(self.splitter)
97+
98+
# Make Connections
99+
connect(self.listWidget.currentItemChanged, self.showCurrentItem)
100+
101+
# Aditional config + logic setup
102+
self.tbReverse = True
103+
self.counter = 1
104+
105+
def addException(self, cls, err, tb):
106+
errorMessage = str(self.counter)+' '+cls+': '+err
107+
exceptionData = ExceptionWindow.ExceptionData(cls, err, tb)
108+
109+
item = QListWidgetItem(errorMessage)
110+
item.setData(ExceptionWindow.ExceptionDataRole, exceptionData)
111+
112+
self.listWidget.insertItem(0, item)
113+
#self.listWidget.scrollToItem(item)
114+
self.listWidget.setCurrentItem(item)
115+
self.counter += 1 # increament after added
116+
117+
def clearExceptions(self):
118+
self.listWidget.clear()
119+
self.counter = 1
120+
121+
def showCurrentItem(self, current, previous):
122+
if current is None:
123+
# Set self.textBrowser text to '' ''
124+
self.viewerWidget.clear()
125+
else:
126+
# Get the current item's data
127+
exceptionData = current.data(ExceptionWindow.ExceptionDataRole)
128+
titleText = exceptionData.cls+': '+exceptionData.err
129+
tb = list(exceptionData.tb)
130+
if self.tbReverse is True:
131+
tb.reverse()
132+
bodyText = "".join(tb)
133+
134+
# Then set the new text of the viewerWidget
135+
self.viewerWidget.setText(titleText, bodyText)
136+
137+
def excepthook(self, cls, err, tb):
138+
CLS = str(cls.__name__)
139+
ERR = str(err)
140+
TBLIST = list(traceback.format_tb(tb))
141+
# print minimal error code for console
142+
print('\033[91m'+CLS+'\033[0m: \033[92m'+ERR+'\033[0m')
143+
144+
self.addException(CLS, ERR, TBLIST)
145+
146+
if __name__ == '__main__':
147+
app = QApplication(sys.argv)
148+
_app_ = app # save originals incase user modifies
149+
exceptConsole = ExceptionWindow()
150+
_exceptConsole_ = exceptConsole # save originals
151+
exceptConsole.show()
152+
exceptConsole.raise_()
153+
154+
sys.excepthook = exceptConsole.excepthook
155+
156+
print('Try making exceptions and testing console.')
157+
print("Traceback for exceptions will appear in the 'exceptConsole'")
158+
print('TODO: add clear button in console')
159+
160+

ipythonqt.command

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
# Runs python interactive environment with
3+
# PYTHONSTARTUP set to exception_viewer.py
4+
# for easy interactive sessions with PyQt5
5+
# or verbose Exception crazy libraries
6+
# such as Pandas.
7+
startupfile="exception_viewer.py"
8+
DIR="$(dirname "${BASH_SOURCE[0]}")"
9+
10+
#PYTHONSTARTUP="exception_viewer.py" python -i
11+
PYTHONSTARTUP=$DIR/$startupfile
12+
echo $PYTHONSTARTUP
13+
PYTHONSTARTUP=$PYTHONSTARTUP pythonw -i

0 commit comments

Comments
 (0)