Coverage for application / main.py: 33%

49 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-07 06:46 +0000

1import traceback 

2from concurrent.futures import ThreadPoolExecutor, as_completed 

3from json import JSONDecodeError 

4 

5from flask import flash, render_template, request, session 

6 

7from application import app 

8from application.vars.annosaurus import * 

9 

10 

11@app.route('/favicon.ico') 

12def favicon(): 

13 return app.send_static_file('img/favicon.ico') 

14 

15 

16@app.route('/') 

17def index(): 

18 def fetch_json(url, headers=None): 

19 try: 

20 res = requests.get(url, headers=headers) 

21 res.raise_for_status() 

22 return res.json() 

23 except requests.exceptions.RequestException as e: 

24 print(f'\nERROR: failed to fetch {url}: {e}\n') 

25 flash(f'Unable to connect to {url}', 'danger') 

26 except JSONDecodeError: 

27 print(f'\nERROR: failed to parse JSON from {url}\n') 

28 return None 

29 

30 http_requests = [ 

31 dict(name='reviewers', url=f'{app.config["DARC_REVIEW_URL"]}/reviewer/all', headers=app.config['DARC_REVIEW_HEADERS']), 

32 dict(name='stats', url=f'{app.config["DARC_REVIEW_URL"]}/stats', headers=app.config['DARC_REVIEW_HEADERS']), 

33 dict(name='sequences', url=app.config['VARS_SEQUENCE_LIST_URL']), 

34 dict(name='concepts', url=app.config['VARS_CONCEPT_LIST_URL']) 

35 ] 

36 results = {} 

37 with ThreadPoolExecutor(max_workers=4) as executor: 

38 futures = { 

39 executor.submit(fetch_json, url=item['url'], headers=item.get('headers')): item['name'] 

40 for item in http_requests 

41 } 

42 for future in as_completed(futures): 

43 name = futures[future] 

44 results[name] = future.result() 

45 

46 stats = results.get('stats') or {} 

47 session['reviewers'] = results.get('reviewers') or [] 

48 session['vars_video_sequences'] = results.get('sequences') or [] 

49 session['vars_concepts'] = results.get('concepts') or [] 

50 

51 return render_template( 

52 'index.html', 

53 sequences=session['vars_video_sequences'], 

54 unread_comment_count=stats.get('unread_comments', 0), 

55 read_comment_count=stats.get('read_comments', 0), 

56 total_comment_count=stats.get('total_comments', 0), 

57 active_reviewers=stats.get('active_reviewers', []), 

58 ) 

59 

60 

61# video player 

62@app.get('/video') 

63def video(): 

64 data = {'link': request.args.get('link'), 'time': request.args.get('time')} 

65 return render_template('video.html', data=data), 200 

66 

67 

68@app.errorhandler(404) 

69def page_not_found(e): 

70 return render_template('errors/404.html', err=''), 404 

71 

72 

73@app.errorhandler(Exception) 

74def server_error(e): 

75 error = f'{type(e).__name__}: {e}' 

76 print('\nApplication error 😔') 

77 print(error) 

78 print(traceback.format_exc()) 

79 requests.post( 

80 url=f'{app.config.get("DARC_REVIEW_URL")}/log-error', 

81 headers=app.config.get('DARC_REVIEW_HEADERS'), 

82 json={'error': traceback.format_exc()}, 

83 ) 

84 return render_template('errors/500.html', err=error), 500