Changeset 0f50a20 in flexograder
- Timestamp:
- 11/09/25 10:24:21 (2 months ago)
- Branches:
- master
- Children:
- e77bfb3
- Parents:
- 066f7d9
- Files:
-
- 5 edited
-
builder/exam.py (modified) (3 diffs)
-
builder/question_catalog.py (modified) (1 diff)
-
gui/gui.py (modified) (7 diffs)
-
gui/session_manager.py (modified) (3 diffs)
-
tests/test_question_catalog.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
builder/exam.py
r066f7d9 r0f50a20 82 82 def default(cls): 83 83 return cls() 84 85 @staticmethod86 def _qid_of(q: ExamElement | str) -> str:87 if isinstance(q, str):88 return q89 # prefer flexo_id, fallback to id if needed90 return str(getattr(q, "flexo_id", getattr(q, "id")))91 92 84 def add_question(self, question: ExamElement): 93 85 self.questions.append(question) 94 86 95 87 def remove_question(self, qid: str): 96 qid = str(qid) 97 self.questions = [q for q in self.questions if self._qid_of(q) != qid] 88 self.questions = [q for q in self.questions if q.flexo_id != qid] 98 89 self.layout.purge_question(qid) 99 90 100 91 def get_question_by_id(self, qid: str) -> Optional[ExamElement]: 101 92 qid = str(qid) 102 return next((q for q in self.questions if self._qid_of(q)== qid), None)93 return next((q for q in self.questions if q.flexo_id == qid), None) 103 94 104 95 def __post_init__(self): … … 217 208 def add_question_to_page(self, page_title: str, question: ExamElement | str): 218 209 """Assign a question to a page (by object or id).""" 219 qid = self._qid_of(question) 220 self.layout.assign(page_title, qid) 210 self.layout.assign(page_title, question.flexo_id) 221 211 222 212 # FIXME: This needs to be addressed somewhere else now … … 307 297 continue 308 298 # prefer flexo_id as the answer key 309 key = self._qid_of(q) 310 submitted = submission.get_answer_for(key) 299 submitted = submission.get_answer_for(q.flexo_id) 311 300 score = q.evaluate(submitted) 312 301 total_score += score -
builder/question_catalog.py
r066f7d9 r0f50a20 111 111 int(q.id.split("_")[-1]) 112 112 for q in self.questions 113 if q. id.startswith(f"{abbrev}_") and q.id.split("_")[-1].isdigit()113 if q.flexo_id.startswith(f"{abbrev}_") and q.flexo_id.split("_")[-1].isdigit() 114 114 ] 115 115 next_num = max(existing_numbers, default=0) + 1 -
gui/gui.py
r066f7d9 r0f50a20 48 48 self._recent_actions = [] 49 49 self.domain_set = set() 50 self.clipboard = [] # holds copied /cutQuestion objects51 self.clipboard_action = None # "copy" or "cut"50 self.clipboard = [] # holds copied Question objects 51 self.clipboard_action = None # "copy" 52 52 self.clipboard_source_catalog = None 53 53 self.create_menu() … … 58 58 self.session = SessionManager(catalog_manager=self.catalog_manager, 59 59 exam_manager=self.exam_manager) 60 self.session.load() 60 geometry = self.session.load() 61 self.geometry(geometry) 61 62 self.refresh_catalog_list() 62 63 self.refresh_exam_list() … … 201 202 ttk.Button(frame_buttons, text="Copy", 202 203 command=self.copy_selected_question).grid(row=0, column=1, padx=2, sticky="ew") 203 ttk.Button(frame_buttons, text="Cut",204 command=self.cut_selected_question).grid(row=0, column=2, padx=2, sticky="ew")205 204 ttk.Button(frame_buttons, text="Paste", 206 205 command=self.paste_selected_question).grid(row=0, column=3, padx=2, sticky="ew") … … 236 235 237 236 ttk.Label(frame_right, text="Question Text").grid(row=0, column=0, sticky="w") 238 self.txt_question = tk.Text(frame_right, wrap="word", height= 5)237 self.txt_question = tk.Text(frame_right, wrap="word", height=3) 239 238 self.txt_question.grid(row=1, column=0, sticky="nsew") 240 239 … … 352 351 # Always provide deterministic order (e.g. by question ID) 353 352 return sorted(self.active_catalog.questions, key=lambda q: q.id) 354 355 def switch_catalog(self):356 catalogs = self.catalog_manager.list_catalogs()357 if not catalogs:358 messagebox.showinfo("No Catalogs", "No catalogs loaded.")359 return360 361 selection = simpledialog.askstring(362 "Switch Catalog",363 f"Available catalogs:\n{', '.join(catalogs)}\nEnter catalog ID to activate:",364 )365 if not selection:366 return367 368 try:369 self.catalog_manager.set_active(selection)370 self.refresh_question_tree()371 self.log_action(f"Switched - Active catalog: {selection}")372 except ValueError:373 messagebox.showerror("Invalid", f"No catalog with ID '{selection}'")374 self.refresh_status_bar()375 353 376 354 def create_catalog(self): … … 653 631 text = q.text.strip().replace("\n", " ") 654 632 if len(text) > 100: 655 text = text [:97] + "..."633 text = text # [:97] + "..." 656 634 657 635 # Try to display a readable status name … … 783 761 target.add_questions([new_q]) 784 762 transferred.append(new_q) 785 786 elif self.clipboard_action == "cut":787 # Move from source to target788 source = self.catalog_manager.catalogs[self.clipboard_source_catalog]789 for q in list(self.clipboard):790 # Remove from source791 try:792 source.remove(q.id)793 except ValueError:794 pass # maybe already removed or invalid state795 # Add to target796 target.add_questions([q])797 transferred.append(q)798 799 763 else: 800 764 messagebox.showwarning("Paste", f"Unknown clipboard action: {self.clipboard_action}") -
gui/session_manager.py
r066f7d9 r0f50a20 32 32 for ex_id, each in self.exam_manager.exams.items(): 33 33 path = self.exam_dir / f"{ex_id}.json" 34 34 35 35 if isinstance(each.flexo_id, str): 36 36 print(f"[WARN] Catalog {each.title} has string flexo_id: {each.flexo_id}") … … 51 51 def load(self): 52 52 """Restore the previous workspace if available.""" 53 geometry = "800x600+50+50" 53 54 if not self.session_file.exists(): 54 55 print("[Session] No previous session found.") 55 return 56 57 geometry = "800x600+50+50" 56 return geometry 58 57 59 58 try: … … 62 61 63 62 # 1. Restore window 64 65 63 geometry = data["geometry"] 66 64 -
tests/test_question_catalog.py
r066f7d9 r0f50a20 31 31 qid = sample_question.flexo_id 32 32 assert any(q.flexo_id == qid for q in catalog.questions) 33 assert catalog.remove(sample_question. id) # removes if DRAFT33 assert catalog.remove(sample_question.flexo_id) # removes if DRAFT 34 34 assert not any(q.flexo_id == qid for q in catalog.questions) 35 35 … … 38 38 sample_question.approve() 39 39 with pytest.raises(ValueError): 40 catalog.remove(sample_question. id)40 catalog.remove(sample_question.flexo_id) 41 41 42 42 def test_next_question_id(catalog):
Note:
See TracChangeset
for help on using the changeset viewer.
