[rtems-central commit] items: Add Item.digest()

Sebastian Huber sebh at rtems.org
Mon Dec 14 11:05:09 UTC 2020


Module:    rtems-central
Branch:    master
Commit:    2ac02c3aac52129b58ad20c9d5a8163596f768e6
Changeset: http://git.rtems.org/rtems-central/commit/?id=2ac02c3aac52129b58ad20c9d5a8163596f768e6

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Sun Dec 13 14:24:20 2020 +0100

items: Add Item.digest()

---

 rtemsspec/items.py                 | 31 +++++++++++++++++++++++++++++++
 rtemsspec/tests/test_items_item.py | 13 +++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/rtemsspec/items.py b/rtemsspec/items.py
index 2bbf084..85a713f 100644
--- a/rtemsspec/items.py
+++ b/rtemsspec/items.py
@@ -25,6 +25,7 @@
 # POSSIBILITY OF SUCH DAMAGE.
 
 from contextlib import contextmanager
+import hashlib
 import os
 import pickle
 import string
@@ -136,6 +137,29 @@ def normalize_key_path(key_path: str, prefix: str = "") -> str:
     return os.path.normpath(key_path)
 
 
+_TYPES = {
+    type(True): "B".encode("utf-8"),
+    type(1.0): "F".encode("utf-8"),
+    type(1): "I".encode("utf-8"),
+    type(None): "N".encode("utf-8"),
+    type(""): "S".encode("utf-8"),
+}
+
+
+def _hash_data(data, state) -> None:
+    if isinstance(data, list):
+        for value in data:
+            _hash_data(value, state)
+    elif isinstance(data, dict):
+        for key, value in sorted(data.items()):
+            if not key.startswith("_"):
+                state.update(key.encode("utf-8"))
+                _hash_data(value, state)
+    else:
+        state.update(_TYPES[type(data)])
+        state.update(str(data).encode("utf-8"))
+
+
 class Item:
     """ Objects of this class represent a specification item. """
 
@@ -174,6 +198,13 @@ class Item:
         """ Returns the cache of the items. """
         return self._cache
 
+    @property
+    def digest(self) -> str:
+        """ Returns the digest of the item data. """
+        state = hashlib.sha512()
+        _hash_data(self._data, state)
+        return state.hexdigest()
+
     def get(self, key: str, default: Any) -> Any:
         """
         Gets the attribute value if the attribute exists, otherwise the
diff --git a/rtemsspec/tests/test_items_item.py b/rtemsspec/tests/test_items_item.py
index f2a137d..9a7c119 100644
--- a/rtemsspec/tests/test_items_item.py
+++ b/rtemsspec/tests/test_items_item.py
@@ -91,6 +91,19 @@ def test_cache():
     assert item.cache == item_cache
 
 
+def test_digest():
+    i = Item(EmptyItemCache(), "i", {})
+    assert i.digest == "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+    i["_ignored"] = "nix"
+    assert i.digest == "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+    i["a"] = {"b": ["c", 1, False, 1.25], "d": None}
+    assert i.digest == "24944e62a4e79b109c5fa97264b8c2fd694a630ede9a82ca7de36a64d01cbc902d29611490cef78e915b44b022b622de058fed2e4bdda394cb37ab9636d06925"
+    i["a"] = {"b": ["e", 1, False, 1.25], "d": None}
+    assert i.digest == "da696508ae767be7d34f16d51a2fe151a942c213596f5de4baf3c048ee519dd97dc19ab813c8730b861fad4c9c82f18652ad87402c84f80aaa59d24f3ed83c20"
+    i["a"] = {"b": ["e", "1", False, 1.25], "d": None}
+    assert i.digest == "7404cafe87a132de131d1e88170ce6d671de36bba811f9a10892a82a21a8e923f7596838d0f9cced24fe34620485603165efd9f64fffb2363c96253fd640b086"
+
+
 def test_get_key_path():
     data = {}
     data["a"] = {"b": "c", "d": [1, 2, 3]}



More information about the vc mailing list