From 2b3139893ac17d73c30465224c847112098705ef Mon Sep 17 00:00:00 2001 From: Nora-Olivia-Ammann <103038637+Nora-Olivia-Ammann@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:28:15 +0100 Subject: [PATCH] refactor(xmlupload): change serialisation of date value (#1277) --- .../models/serialise/serialise_value.py | 55 ++++++++++++++++++- .../xmlupload/resource_create_client.py | 39 +++++-------- src/dsp_tools/utils/date_util.py | 12 ++++ 3 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/dsp_tools/commands/xmlupload/models/serialise/serialise_value.py b/src/dsp_tools/commands/xmlupload/models/serialise/serialise_value.py index 77309b1e39..f78b3b90e0 100644 --- a/src/dsp_tools/commands/xmlupload/models/serialise/serialise_value.py +++ b/src/dsp_tools/commands/xmlupload/models/serialise/serialise_value.py @@ -5,6 +5,15 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import Any +from typing import TypeAlias +from typing import Union + +from dsp_tools.utils.date_util import Date +from dsp_tools.utils.date_util import DayMonthYearEra +from dsp_tools.utils.date_util import SingleDate +from dsp_tools.utils.date_util import StartEnd + +ValueTypes: TypeAlias = Union[str, Date] @dataclass(frozen=True) @@ -21,7 +30,7 @@ def serialise(self) -> dict[str, Any]: class SerialiseValue(ABC): """A value to be serialised.""" - value: str + value: ValueTypes permissions: str | None comment: str | None @@ -39,6 +48,8 @@ def _get_optionals(self) -> dict[str, str]: class SerialiseColor(SerialiseValue): """A ColorValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:ColorValue", @@ -48,9 +59,39 @@ def serialise(self) -> dict[str, Any]: return serialised +class SerialiseDate(SerialiseValue): + """A DateValue to be serialised.""" + + value: Date + + def serialise(self) -> dict[str, Any]: + serialised = {"knora-api:dateValueHasCalendar": self.value.calendar.value} if self.value.calendar else {} + serialised["@type"] = "knora-api:DateValue" + serialised.update(self._get_one_date_dict(self.value.start, StartEnd.START)) + if self.value.end: + serialised.update(self._get_one_date_dict(self.value.end, StartEnd.END)) + serialised.update(self._get_optionals()) + return serialised + + def _get_one_date_dict(self, date: SingleDate, start_end: StartEnd) -> dict[str, Any]: + def get_prop(precision: DayMonthYearEra) -> str: + return f"knora-api:dateValueHas{start_end.value}{precision.value}" + + date_dict: dict[str, Any] = {get_prop(DayMonthYearEra.YEAR): date.year} if date.year else {} + if date.month: + date_dict[get_prop(DayMonthYearEra.MONTH)] = date.month + if date.day: + date_dict[get_prop(DayMonthYearEra.DAY)] = date.day + if date.era: + date_dict[get_prop(DayMonthYearEra.ERA)] = date.era.value + return date_dict + + class SerialiseDecimal(SerialiseValue): """A DecimalValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:DecimalValue", @@ -66,6 +107,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseGeometry(SerialiseValue): """A GeomValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:GeomValue", @@ -78,6 +121,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseGeoname(SerialiseValue): """A GeonameValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:GeonameValue", @@ -90,6 +135,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseSimpletext(SerialiseValue): """A Simpletext to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:TextValue", @@ -102,6 +149,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseRichtext(SerialiseValue): """A Richtext to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:TextValue", @@ -117,6 +166,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseTime(SerialiseValue): """A TimeValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:TimeValue", @@ -132,6 +183,8 @@ def serialise(self) -> dict[str, Any]: class SerialiseURI(SerialiseValue): """A UriValue to be serialised.""" + value: str + def serialise(self) -> dict[str, Any]: serialised = { "@type": "knora-api:UriValue", diff --git a/src/dsp_tools/commands/xmlupload/resource_create_client.py b/src/dsp_tools/commands/xmlupload/resource_create_client.py index 482c09eb89..0d62ca73cb 100644 --- a/src/dsp_tools/commands/xmlupload/resource_create_client.py +++ b/src/dsp_tools/commands/xmlupload/resource_create_client.py @@ -35,6 +35,7 @@ from dsp_tools.commands.xmlupload.models.serialise.serialise_rdf_value import BooleanValueRDF from dsp_tools.commands.xmlupload.models.serialise.serialise_rdf_value import IntValueRDF from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseColor +from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseDate from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseDecimal from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseGeometry from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseGeoname @@ -183,6 +184,12 @@ def make_values(p: XMLProperty) -> list[dict[str, Any]]: iri_resolver=self.iri_resolver, ) properties_serialised.update(transformed_prop.serialise()) + case "date": + transformed_prop = _transform_into_date_prop( + prop=prop, + permissions_lookup=self.permissions_lookup, + ) + properties_serialised.update(transformed_prop.serialise()) # serialised with rdflib case "integer": int_prop_name = self._get_absolute_prop_iri(prop.name, namespaces) @@ -213,8 +220,6 @@ def _get_absolute_prop_iri(self, prefixed_prop: str, namespaces: dict[str, Names def _make_value(self, value: XMLValue, value_type: str) -> dict[str, Any]: match value_type: - case "date": - res = _make_date_value(value) case "interval": res = _make_interval_value(value) case "resptr": @@ -285,30 +290,16 @@ def _to_boolean(s: str | int | bool) -> bool: raise BaseError(f"Could not parse boolean value: {s}") -def _make_date_value(value: XMLValue) -> dict[str, Any]: +def _transform_into_date_prop(prop: XMLProperty, permissions_lookup: dict[str, Permissions]) -> SerialiseProperty: + vals = [_transform_into_date_value(v, permissions_lookup) for v in prop.values] + return SerialiseProperty(property_name=prop.name, values=vals) + + +def _transform_into_date_value(value: XMLValue, permissions_lookup: dict[str, Permissions]) -> SerialiseDate: string_value = _assert_is_string(value.value) date = parse_date_string(string_value) - res: dict[str, Any] = { - "@type": "knora-api:DateValue", - "knora-api:dateValueHasStartYear": date.start.year, - } - if month := date.start.month: - res["knora-api:dateValueHasStartMonth"] = month - if day := date.start.day: - res["knora-api:dateValueHasStartDay"] = day - if era := date.start.era: - res["knora-api:dateValueHasStartEra"] = era.value - if calendar := date.calendar: - res["knora-api:dateValueHasCalendar"] = calendar.value - if date.end: - res["knora-api:dateValueHasEndYear"] = date.end.year - if month := date.end.month: - res["knora-api:dateValueHasEndMonth"] = month - if day := date.end.day: - res["knora-api:dateValueHasEndDay"] = day - if era := date.end.era: - res["knora-api:dateValueHasEndEra"] = era.value - return res + permission_str = _get_permission_str(value.permissions, permissions_lookup) + return SerialiseDate(value=date, permissions=permission_str, comment=value.comment) def _transform_into_decimal_prop(prop: XMLProperty, permissions_lookup: dict[str, Permissions]) -> SerialiseProperty: diff --git a/src/dsp_tools/utils/date_util.py b/src/dsp_tools/utils/date_util.py index a90bbda4a2..8c54806875 100644 --- a/src/dsp_tools/utils/date_util.py +++ b/src/dsp_tools/utils/date_util.py @@ -70,6 +70,18 @@ def from_string(s: str) -> Era: raise BaseError(f"Invalid era type: {s}") +class DayMonthYearEra(Enum): + DAY = "Day" + MONTH = "Month" + YEAR = "Year" + ERA = "Era" + + +class StartEnd(Enum): + START = "Start" + END = "End" + + @dataclass(frozen=True) class SingleDate: """Information about a single date."""