diff --git a/osc/util/models.py b/osc/util/models.py index c95de6e9bf..71e586feba 100644 --- a/osc/util/models.py +++ b/osc/util/models.py @@ -385,8 +385,16 @@ def __init__(self, **kwargs): for name, field in self.__fields__.items(): field.validate_type(getattr(self, name)) + self._snapshot = {} # copy of ``self.dict()`` so we can determine if the object has changed later on + self.do_snapshot() + self._allow_new_attributes = False + def __eq__(self, other): + if type(self) != type(other): + return False + return self.dict() == other.dict() + def dict(self): result = {} for name, field in self.__fields__.items(): @@ -402,6 +410,18 @@ def dict(self): return result + def do_snapshot(self): + """ + Save ``self.dict()`` result as a new starting point for detecting changes in the object data. + """ + self._snapshot = self.dict() + + def has_changed(self): + """ + Determine if the object data has changed since its creation or the last snapshot. + """ + return self.dict() != self._snapshot + class XmlModel(BaseModel): XML_TAG = None diff --git a/tests/test_conf.py b/tests/test_conf.py index 0f4db6017c..80da23209c 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -517,7 +517,7 @@ def test_api_host_options(self): conf1 = osc.conf.Options() conf2 = osc.conf.Options() - self.assertNotEqual(conf1, conf2) + self.assertEqual(conf1, conf2) # models are compared by their contents now self.assertNotEqual(id(conf1), id(conf2)) self.assertNotEqual(id(conf1.api_host_options), id(conf2.api_host_options)) diff --git a/tests/test_models.py b/tests/test_models.py index df6e512511..89f9d98186 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -316,6 +316,29 @@ class Model(BaseModel): self.assertEqual(m.quiet, False) self.assertEqual(m.verbose, True) + def test_has_changed(self): + class TestSubmodel(BaseModel): + text: str = Field(default="default") + + class TestModel(BaseModel): + field: Optional[List[TestSubmodel]] = Field(default=[]) + + m = TestModel() + self.assertFalse(m.has_changed()) + + # a new instance of empty list + m.field = [] + self.assertFalse(m.has_changed()) + + m.field = [{"text": "one"}, {"text": "two"}] + self.assertTrue(m.has_changed()) + + m.do_snapshot() + + # a new instance of list with new instances of objects with the same data + m.field = [{"text": "one"}, {"text": "two"}] + self.assertFalse(m.has_changed()) + if __name__ == "__main__": unittest.main()