diff --git a/swh/model/model.py b/swh/model/model.py --- a/swh/model/model.py +++ b/swh/model/model.py @@ -25,6 +25,7 @@ release_identifier, snapshot_identifier, SWHID, + parse_swhid, ) @@ -58,6 +59,8 @@ "Helper function used by BaseModel.to_dict()" if isinstance(value, BaseModel): return value.to_dict() + elif isinstance(value, SWHID): + return str(value) elif isinstance(value, Enum): return value.value elif isinstance(value, (dict, ImmutableDict)): @@ -742,6 +745,17 @@ converter=freeze_optional_dict, ) + def to_dict(self): + d = super().to_dict() + if d["metadata"] is None: + del d["metadata"] + return d + + @classmethod + def from_dict(cls, d): + d["type"] = MetadataAuthorityType(d["type"]) + return super().from_dict(d) + @attr.s(frozen=True) class MetadataFetcher(BaseModel): @@ -757,6 +771,12 @@ converter=freeze_optional_dict, ) + def to_dict(self): + d = super().to_dict() + if d["metadata"] is None: + del d["metadata"] + return d + class MetadataTargetType(Enum): """The type of object extrinsic metadata refer to.""" @@ -929,3 +949,38 @@ if pid.metadata: raise ValueError(f"Expected core SWHID, but got: {pid}") + + def to_dict(self): + d = super().to_dict() + context_keys = ( + "origin", + "visit", + "snapshot", + "release", + "revision", + "directory", + "path", + ) + for context_key in context_keys: + if d[context_key] is None: + del d[context_key] + return d + + @classmethod + def from_dict(cls, d): + d = { + **d, + "type": MetadataTargetType(d["type"]), + "authority": MetadataAuthority.from_dict(d["authority"]), + "fetcher": MetadataFetcher.from_dict(d["fetcher"]), + } + + if d["type"] != MetadataTargetType.ORIGIN: + d["id"] = parse_swhid(d["id"]) + + swhid_keys = ("snapshot", "release", "revision", "directory") + for swhid_key in swhid_keys: + if d.get(swhid_key): + d[swhid_key] = parse_swhid(d[swhid_key]) + + return super().from_dict(d) diff --git a/swh/model/tests/test_model.py b/swh/model/tests/test_model.py --- a/swh/model/tests/test_model.py +++ b/swh/model/tests/test_model.py @@ -716,6 +716,38 @@ ) +def test_metadata_to_dict(): + """Checks valid RawExtrinsicMetadata objects don't raise an error.""" + + common_fields = { + "authority": {"type": "forge", "url": "https://forge.softwareheritage.org",}, + "fetcher": {"name": "test-fetcher", "version": "0.0.1",}, + "discovery_date": _common_metadata_fields["discovery_date"], + "format": "json", + "metadata": b'{"foo": "bar"}', + } + + m = RawExtrinsicMetadata( + type=MetadataTargetType.ORIGIN, id=_origin_url, **_common_metadata_fields + ) + assert m.to_dict() == { + "type": "origin", + "id": _origin_url, + **common_fields, + } + assert RawExtrinsicMetadata.from_dict(m.to_dict()) == m + + m = RawExtrinsicMetadata( + type=MetadataTargetType.CONTENT, id=_content_swhid, **_common_metadata_fields + ) + assert m.to_dict() == { + "type": "content", + "id": "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2", + **common_fields, + } + assert RawExtrinsicMetadata.from_dict(m.to_dict()) == m + + def test_metadata_invalid_id(): """Checks various invalid values for the 'id' field."""