Coverage for oc_ocdm / metadata / entities / dataset.py: 93%
128 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 20:23 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 20:23 +0000
1#!/usr/bin/python
3# SPDX-FileCopyrightText: 2020-2022 Simone Persiani <iosonopersia@gmail.com>
4#
5# SPDX-License-Identifier: ISC
7# -*- coding: utf-8 -*-
8from __future__ import annotations
10from typing import TYPE_CHECKING
12from triplelite import RDFTerm
14from oc_ocdm.constants import XSD_DATETIME
15from oc_ocdm.decorators import accepts_only
16from oc_ocdm.metadata.metadata_entity import MetadataEntity
18if TYPE_CHECKING:
19 from typing import List
21 from oc_ocdm.metadata.entities.distribution import Distribution
24class Dataset(MetadataEntity):
25 """Dataset (short: not applicable and strictly dependent on the implementation of the
26 dataset infrastructure): a set of collected information about something."""
28 def _merge_properties(self, other: MetadataEntity) -> None:
29 """
30 The merge operation allows combining two ``Dataset`` entities into a single one,
31 by marking the second entity as to be deleted while also copying its data into the current
32 ``Dataset``. Moreover, every triple from the containing ``MetadataSet`` referring to the second
33 entity gets "redirected" to the current entity: **every other reference contained inside a
34 different source (e.g. a triplestore) must be manually handled by the user!**
36 In case of functional properties, values from the current entity get overwritten
37 by those coming from the second entity while, in all other cases, values from the
38 second entity are simply appended to those of the current entity. In this context,
39 ``rdfs:label`` is considered as a functional property, while ``rdf:type`` is not.
41 :param other: The entity which will be marked as to be deleted and whose properties will
42 be merged into the current entity.
43 :type other: Dataset
44 :raises TypeError: if the parameter is of the wrong type
45 :return: None
46 """
47 super()._merge_properties(other)
48 assert isinstance(other, Dataset)
50 title: str | None = other.get_title()
51 if title is not None:
52 self.has_title(title)
54 description: str | None = other.get_description()
55 if description is not None:
56 self.has_description(description)
58 pub_date: str | None = other.get_publication_date()
59 if pub_date is not None:
60 self.has_publication_date(pub_date)
62 mod_date: str | None = other.get_modification_date()
63 if mod_date is not None:
64 self.has_modification_date(mod_date)
66 keywords_list: List[str] = other.get_keywords()
67 for cur_keyword in keywords_list:
68 self.has_keyword(cur_keyword)
70 subjects_list: List[str] = other.get_subjects()
71 for cur_subject in subjects_list:
72 self.has_subject(cur_subject)
74 landing_page: str | None = other.get_landing_page()
75 if landing_page is not None:
76 self.has_landing_page(landing_page)
78 sub_datasets_list: List[Dataset] = other.get_sub_datasets()
79 for cur_sub_dataset in sub_datasets_list:
80 self.has_sub_dataset(cur_sub_dataset)
82 sparql_endpoint: str | None = other.get_sparql_endpoint()
83 if sparql_endpoint is not None:
84 self.has_sparql_endpoint(sparql_endpoint)
86 distributions_list: List[Distribution] = other.get_distributions()
87 for cur_distribution in distributions_list:
88 self.has_distribution(cur_distribution)
90 # HAS TITLE
91 def get_title(self) -> str | None:
92 """
93 Getter method corresponding to the ``dcterms:title`` RDF predicate.
95 :return: The requested value if found, None otherwise
96 """
97 return self._get_literal(MetadataEntity.iri_title)
99 def has_title(self, string: str) -> None:
100 """
101 Setter method corresponding to the ``dcterms:title`` RDF predicate.
103 **WARNING: this is a functional property, hence any existing value will be overwritten!**
105 `The title of the dataset.`
107 :param string: The value that will be set as the object of the property related to this method
108 :type string: str
109 :raises TypeError: if the parameter is of the wrong type
110 :return: None
111 """
112 self.remove_title()
113 self._create_literal(MetadataEntity.iri_title, string)
115 def remove_title(self) -> None:
116 """
117 Remover method corresponding to the ``dcterms:title`` RDF predicate.
119 :return: None
120 """
121 self.g.remove((self.res, MetadataEntity.iri_title, None))
123 # HAS DESCRIPTION
124 def get_description(self) -> str | None:
125 """
126 Getter method corresponding to the ``dcterms:description`` RDF predicate.
128 :return: The requested value if found, None otherwise
129 """
130 return self._get_literal(MetadataEntity.iri_description)
132 def has_description(self, string: str) -> None:
133 """
134 Setter method corresponding to the ``dcterms:description`` RDF predicate.
136 **WARNING: this is a functional property, hence any existing value will be overwritten!**
138 `A short textual description of the content of the dataset.`
140 :param string: The value that will be set as the object of the property related to this method
141 :type string: str
142 :raises TypeError: if the parameter is of the wrong type
143 :return: None
144 """
145 self.remove_description()
146 self._create_literal(MetadataEntity.iri_description, string)
148 def remove_description(self) -> None:
149 """
150 Remover method corresponding to the ``dcterms:description`` RDF predicate.
152 :return: None
153 """
154 self.g.remove((self.res, MetadataEntity.iri_description, None))
156 # HAS PUBLICATION DATE
157 def get_publication_date(self) -> str | None:
158 """
159 Getter method corresponding to the ``dcterms:issued`` RDF predicate.
161 :return: The requested value if found, None otherwise
162 """
163 return self._get_literal(MetadataEntity.iri_issued)
165 def has_publication_date(self, string: str) -> None:
166 """
167 Setter method corresponding to the ``dcterms:issued`` RDF predicate.
169 **WARNING: this is a functional property, hence any existing value will be overwritten!**
171 `The date of first publication of the dataset.`
173 :param string: The value that will be set as the object of the property related to this method. **It must
174 be a string compliant with the** ``xsd:dateTime`` **datatype.**
175 :type string: str
176 :raises TypeError: if the parameter is of the wrong type
177 :return: None
178 """
179 self.remove_publication_date()
180 self._create_literal(MetadataEntity.iri_issued, string, XSD_DATETIME, False)
182 def remove_publication_date(self) -> None:
183 """
184 Remover method corresponding to the ``dcterms:issued`` RDF predicate.
186 :return: None
187 """
188 self.g.remove((self.res, MetadataEntity.iri_issued, None))
190 # HAS MODIFICATION DATE
191 def get_modification_date(self) -> str | None:
192 """
193 Getter method corresponding to the ``dcterms:modified`` RDF predicate.
195 :return: The requested value if found, None otherwise
196 """
197 return self._get_literal(MetadataEntity.iri_modified)
199 def has_modification_date(self, string: str) -> None:
200 """
201 Setter method corresponding to the ``dcterms:modified`` RDF predicate.
203 **WARNING: this is a functional property, hence any existing value will be overwritten!**
205 `The date on which the dataset has been modified.`
207 :param string: The value that will be set as the object of the property related to this method. **It must
208 be a string compliant with the** ``xsd:dateTime`` **datatype.**
209 :type string: str
210 :raises TypeError: if the parameter is of the wrong type
211 :return: None
212 """
213 self.remove_modification_date()
214 self._create_literal(MetadataEntity.iri_modified, string, XSD_DATETIME, False)
216 def remove_modification_date(self) -> None:
217 """
218 Remover method corresponding to the ``dcterms:modified`` RDF predicate.
220 :return: None
221 """
222 self.g.remove((self.res, MetadataEntity.iri_modified, None))
224 # HAS KEYWORD
225 def get_keywords(self) -> List[str]:
226 """
227 Getter method corresponding to the ``dcat:keyword`` RDF predicate.
229 :return: A list containing the requested values if found, None otherwise
230 """
231 return self._get_multiple_literals(MetadataEntity.iri_keyword)
233 def has_keyword(self, string: str) -> None:
234 """
235 Setter method corresponding to the ``dcat:keyword`` RDF predicate.
237 `A keyword or phrase describing the content of the dataset.`
239 :param string: The value that will be set as the object of the property related to this method
240 :type string: str
241 :raises TypeError: if the parameter is of the wrong type
242 :return: None
243 """
244 self._create_literal(MetadataEntity.iri_keyword, string)
246 def remove_keyword(self, string: str | None = None) -> None:
247 """
248 Remover method corresponding to the ``dcat:keyword`` RDF predicate.
250 **WARNING: this is a non-functional property, hence, if the parameter
251 is None, any existing value will be removed!**
253 :param string: If not None, the specific object value that will be removed from the property
254 related to this method (defaults to None)
255 :type string: str
256 :raises TypeError: if the parameter is of the wrong type
257 :return: None
258 """
259 if string is not None:
260 self.g.remove((self.res, MetadataEntity.iri_keyword, RDFTerm("literal", string, "http://www.w3.org/2001/XMLSchema#string")))
261 else:
262 self.g.remove((self.res, MetadataEntity.iri_keyword, None))
264 # HAS SUBJECT
265 def get_subjects(self) -> List[str]:
266 """
267 Getter method corresponding to the ``dcat:theme`` RDF predicate.
269 :return: A list containing the requested values if found, None otherwise
270 """
271 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_subject)
272 return uri_list
274 def has_subject(self, thing_res: str) -> None:
275 """
276 Setter method corresponding to the ``dcat:theme`` RDF predicate.
278 `A concept describing the primary subject of the dataset.`
280 :param thing_res: The value that will be set as the object of the property related to this method
281 :type thing_res: URIRef
282 :raises TypeError: if the parameter is of the wrong type
283 :return: None
284 """
285 self.g.add((self.res, MetadataEntity.iri_subject, RDFTerm("uri", str(thing_res))))
287 def remove_subject(self, thing_res: str | None = None) -> None:
288 """
289 Remover method corresponding to the ``dcat:theme`` RDF predicate.
291 **WARNING: this is a non-functional property, hence, if the parameter
292 is None, any existing value will be removed!**
294 :param thing_res: If not None, the specific object value that will be removed from the property
295 related to this method (defaults to None)
296 :type thing_res: URIRef
297 :raises TypeError: if the parameter is of the wrong type
298 :return: None
299 """
300 if thing_res is not None:
301 self.g.remove((self.res, MetadataEntity.iri_subject, RDFTerm("uri", str(thing_res))))
302 else:
303 self.g.remove((self.res, MetadataEntity.iri_subject, None))
305 # HAS LANDING PAGE
306 def get_landing_page(self) -> str | None:
307 """
308 Getter method corresponding to the ``dcat:landingPage`` RDF predicate.
310 :return: The requested value if found, None otherwise
311 """
312 return self._get_uri_reference(MetadataEntity.iri_landing_page)
314 def has_landing_page(self, thing_res: str) -> None:
315 """
316 Setter method corresponding to the ``dcat:landingPage`` RDF predicate.
318 **WARNING: this is a functional property, hence any existing value will be overwritten!**
320 `An HTML page (indicated by its URL) representing a browsable page for the dataset.`
322 :param thing_res: The value that will be set as the object of the property related to this method
323 :type thing_res: URIRef
324 :raises TypeError: if the parameter is of the wrong type
325 :return: None
326 """
327 self.remove_landing_page()
328 self.g.add((self.res, MetadataEntity.iri_landing_page, RDFTerm("uri", str(thing_res))))
330 def remove_landing_page(self) -> None:
331 """
332 Remover method corresponding to the ``dcat:landingPage`` RDF predicate.
334 :return: None
335 """
336 self.g.remove((self.res, MetadataEntity.iri_landing_page, None))
338 # HAS SUB-DATASET
339 def get_sub_datasets(self) -> List[Dataset]:
340 """
341 Getter method corresponding to the ``void:subset`` RDF predicate.
343 :return: A list containing the requested values if found, None otherwise
344 """
345 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_subset, '_dataset_')
346 result: List[Dataset] = []
347 for uri in uri_list:
348 result.append(self.m_set.add_dataset(self.dataset_name, self.resp_agent or "", self.source, uri))
349 return result
351 @accepts_only('_dataset_')
352 def has_sub_dataset(self, obj: Dataset) -> None:
353 """
354 Setter method corresponding to the ``void:subset`` RDF predicate.
356 `A link to a subset of the present dataset.`
358 :param obj: The value that will be set as the object of the property related to this method
359 :type obj: Dataset
360 :raises TypeError: if the parameter is of the wrong type
361 :return: None
362 """
363 self.g.add((self.res, MetadataEntity.iri_subset, RDFTerm("uri", str(obj.res))))
365 @accepts_only('_dataset_')
366 def remove_sub_dataset(self, dataset_res: Dataset | None = None) -> None:
367 """
368 Remover method corresponding to the ``void:subset`` RDF predicate.
370 **WARNING: this is a non-functional property, hence, if the parameter
371 is None, any existing value will be removed!**
373 :param dataset_res: If not None, the specific object value that will be removed from the property
374 related to this method (defaults to None)
375 :type dataset_res: Dataset
376 :raises TypeError: if the parameter is of the wrong type
377 :return: None
378 """
379 if dataset_res is not None:
380 self.g.remove((self.res, MetadataEntity.iri_subset, RDFTerm("uri", str(dataset_res.res))))
381 else:
382 self.g.remove((self.res, MetadataEntity.iri_subset, None))
384 # HAS SPARQL ENDPOINT
385 def get_sparql_endpoint(self) -> str | None:
386 """
387 Getter method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
389 :return: The requested value if found, None otherwise
390 """
391 uri: str | None = self._get_uri_reference(MetadataEntity.iri_sparql_endpoint)
392 return uri
394 def has_sparql_endpoint(self, thing_res: str) -> None:
395 """
396 Setter method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
398 **WARNING: this is a functional property, hence any existing value will be overwritten!**
400 `The link to the SPARQL endpoint for querying the dataset.`
402 :param thing_res: The value that will be set as the object of the property related to this method
403 :type thing_res: URIRef
404 :raises TypeError: if the parameter is of the wrong type
405 :return: None
406 """
407 self.remove_sparql_endpoint()
408 self.g.add((self.res, MetadataEntity.iri_sparql_endpoint, RDFTerm("uri", str(thing_res))))
410 def remove_sparql_endpoint(self) -> None:
411 """
412 Remover method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
414 :return: None
415 """
416 self.g.remove((self.res, MetadataEntity.iri_sparql_endpoint, None))
418 # HAS DISTRIBUTION (Distribution)
419 def get_distributions(self) -> List[Distribution]:
420 """
421 Getter method corresponding to the ``dcat:distribution`` RDF predicate.
423 :return: The requested value if found, None otherwise
424 """
425 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_distribution, 'di')
426 result: List[Distribution] = []
427 for uri in uri_list:
428 result.append(self.m_set.add_di(self.dataset_name, self.resp_agent or "", self.source, uri))
429 return result
431 @accepts_only('di')
432 def has_distribution(self, obj: Distribution) -> None:
433 """
434 Setter method corresponding to the ``dcat:distribution`` RDF predicate.
436 `A distribution of the dataset.`
438 :param obj: The value that will be set as the object of the property related to this method
439 :type obj: Distribution
440 :raises TypeError: if the parameter is of the wrong type
441 :return: None
442 """
443 self.g.add((self.res, MetadataEntity.iri_distribution, RDFTerm("uri", str(obj.res))))
445 @accepts_only('di')
446 def remove_distribution(self, di_res: Distribution | None = None) -> None:
447 """
448 Remover method corresponding to the ``dcat:distribution`` RDF predicate.
450 **WARNING: this is a non-functional property, hence, if the parameter
451 is None, any existing value will be removed!**
453 :param di_res: If not None, the specific object value that will be removed from the property
454 related to this method (defaults to None)
455 :type di_res: Distribution
456 :raises TypeError: if the parameter is of the wrong type
457 :return: None
458 """
459 if di_res is not None:
460 self.g.remove((self.res, MetadataEntity.iri_distribution, RDFTerm("uri", str(di_res.res))))
461 else:
462 self.g.remove((self.res, MetadataEntity.iri_distribution, None))