Coverage for visailu/publish.py: 100.00%

45 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-05 19:49:28 +00:00

1"""Publish a valid YAML model as application specific JSON. 

2 

3Target format is a naive 10 question array with 4 options each array: 

4[ 

5 { 

6 "id": 1, 

7 "question": "A", 

8 "options": [ 

9 { "answer": "1", "isCorrect": false }, 

10 { "answer": "2", "isCorrect": false }, 

11 { "answer": "3", "isCorrect": true }, 

12 { "answer": "4", "isCorrect": false } 

13 ] 

14 }, 

15 ... 

16 { 

17 "id": 10, 

18 "question": "J", 

19 "options": [ 

20 { "answer": "a", "isCorrect": false }, 

21 { "answer": "b", "isCorrect": false }, 

22 { "answer": "c", "isCorrect": true }, 

23 { "answer": "d", "isCorrect": false } 

24 ] 

25 }, 

26] 

27""" 

28 

29import json 

30import pathlib 

31from typing import Any, Union, no_type_check 

32 

33from visailu import ( 

34 OUT_QUESTION_COUNT, 

35 OUT_ANSWERS_COUNT, 

36 log, 

37) 

38from visailu.validate import validate_path 

39 

40AnswerExportType = list[dict[str, Union[str, bool]]] 

41QuestionExportType = dict[str, Union[int, str, AnswerExportType]] 

42QuizExportType = list[QuestionExportType] 

43 

44 

45@no_type_check 

46def etl(data: Any) -> QuizExportType: 

47 """Extract, load, and transform the data.""" 

48 id_export = 1 

49 quiz_export: QuestionExportType = [] 

50 questions = data['questions'] 

51 num_questions = len(questions) 

52 if num_questions < OUT_QUESTION_COUNT or OUT_QUESTION_COUNT < num_questions: 

53 problem = 'too few' if num_questions < OUT_QUESTION_COUNT else 'too many' 

54 log.warning(f'model with {problem} questions {num_questions} instead of 10') 

55 for entry in questions: 

56 question_export = { 

57 'id': id_export, 

58 'question': entry['question'], 

59 'options': [], 

60 } 

61 answers = entry['answers'] 

62 num_answers = len(answers) 

63 if num_answers < OUT_ANSWERS_COUNT or OUT_ANSWERS_COUNT < num_answers: 

64 problem = 'too few' if num_answers < OUT_ANSWERS_COUNT else 'too many' 

65 log.warning(f'model with {problem} answers {num_answers} instead of 4 at question {id_export}') 

66 for option in answers: 

67 question_export['options'].append({'answer': option['answer'], 'isCorrect': option['rating']}) 

68 quiz_export.append(question_export) 

69 id_export += 1 

70 if id_export > OUT_QUESTION_COUNT: 

71 break 

72 

73 if len(quiz_export) < OUT_QUESTION_COUNT: 

74 log.warning(f'quiz with too few questions {len(quiz_export)} instead of 10') 

75 

76 return quiz_export 

77 

78 

79@no_type_check 

80def publish_path(path: str, options=None) -> tuple[int, str, Any]: 

81 """Drive the model publication.""" 

82 code, message, data = validate_path(path) 

83 if code != 0: 

84 return code, message, data 

85 

86 quiz = etl(data) 

87 build_path = pathlib.Path('build') 

88 build_path.mkdir(parents=True, exist_ok=True) 

89 target_path = build_path / (pathlib.Path(path).stem + '.json') 

90 with target_path.open('wt', encoding='utf-8') as handle: 

91 json.dump(quiz, handle, indent=2) 

92 

93 return 0, f'published quiz data at {target_path} (from model at {path})', quiz