Skip to content

Commit

Permalink
Implement do_snapshot() and has_changed() methods to determine change…
Browse files Browse the repository at this point in the history
…s in BaseModel
  • Loading branch information
dmach committed Feb 13, 2024
1 parent 82afcef commit 61dd9c0
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
20 changes: 20 additions & 0 deletions osc/util/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/test_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
23 changes: 23 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit 61dd9c0

Please sign in to comment.