1- import inspect
21import json
32import logging
3+ import traceback
44from datetime import datetime
55from io import StringIO
66from pathlib import Path
1515from django .contrib .auth .mixins import LoginRequiredMixin
1616from django .contrib .messages .views import SuccessMessageMixin
1717from django .forms import ModelForm
18- from django .http import JsonResponse ,HttpResponseBadRequest , HttpResponse
18+ from django .http import JsonResponse ,HttpResponse
1919from django .views import View
2020from django .views .generic import CreateView
2121from django_user_agents .utils import get_user_agent
2828from main .models import CodeEntry ,ListEmail
2929from main .text import Page ,page_slugs_list ,pages ,ExerciseStep ,clean_program
3030from main .utils .django import PlaceHolderForm
31- from main .worker import worker_result
31+ from main .workers . master import worker_result
3232
3333log = logging .getLogger (__name__ )
3434
3535
3636def api_view (request ,method_name ):
37- body = request .body
3837try :
3938method = getattr (API (request ),method_name )
40- except AttributeError :
41- log .error ('Unknown method %s, body = %s' ,method_name ,body )
42- return HttpResponseBadRequest ()
43- try :
39+ body = request .body
4440body = body .decode ('utf8' )
45- except UnicodeDecodeError :
46- log .exception ('Failed to decode %s' ,body )
47- return HttpResponseBadRequest ()
48- log .info ('API request: method = %s, body = %s' ,method_name ,body )
49- try :
5041args = json .loads (body )
51- except ValueError as e :
52- log .error ('JSON decode error: %s' ,e )
53- return HttpResponseBadRequest ()
54- signature = inspect .signature (method )
55- try :
56- signature .bind (** args )
57- except TypeError as e :
58- log .error (e )
59- return HttpResponseBadRequest ()
60- for arg_name ,hint in get_type_hints (method ).items ():
61- if arg_name == 'return' :
62- continue
63- arg = args [arg_name ]
64- if not isinstance (arg ,hint ):
65- log .warning (
66- 'Incorrect type for argument %s = %r of method %s: found %s, expected %s' ,
67- arg_name ,arg ,method_name ,arg .__class__ .__name__ ,hint .__name__ )
68- result = method (** args )
69- if not isinstance (result ,dict ):
70- result = {'result' :result }
71- return JsonResponse (result ,json_dumps_params = dict (indent = 4 ,sort_keys = True ))
42+ for arg_name ,hint in get_type_hints (method ).items ():
43+ if arg_name == 'return' :
44+ continue
45+ arg = args [arg_name ]
46+ if not isinstance (arg ,hint ):
47+ log .warning (
48+ 'Incorrect type for argument %s = %r of method %s: found %s, expected %s' ,
49+ arg_name ,arg ,method_name ,arg .__class__ .__name__ ,hint .__name__ )
50+ result = method (** args )
51+ if not isinstance (result ,dict ):
52+ result = {'result' :result }
53+ except Exception :
54+ result = dict (
55+ error = dict (
56+ traceback = traceback .format_exc (),
57+ )
58+ )
59+ return JsonResponse (result )
7260
7361
7462class API :
@@ -107,6 +95,9 @@ def run_code(self, code, source):
10795entry .output = result ["output" ]
10896entry .save ()
10997
98+ if result ["error" ]:
99+ return dict (error = result ["error" ])
100+
110101if result ["passed" ]:
111102self .move_step (1 )
112103
@@ -128,7 +119,8 @@ def run_code(self, code, source):
128119
129120for call in birdseye_objects ["calls" ]:
130121call ["function_id" ]= function_ids [call ["function_id" ]]
131- call ["start_time" ]= datetime .fromisoformat (call ["start_time" ])
122+ if isinstance (call ["start_time" ],str ):
123+ call ["start_time" ]= datetime .fromisoformat (call ["start_time" ])
132124call = eye .db .Call (** call )
133125session .add (call )
134126# TODO get correct call from top level