From 509f2fcee95c0f1ac0e15c127366856476c7d303 Mon Sep 17 00:00:00 2001
From: vlorentz <vlorentz@softwareheritage.org>
Date: Wed, 15 Nov 2023 09:14:20 +0000
Subject: [PATCH] Rename HashableObject to BaseHashableModel and make it a
 subclass of BaseModel

instead of a mix-in class.

A future commit will add a method implemented by both with different signatures that mypy cannot unify yet.
---
 swh/model/model.py            | 19 +++++++++++--------
 swh/model/tests/test_model.py |  4 ++++
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/swh/model/model.py b/swh/model/model.py
index c919df0d..0170bcaf 100644
--- a/swh/model/model.py
+++ b/swh/model/model.py
@@ -382,7 +382,7 @@ def _compute_hash_from_manifest(manifest: bytes) -> Sha1Git:
     return hashlib.new("sha1", manifest).digest()
 
 
-class HashableObject(metaclass=ABCMeta):
+class BaseHashableModel(BaseModel, metaclass=ABCMeta):
     """Mixin to automatically compute object identifier hash when
     the associated model is instantiated."""
 
@@ -412,14 +412,17 @@ class HashableObject(metaclass=ABCMeta):
         return self.id
 
     def check(self) -> None:
-        super().check()  # type: ignore
+        super().check()
 
         if self.id != self.compute_hash():
             raise ValueError("'id' does not match recomputed hash.")
 
 
-class HashableObjectWithManifest(HashableObject):
-    """Derived class of HashableObject, for objects that may need to store
+HashableObject = BaseHashableModel  # deprecated alias
+
+
+class HashableObjectWithManifest(BaseHashableModel):
+    """Derived class of BaseHashableModel, for objects that may need to store
     verbatim git objects as ``raw_manifest`` to preserve original hashes."""
 
     __slots__ = ()
@@ -767,7 +770,7 @@ class TimestampWithTimezone(BaseModel):
 
 
 @attr.s(frozen=True, slots=True, field_transformer=optimize_all_validators)
-class Origin(HashableObject, BaseModel):
+class Origin(BaseHashableModel):
     """Represents a software source: a VCS and an URL."""
 
     object_type: Final = "origin"
@@ -933,7 +936,7 @@ class SnapshotBranch(BaseModel):
 
 
 @attr.s(frozen=True, slots=True, field_transformer=optimize_all_validators)
-class Snapshot(HashableObject, BaseModel):
+class Snapshot(BaseHashableModel):
     """Represents the full state of an origin at a given point in time."""
 
     object_type: Final = "snapshot"
@@ -1651,7 +1654,7 @@ def normalize_discovery_date(value: Any) -> datetime.datetime:
 
 
 @attr.s(frozen=True, slots=True, field_transformer=optimize_all_validators)
-class RawExtrinsicMetadata(HashableObject, BaseModel):
+class RawExtrinsicMetadata(BaseHashableModel):
     object_type: Final = "raw_extrinsic_metadata"
 
     # target object
@@ -1897,7 +1900,7 @@ class RawExtrinsicMetadata(HashableObject, BaseModel):
 
 
 @attr.s(frozen=True, slots=True, field_transformer=optimize_all_validators)
-class ExtID(HashableObject, BaseModel):
+class ExtID(BaseHashableModel):
     object_type: Final = "extid"
 
     extid_type = attr.ib(type=str, validator=generic_type_validator)
diff --git a/swh/model/tests/test_model.py b/swh/model/tests/test_model.py
index f2adc629..248410f9 100644
--- a/swh/model/tests/test_model.py
+++ b/swh/model/tests/test_model.py
@@ -1509,9 +1509,13 @@ def test_object_type(objtype_and_obj):
 
 
 def test_object_type_is_final():
+    checked_classes = set()
     object_types = set()
 
     def check_final(cls):
+        if cls in checked_classes:
+            return
+        checked_classes.add(cls)
         if hasattr(cls, "object_type"):
             assert cls.object_type not in object_types
             object_types.add(cls.object_type)
-- 
GitLab