Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8ec12a7

Browse files
committed
Show internal errors
1 parentdaa0881 commit8ec12a7

File tree

4 files changed

+97
-68
lines changed

4 files changed

+97
-68
lines changed

‎backend/main/exercises.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def check_result(func, inputs, expected_result):
117117
try:
118118
result=func(**inputs)
119119
exceptExceptionase:
120-
result=format_exception_string(e)
120+
result=format_exception_string()
121121

122122
result=clean_result(result)
123123
expected_result=clean_result(expected_result)

‎backend/main/utils/__init__.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,13 @@ def unwrapped_markdown(s):
5454
returns
5555

5656

57-
defformat_exception_string(e):
58-
return''.join(traceback.format_exception_only(type(e),e))
57+
defformat_exception_string():
58+
return''.join(traceback.format_exception_only(*sys.exc_info()[:2]))
59+
60+
61+
defprint_exception():
62+
print(format_exception_string(),file=sys.stderr)
63+
5964

6065

6166
defrow_to_dict(row):

‎backend/main/views.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ def run_code(self, code, source):
128128

129129
forcallinbirdseye_objects["calls"]:
130130
call["function_id"]=function_ids[call["function_id"]]
131-
call["start_time"]=datetime.fromisoformat(call["start_time"])
131+
ifisinstance(call["start_time"],str):
132+
call["start_time"]=datetime.fromisoformat(call["start_time"])
132133
call=eye.db.Call(**call)
133134
session.add(call)
134135
# TODO get correct call from top level

‎backend/main/worker.py‎

Lines changed: 87 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
importqueue
99
importresource
1010
importsys
11+
importtraceback
1112
fromcodeimportInteractiveConsole
1213
fromcollectionsimportdefaultdict
1314
fromdatetimeimportdatetime
@@ -25,7 +26,7 @@
2526
fromsnoopimportsnoop
2627

2728
frommain.textimportpages
28-
frommain.utilsimportformat_exception_string,rows_to_dicts
29+
frommain.utilsimportrows_to_dicts,print_exception
2930
frommain.workers.communicationsimportAbstractCommunications,ThreadCommunications
3031

3132
log=logging.getLogger(__name__)
@@ -87,6 +88,14 @@ def __init__(self, *args, **kwargs):
8788
console=InteractiveConsole()
8889

8990

91+
defexecute(code_obj):
92+
try:
93+
# noinspection PyTypeChecker
94+
exec(code_obj,console.locals)
95+
exceptException:
96+
print_exception()
97+
98+
9099
defrunner(code_source,code):
91100
ifcode_source=="shell":
92101
console.push(code)
@@ -104,46 +113,41 @@ def runner(code_source, code):
104113

105114
try:
106115
code_obj=compile(code,filename,"exec")
107-
exceptSyntaxErrorase:
108-
print(format_exception_string(e),file=sys.stderr)
116+
exceptSyntaxError:
117+
print_exception()
109118
return {}
110119

111120
birdseye_objects=None
112121

113-
try:
114-
ifcode_source=="snoop":
115-
config=snoop.Config(
116-
columns=(),
117-
out=sys.stdout,
118-
color=True,
119-
)
120-
tracer=config.snoop()
121-
tracer.variable_whitelist=set()
122-
fornodeinast.walk(ast.parse(code)):
123-
ifisinstance(node,ast.Name):
124-
name=node.id
125-
tracer.variable_whitelist.add(name)
126-
tracer.target_codes.add(code_obj)
127-
withtracer:
128-
exec(code_obj,console.locals)
129-
elifcode_source=="birdseye":
130-
eye=BirdsEye("sqlite://")
131-
traced_file=eye.compile(code,filename)
132-
eye._trace('<module>',filename,traced_file,traced_file.code,'module',code)
133-
try:
134-
exec(traced_file.code,eye._trace_methods_dict(traced_file))
135-
finally:
136-
witheye.db.session_scope()assession:
137-
objects=session.query(eye.db.Call,eye.db.Function).all()
138-
calls,functions= [rows_to_dicts(set(column))forcolumninzip(*objects)]
139-
birdseye_objects=dict(calls=calls,functions=functions)
140-
else:
141-
exec(code_obj,console.locals)
142-
143-
exceptExceptionase:
144-
print(format_exception_string(e),file=sys.stderr)
122+
ifcode_source=="snoop":
123+
config=snoop.Config(
124+
columns=(),
125+
out=sys.stdout,
126+
color=True,
127+
)
128+
tracer=config.snoop()
129+
tracer.variable_whitelist=set()
130+
fornodeinast.walk(ast.parse(code)):
131+
ifisinstance(node,ast.Name):
132+
name=node.id
133+
tracer.variable_whitelist.add(name)
134+
tracer.target_codes.add(code_obj)
135+
withtracer:
136+
execute(code_obj)
137+
elifcode_source=="birdseye":
138+
eye=BirdsEye("sqlite://")
139+
traced_file=eye.compile(code,filename)
140+
eye._trace('<module>',filename,traced_file,traced_file.code,'module',code)
141+
console.locals=eye._trace_methods_dict(traced_file)
142+
execute(traced_file.code)
143+
witheye.db.session_scope()assession:
144+
objects=session.query(eye.db.Call,eye.db.Function).all()
145+
calls,functions= [rows_to_dicts(set(column))forcolumninzip(*objects)]
146+
birdseye_objects=dict(calls=calls,functions=functions)
147+
else:
148+
execute(code_obj)
145149

