From 2ac02c3aac52129b58ad20c9d5a8163596f768e6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Sun, 13 Dec 2020 14:24:20 +0100 Subject: 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 2bbf0848..85a713f0 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 f2a137d5..9a7c119c 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]} -- cgit v1.2.3