From bea256e39037ac31fd1d075845ccf2bc71d4cb35 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz <vlorentz@softwareheritage.org> Date: Tue, 7 Jul 2020 15:12:44 +0200 Subject: [PATCH] Make SWHID immutable and hashable. --- swh/model/identifiers.py | 16 +++++--- swh/model/test_identifiers.py | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 swh/model/test_identifiers.py diff --git a/swh/model/identifiers.py b/swh/model/identifiers.py index 3c0a46eb..1e212eb8 100644 --- a/swh/model/identifiers.py +++ b/swh/model/identifiers.py @@ -8,10 +8,11 @@ import datetime import hashlib from functools import lru_cache -from typing import Any, Dict, NamedTuple +from typing import Any, Dict, NamedTuple, Union from deprecated import deprecated +from .collections import ImmutableDict from .exceptions import ValidationError from .fields.hashes import validate_sha1 from .hashutil import hash_git_data, hash_to_hex, MultiHash @@ -656,7 +657,7 @@ _SWHID = NamedTuple( ("scheme_version", int), ("object_type", str), ("object_id", str), - ("metadata", Dict[str, Any]), + ("metadata", ImmutableDict[str, Any]), ], ) @@ -707,7 +708,7 @@ class SWHID(_SWHID): scheme_version: int = SWHID_VERSION, object_type: str = "", object_id: str = "", - metadata: Dict[str, Any] = {}, + metadata: Union[ImmutableDict[str, Any], Dict[str, Any]] = ImmutableDict(), ): o = _object_type_map.get(object_type) if not o: @@ -730,7 +731,12 @@ class SWHID(_SWHID): validate_sha1(object_id) # can raise if invalid hash object_id = hash_to_hex(object_id) return super().__new__( - cls, namespace, scheme_version, object_type, object_id, metadata + cls, + namespace, + scheme_version, + object_type, + object_id, + ImmutableDict(metadata), ) def __str__(self) -> str: @@ -764,7 +770,7 @@ def swhid( object_type: str, object_id: str, scheme_version: int = 1, - metadata: Dict[str, Any] = {}, + metadata: Union[ImmutableDict[str, Any], Dict[str, Any]] = ImmutableDict(), ) -> str: """Compute :ref:`persistent-identifiers` diff --git a/swh/model/test_identifiers.py b/swh/model/test_identifiers.py new file mode 100644 index 00000000..412e00a0 --- /dev/null +++ b/swh/model/test_identifiers.py @@ -0,0 +1,72 @@ +# Copyright (C) 2020 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from swh.model.identifiers import SWHID + + +def test_swhid_hash(): + object_id = "94a9ed024d3859793618152ea559a168bbcbb5e2" + + assert hash(SWHID(object_type="directory", object_id=object_id)) == hash( + SWHID(object_type="directory", object_id=object_id) + ) + + assert hash( + SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) + ) == hash( + SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) + ) + + # Different order of the dictionary, so the underlying order of the tuple in + # ImmutableDict is different. + assert hash( + SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) + ) == hash( + SWHID( + object_type="directory", + object_id=object_id, + metadata={"baz": "qux", "foo": "bar"}, + ) + ) + + +def test_swhid_eq(): + object_id = "94a9ed024d3859793618152ea559a168bbcbb5e2" + + assert SWHID(object_type="directory", object_id=object_id) == SWHID( + object_type="directory", object_id=object_id + ) + + assert SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) == SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) + + assert SWHID( + object_type="directory", + object_id=object_id, + metadata={"foo": "bar", "baz": "qux"}, + ) == SWHID( + object_type="directory", + object_id=object_id, + metadata={"baz": "qux", "foo": "bar"}, + ) -- GitLab