146-
returndict(birdseye_objects=birdseye_objects)
150+
returnbirdseye_objects
147151

148152

149153
@lru_cache
@@ -202,8 +206,7 @@ def set_limits():
202206
resource.setrlimit(resource.RLIMIT_NOFILE, (0,0))
203207

204208

205-
defput_result(
206-
q,*,
209+
defmake_result(
207210
passed=False,
208211
message='',
209212
awaiting_input=False,
@@ -217,16 +220,31 @@ def put_result(
217220
ifoutput_partsisNone:
218221
output_parts=output_buffer.pop()
219222

220-
q.put(dict(
223+
returndict(
221224
passed=passed,
222225
message=message,
223226
awaiting_input=awaiting_input,
224227
output=output,
225228
output_parts=output_parts,
226229
birdseye_objects=birdseye_objects,
227-
))
230+
)
228231

229-
returnoutput
232+
233+
definternal_error_result():
234+
output=f"""
235+
INTERNAL ERROR IN COURSE:
236+
=========================
237+
238+
{"".join(traceback.format_exception(*sys.exc_info()))}
239+
240+
This is an error in our code, not yours.
241+
Consider using the Feedback button in the top-right menu
242+
to explain what led up to this.
243+
"""
244+
returnmake_result(
245+
output=output,
246+
output_parts=[dict(color="red",text=output)],
247+
)
230248

231249

232250
defworker_loop_in_thread(*args):
@@ -244,15 +262,15 @@ def worker_loop(task_queue, input_queue, result_queue):
244262

245263
whileTrue:
246264
entry=task_queue.get()
247-
run_code(entry,input_queue,result_queue)
265+
try:
266+
run_code(entry,input_queue,result_queue)
267+
exceptException:
268+
result_queue.put(internal_error_result())
248269

249270

250271
defrun_code(entry,input_queue,result_queue):
251272
defreadline():
252-
put_result(
253-
result_queue,
254-
awaiting_input=True,
255-
)
273+
result_queue.put(make_result(awaiting_input=True))
256274
returninput_queue.get()
257275

258276
sys.stdin.readline=readline
@@ -262,7 +280,7 @@ def readline():
262280
try:
263281
sys.stdout=output_buffer.stdout
264282
sys.stderr=output_buffer.stderr
265-
runner_result=runner(entry['source'],entry['input'])
283+
birdseye_objects=runner(entry['source'],entry['input'])
266284
finally:
267285
sys.stdout=orig_stdout
268286
sys.stderr=orig_stderr
@@ -280,13 +298,12 @@ def readline():
280298
else:
281299
passed=step_result
282300

283-
put_result(
284-
result_queue,
301+
result_queue.put(make_result(
285302
passed=passed,
286303
message=message,
287304
output=output,
288-
birdseye_objects=runner_result.get("birdseye_objects"),
289-
)
305+
birdseye_objects=birdseye_objects,
306+
))
290307

291308

292309
classUserProcess:
@@ -325,6 +342,14 @@ def handle_entry(self, entry):
325342
self.task_queue.put(entry)
326343

327344
defawait_result(self,callback):
345+
try:
346+
result=self._await_result()
347+
exceptException:
348+
result=internal_error_result()
349+
self.awaiting_input=result["awaiting_input"]
350+
callback(result)
351+
352+
def_await_result(self):
328353
# TODO cancel if result was cancelled by a newer handle_entry
329354
result=None
330355
whileresultisNone:
@@ -336,20 +361,15 @@ def await_result(self, callback):
336361
ifalive:
337362
self.process.terminate()
338363
self.start_process()
339-
result=dict(
364+
result=make_result(
340365
output_parts=[
341366
dict(color='red',text='The process died.\n'),
342367
dict(color='red',text='Your code probably took too long.\n'),
343368
dict(color='red',text='Maybe you have an infinite loop?\n'),
344369
],
345-
passed=False,
346-
message='',
347370
output='The process died.',
348-
awaiting_input=False,
349-
birdseye_objects=None,
350371
)
351-
self.awaiting_input=result["awaiting_input"]
352-
callback(result)
372+
returnresult
353373

354374

355375
defmaster_consumer_loop(comms:AbstractCommunications):
@@ -360,16 +380,19 @@ def master_consumer_loop(comms: AbstractCommunications):
360380
whileTrue:
361381
entry=comms.recv_entry()
362382
user_id=str(entry["user_id"])
363-
user_process=user_processes[user_id]
364-
user_process.handle_entry(entry)
365383

366384
defcallback(result):
367385
comms.send_result(user_id,result)
368386

369-
Thread(
370-
target=user_process.await_result,
371-
args=[callback],
372-
).start()
387+
try:
388+
user_process=user_processes[user_id]
389+
user_process.handle_entry(entry)
390+
Thread(
391+
target=user_process.await_result,
392+
args=[callback],
393+
).start()
394+
exceptException:
395+
callback(internal_error_result())
373396

374397

375398
@lru_cache()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp