# tests/stubs/single_choice_question.py import pytest from datetime import datetime from dataclasses import dataclass, field from typing import List from flexoentity import FlexOID, FlexoEntity, EntityType, EntityState, Domain @pytest.fixture def fixed_datetime(monkeypatch): class FixedDate(datetime): @classmethod def now(cls, tz=None): return datetime(2025, 11, 1, tzinfo=tz) monkeypatch.setattr("flexoentity.id_factory.datetime", FixedDate) return FixedDate @dataclass class AnswerOption: id: str text: str points: float = 0.0 def to_dict(self): return {"id": self.id, "text": self.text, "points": self.points} @classmethod def from_dict(cls, data): return cls( id=data.get("id", ""), text=data.get("text", ""), points=data.get("points", 0.0) ) @dataclass class SingleChoiceQuestion(FlexoEntity): """A minimal stub to test FlexoEntity integration.""" ENTITY_TYPE = EntityType.ITEM text: str = "" options: List[AnswerOption] = field(default_factory=list) def __post_init__(self): # If no FlexOID yet, generate a draft ID now. if not getattr(self, "flexo_id", None): self.flexo_id = FlexOID.safe_generate( domain=self.domain_id, entity_type=SingleChoiceQuestion.ENTITY_TYPE.value, # 'I' estate=EntityState.DRAFT.value, # 'D' text=self.text_seed or self.text, version=1, ) @classmethod def default(cls): return cls() def to_dict(self): base = super().to_dict() base.update({ "text": self.text, "options": [opt.to_dict() for opt in self.options], }) return base @property def text_seed(self) -> str: """Include answer options (and points) for deterministic ID generation.""" joined = "|".join( f"{opt.text.strip()}:{opt.points}" for opt in sorted(self.options, key=lambda o: o.text.strip().lower()) ) return f"{self.text}{joined}" @classmethod def from_dict(cls, data): obj = cls(text=data.get("text", ""), options=[AnswerOption.from_dict(o) for o in data.get("options", [])], ) # restore FlexoEntity core fields if "flexo_id" in data: obj.flexo_id = FlexOID.parsed(data["flexo_id"]) return obj @pytest.fixture def sample_domain(): domain_id = "PY_ARITHM" flexo_id = FlexOID.safe_generate(domain_id=domain_id, entity_type=EntityType.DOMAIN.value, state=EntityState.DRAFT.value, text=domain_id) return Domain(flexo_id=flexo_id, fullname="PYTHON_ARITHMETIC", description="ALL ABOUT ARITHMETIC IN PYTHON") @pytest.fixture def sample_question(sample_domain): flexo_id = FlexOID.safe_generate(domain_id=sample_domain.domain_id, entity_type=EntityType.ITEM.value, state=EntityState.DRAFT.value, text="What is 2 + 2") q = SingleChoiceQuestion(flexo_id=flexo_id, text="What is 2 + 2?", options=[]) q._update_fingerprint() return q