This repository has been archived by the owner on Oct 31, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathd8error.py
208 lines (186 loc) · 8.98 KB
/
d8error.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
206
207
208
from IPython.core.display import display, HTML, Markdown
import json
import os.path
import csv
import ipywidgets as widgets
import datetime
import traceback
from IPython.display import clear_output
import webbrowser
from IPython.display import Javascript
import functools
import iwut
class Announce:
"""error index, serves as an id on the csv file"""
eindex = 0
def __init__(self, etype, value, tb, tb_offset=None):
self.eindex = Announce.eindex
Announce.eindex += 1
self.etype = etype
self.value = value
self.feedbackRating = 0
self.feedbackMSG = ""
self.errorname = str(etype().__class__.__name__)
self.tb = tb
self.tb_offset = tb_offset
self.resourceList = {}
with open("errorConfig.json", "r") as f:
diction = json.load(f)
exceptionClass = diction.get(self.errorname)
prewrittenMessge = False
if exceptionClass is None:
self.print = False
else:
self.print = True
for i in exceptionClass:
key, items = list(i.items())[0]
if (key in str(value)):
prewrittenMessge = True
self.print = prewrittenMessge
# this generates a semi-readable summary of the traceback, which includes some information about the python code that caused the error
summary = traceback.format_exc().splitlines()
# iterate through traceback object to extract linenumber and bytecode of the first two frames
curr_tb = tb.tb_next # skip the first frame which is the jupyter notebook frame
# get code from jupyter notebook
self.codeToLinenos = []
while curr_tb and len(self.codeToLinenos) < 2:
code = self.parseTraceback(curr_tb)
self.codeToLinenos.append((code, curr_tb.tb_lineno))
curr_tb = curr_tb.tb_next
mode = 'w' if not os.path.isfile("errorLog.csv") else 'a'
if os.path.isfile("errorLog.csv") and Announce.eindex == 1:
with open("errorLog.csv", 'r') as f:
for row in csv.reader(f):
self.eindex = int(row[0])
self.eindex += 1
Announce.eindex = self.eindex + 1
with open('errorLog.csv', mode, newline='') as f:
fieldnames = ['index', 'errorType', 'errorMSG', 'feedbackRating', 'feedbackMSG', 'time', 'codeToLinenos', 'traceSummary']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writerow({"index": self.eindex,
"errorType": self.errorname,
"errorMSG": str(self.value),
"feedbackRating": self.feedbackRating,
"feedbackMSG": self.feedbackMSG,
"time": str(datetime.datetime.now()),
"codeToLinenos": self.codeToLinenos,
"traceSummary":summary})
def parseTraceback(self, tb):
return traceback.extract_tb(tb)[0].line
def tips(self):
etype = self.etype
value = self.value
with open("errorConfig.json", "r") as f:
diction = json.load(f)
exceptionClass = diction.get(self.errorname)
if exceptionClass is not None:
self.default()
for i in exceptionClass:
key, items = list(i.items())[0]
if (key in str(value)):
c=1
for j in items.get("helptext"):
display(Markdown(str(c)+". "+j))
c += 1
def data8(self):
display(Markdown("The Data 8 Reference might be helpful to look over for examples and usage: [Data 8 Reference](http://data8.org/fa21/python-reference.html)"))
def furtherTips(self):
display(Markdown("If you are having more trouble please feel free to consult a staff member at [Office Hours](https://oh.data8.org)\
\n or see the error message below "))
def print(self, i):
display(Markdown)
def title(self):
"## **There seems to be a <font color='red'>" + self.errorname+ "<font>**" + "."
display(Markdown("## **" + self.errorname + "**" + "<font size = '3px'>" + ", line " + str(self.codeToLinenos[0][1]) + "<font>"))
def default(self):
display(Markdown("Here are some possible reasons for your error:"))
def resources(self):
"""Generate helpful resources"""
display(Markdown("Still stuck? Here's some useful resources:"))
self.resourceList = {'Textbook': 'http://data8.org/zero-to-data-8/textbook.html', 'Data 8 Reference': 'http://data8.org/fa21/python-reference.html', 'Office Hours': 'https://oh.data8.org/'}
self.makeResources()
def makeResources(self):
"""Helper method for creating resource buttons based on the resource list for error"""
buttons = []
for text in self.resourceList.keys():
currButton = widgets.Button(description=text,icon="square")
buttons.append(currButton)
output = widgets.Output()
h1 = widgets.HBox(buttons)
display(h1)
def button_click(b1, url):
"""clicking button sends you to resource URL"""
with output:
webbrowser.open(url)
# Configure button on click functions for each of the resources
count = 0
for resPair in (self.resourceList.items()):
buttons[count].on_click(functools.partial(button_click, url=resPair[1]))
count += 1
def feedback(self):
def overwriteRow():
"""rewrites the feedbackRating & feedbackMSG columns on errorLog.csv"""
with open("errorLog.csv", 'r') as f:
reader = csv.reader(f, delimiter=',')
lines = []
for line in reader:
if line[0] == str(self.eindex):
line[3] = self.feedbackRating
line[4] = self.feedbackMSG
lines.append(line)
with open("errorLog.csv", 'w', newline='') as f:
writer = csv.writer(f, delimiter=',')
writer.writerows(lines)
"""create & label a dropdown menu"""
dropdown_label = widgets.Label(value="Was the message you saw useful?")
dropdown = widgets.Dropdown(options=[('', 0),
('Extremely useful', 5),
('Very useful', 4),
('Somewhat useful', 3),
('Slightly useful', 2),
('Not at all useful', 1)],
value=0)
def handle_slider_change(change):
"""on change: rewrites the feedbackRating in the CSV"""
self.feedbackRating = dropdown.value
overwriteRow()
dropdown.observe(handle_slider_change)
"""create & label a textbox"""
textbox_label = widgets.Label(value="Any other feedback?")
textbox = widgets.Text(value="",
placeholder="Press enter to submit.",
layout=widgets.Layout(width='50%', margin='0px 8px 0px 0px', padding='0px'))
def submit_text(t):
"""on textbox submit: remove other fields and replace with a thank you message"""
self.feedbackMSG = t.value
accordion.children = [widgets.Label(value="Thank you for your feedback!")]
overwriteRow()
textbox.on_submit(submit_text)
"""create a submit button for the textbox"""
submit_button = widgets.Button(description="Submit",
layout=widgets.Layout(width='10%', min_width='80px'))
def on_btn_click(b):
"""on button click: submits textbox and replaces other fields with a thank you message"""
submit_text(textbox)
submit_button.on_click(on_btn_click)
"""bundle together widgets for a cleaner output"""
dropdownBox = widgets.VBox([dropdown_label, dropdown])
submitBox = widgets.HBox([textbox, submit_button])
submitBox.layout.align_items = 'center'
textboxBox = widgets.VBox([textbox_label, submitBox])
output = widgets.VBox([dropdownBox, textboxBox])
accordion = widgets.Accordion([output])
accordion.set_title(0, ' Feedback Form')
display(accordion)
def test_exception(self, etype, value, tb, tb_offset=None):
try:
announce = Announce(etype, value, tb, tb_offset)
if announce.print:
announce.title()
display(iwut.get_wut_traceback(etype, value, tb, tb_offset))
announce.tips()
announce.resources()
announce.feedback()
except:
display(iwut.get_wut_traceback(etype, value, tb, tb_offset))
get_ipython().set_custom_exc((Exception,), test_exception)