Changeset 9db70f7 in flexograder
- Timestamp:
- 11/27/25 11:25:20 (4 months ago)
- Branches:
- fake-data, main, master
- Children:
- 8e6a433
- Parents:
- e70dd79
- Files:
-
- 1 deleted
- 5 edited
-
builder/exam.py (modified) (2 diffs)
-
builder/exam_elements.py (modified) (11 diffs)
-
builder/flexo_entity.py (deleted)
-
builder/question_factory.py (modified) (2 diffs)
-
tests/conftest.py (modified) (2 diffs)
-
tests/test_question_factory.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
builder/exam.py
re70dd79 r9db70f7 145 145 meta = data.get("exam", {}) 146 146 domains = data.get("domains", {}) 147 147 148 148 flexo_id = FlexOID(meta.get("flexo_id")) 149 149 … … 214 214 def to_question_catalog(self, questions, catalog_id, title, author="unknown", version="1.0"): 215 215 catalog = { 216 " meta": {217 " catalog_id": catalog_id,216 "QuestionCatalog": { 217 "flexo_id": catalog_id, 218 218 "title": title, 219 219 "created_on": datetime.utcnow().isoformat() + "Z", -
builder/exam_elements.py
re70dd79 r9db70f7 53 53 return cls.with_domain_id(domain_id="DEF_DEFAULT") 54 54 55 @property56 @abstractmethod57 def qtype(self):58 pass59 60 55 @abstractmethod 61 56 def to_html(self) -> str: … … 77 72 78 73 def __hash__(self): 79 return hash((self.flexo_id, self. qtype))74 return hash((self.flexo_id, self.subtype)) 80 75 81 76 def evaluate(self, answer): … … 123 118 return obj 124 119 125 def to_dict(self): 126 base = super().to_dict() # from FlexoEntity 127 base.update({ 120 def _serialize_content(self): 121 return { 128 122 "topic": self.topic, 129 "qtype": self.qtype, # avoid name clash with built-in type130 123 "text": self.text, 131 124 "media": [m.to_dict() for m in self.media], 132 }) 133 return base 125 } 134 126 135 127 def has_media(self): … … 153 145 def __post_init__(self): 154 146 super().__post_init__() 155 156 @property157 def qtype(self):158 return "instruction"159 147 160 148 @property … … 201 189 super().__post_init__() 202 190 203 @property 204 @abstractmethod 205 def qtype(self): 206 pass 207 208 def to_dict(self): 209 base = super().to_dict() 210 base.update({ 211 "options": [opt.to_dict() for opt in self.options], 212 }) 213 return base 191 def _serialize_content(self): 192 return { 193 "options": [opt.to_dict() for opt in self.options] 194 } 214 195 215 196 @classmethod … … 239 220 @dataclass 240 221 class SingleChoiceQuestion(ChoiceQuestion): 241 242 @property243 def qtype(self):244 return "single_choice"245 222 246 223 def to_html(self) -> str: … … 269 246 @dataclass 270 247 class MultipleChoiceQuestion(ChoiceQuestion): 271 272 @property273 def qtype(self):274 return "multiple_choice"275 248 276 249 def to_html(self) -> str: … … 311 284 validation: Optional[Validation] = None 312 285 313 @property314 def qtype(self):315 return "text"316 317 286 @classmethod 318 287 def from_dict(cls, data): … … 323 292 return obj 324 293 325 def to_dict(self): 326 d = super().to_dict() 327 if self.validation: 328 d["validation"] = self.validation.to_dict() 329 return d 294 def _serialize_content(self): 295 return { 296 "validation": self.validation.to_dict() 297 } 330 298 331 299 def answer_options_for_display(self): … … 355 323 356 324 @dataclass 357 class CandidateIDQuestion(ExamElement):325 class IDForm(ExamElement): 358 326 359 327 fields: List[dict] = field(default_factory=list) 360 361 @property362 def qtype(self):363 return "candidate_id"364 328 365 329 def __post_init__(self): … … 393 357 return [("Last Name, First Name, Personal ID", "0")] 394 358 395 def to_dict(self):396 d = super().to_dict()397 d["fields"] =self.fields398 return d359 def _serialize_content(self): 360 return { 361 "fields": self.fields 362 } 399 363 400 364 @classmethod -
builder/question_factory.py
re70dd79 r9db70f7 5 5 MultipleChoiceQuestion, 6 6 TextQuestion, 7 CandidateIDQuestion,7 IDForm, 8 8 InstructionBlock, 9 9 AnswerOption, … … 33 33 """ 34 34 35 qtype = q.get("qtype")36 if not qtype:37 raise ValueError("Question missing ' qtype'")35 subtype = q.get("subtype") 36 if not subtype: 37 raise ValueError("Question missing 'subtype'") 38 38 39 mapping = { 40 "single_choice": SingleChoiceQuestion, 41 "multiple_choice": MultipleChoiceQuestion, 42 "text": TextQuestion, 43 "instruction": InstructionBlock, 44 "candidate_id": CandidateIDQuestion, 45 } 46 47 cls = mapping.get(qtype) 39 cls = globals()[subtype] 48 40 if not cls: 49 41 raise ValueError(f"Unknown question type: {qtype}") -
tests/conftest.py
re70dd79 r9db70f7 6 6 SingleChoiceQuestion, 7 7 MultipleChoiceQuestion, 8 CandidateIDQuestion,8 IDForm, 9 9 InstructionBlock, 10 10 TextQuestion, … … 31 31 # ────────────────────────────────────────────────────────────── 32 32 33 q_id = CandidateIDQuestion.with_domain_id(domain_id="ADMIN_CANDIDATE",33 q_id = IDForm.with_domain_id(domain_id="ADMIN_CANDIDATE", 34 34 text="Please enter your candidate ID and name.", 35 35 fields=["Name", "Candidate ID"], -
tests/test_question_factory.py
re70dd79 r9db70f7 5 5 6 6 def test_radio_question_autoid(): 7 q = {"domain_id": "WIP_TEST", " qtype": "single_choice", "text": "What is Ohm’s law?",7 q = {"domain_id": "WIP_TEST", "subtype": "SingleChoiceQuestion", "text": "What is Ohm’s law?", 8 8 "options": [{"id": "A", "text": "U = R / I"}, {"id": "B", "text": "U = R * I"}]} 9 9 obj = question_factory(q) … … 16 16 def test_multiple_choice_question_existing_id(): 17 17 Domain.with_domain_id("WIP_TEST") 18 q = {"domain_id": "WIP_TEST", " qtype": "multiple_choice",18 q = {"domain_id": "WIP_TEST", "subtype": "MultipleChoiceQuestion", 19 19 "text": "Select power units"} 20 20 obj = question_factory(q) … … 27 27 def test_text_question_validation_optional(): 28 28 Domain.with_domain_id(domain_id="WIP_TEST") 29 q = {"domain_id": "WIP_TEST", " qtype": "text",29 q = {"domain_id": "WIP_TEST", "subtype": "TextQuestion", 30 30 "text": "Explain", "validation": {"maxlength": 5}} 31 31 obj = question_factory(q)
Note:
See TracChangeset
for help on using the changeset viewer.
