From: Christian Heller Date: Wed, 1 May 2024 15:26:59 +0000 (+0200) Subject: Improve __eq__ of BaseModel to compare all saved attributes; plus minor refactorings. X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/%7B%7B%20web_path%20%7D%7D/%7B%7Bprefix%7D%7D/todo?a=commitdiff_plain;h=704c00a101fc1922158a3a71a043562d34b696ad;p=plomtask Improve __eq__ of BaseModel to compare all saved attributes; plus minor refactorings. --- diff --git a/plomtask/days.py b/plomtask/days.py index 78340e2..9f3aa69 100644 --- a/plomtask/days.py +++ b/plomtask/days.py @@ -30,14 +30,11 @@ class Day(BaseModel[str]): to_save = ['comment'] def __init__(self, date: str, comment: str = '') -> None: - super().__init__(date) - self.id_: str = valid_date(date) + id_ = valid_date(date) + super().__init__(id_) self.datetime = datetime.strptime(self.date, DATE_FORMAT) self.comment = comment - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) and self.date == other.date - def __lt__(self, other: Day) -> bool: return self.date < other.date @@ -69,6 +66,7 @@ class Day(BaseModel[str]): @property def date(self) -> str: """Return self.id_ under the assumption it's a date string.""" + assert isinstance(self.id_, str) return self.id_ @property @@ -90,4 +88,4 @@ class Day(BaseModel[str]): def save(self, db_conn: DatabaseConnection) -> None: """Add (or re-write) self to DB and cache.""" - self.save_core(db_conn, update_with_lastrowid=False) + self.save_core(db_conn) diff --git a/plomtask/db.py b/plomtask/db.py index deeb748..34b5887 100644 --- a/plomtask/db.py +++ b/plomtask/db.py @@ -223,16 +223,34 @@ class BaseModel(Generic[BaseModelId]): items[item.id_] = item return list(items.values()) - def save_core(self, db_conn: DatabaseConnection, - update_with_lastrowid: bool = True) -> None: - """Write bare-bones self (sans connected items), ensuring self.id_.""" + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + msg = 'cannot compare to object of different class' + raise HandledException(msg) + to_hash_me = tuple([self.id_] + + [getattr(self, name) for name in self.to_save]) + to_hash_other = tuple([other.id_] + + [getattr(other, name) for name in other.to_save]) + return hash(to_hash_me) == hash(to_hash_other) + + def save_core(self, db_conn: DatabaseConnection) -> None: + """Write bare-bones self (sans connected items), ensuring self.id_. + + Write both to DB, and to cache. To DB, write .id_ and attributes + listed in cls.to_save. + + Ensure self.id_ by setting it to what the DB command returns as the + last saved row's ID (cursor.lastrowid), EXCEPT if self.id_ already + exists as a 'str', which implies we do our own ID creation (so far + only the case with the Day class, where it's to be a date string. + """ values = tuple([self.id_] + [getattr(self, key) for key in self.to_save]) q_marks = DatabaseConnection.q_marks_from_values(values) table_name = self.table_name cursor = db_conn.exec(f'REPLACE INTO {table_name} VALUES {q_marks}', values) - if update_with_lastrowid: + if not isinstance(self.id_, str): self.id_ = cursor.lastrowid # type: ignore[assignment] self.cache() diff --git a/plomtask/todos.py b/plomtask/todos.py index d53674b..ecdd599 100644 --- a/plomtask/todos.py +++ b/plomtask/todos.py @@ -177,11 +177,11 @@ class Todo(BaseModel[int], ConditionsRelations): potentially_enabled = set() for child in step.children: for condition in child.enables: - potentially_enabled.add(condition) + potentially_enabled.add(condition.id_) children += [make_node(child)] for condition in [c for c in step.conditions if (not c.is_active) - and (c not in potentially_enabled)]: + and (c.id_ not in potentially_enabled)]: children += [make_node(condition)] else: seen = step.id_ in seen_conditions