Coverage for oc_ocdm / metadata / entities / dataset.py: 93%
128 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-07-06 20:05 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-07-06 20:05 +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(
261 (
262 self.res,
263 MetadataEntity.iri_keyword,
264 RDFTerm("literal", string, "http://www.w3.org/2001/XMLSchema#string"),
265 )
266 )
267 else:
268 self.g.remove((self.res, MetadataEntity.iri_keyword, None))
270 # HAS SUBJECT
271 def get_subjects(self) -> List[str]:
272 """
273 Getter method corresponding to the ``dcat:theme`` RDF predicate.
275 :return: A list containing the requested values if found, None otherwise
276 """
277 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_subject)
278 return uri_list
280 def has_subject(self, thing_res: str) -> None:
281 """
282 Setter method corresponding to the ``dcat:theme`` RDF predicate.
284 `A concept describing the primary subject of the dataset.`
286 :param thing_res: The value that will be set as the object of the property related to this method
287 :type thing_res: URIRef
288 :raises TypeError: if the parameter is of the wrong type
289 :return: None
290 """
291 self.g.add((self.res, MetadataEntity.iri_subject, RDFTerm("uri", str(thing_res))))
293 def remove_subject(self, thing_res: str | None = None) -> None:
294 """
295 Remover method corresponding to the ``dcat:theme`` RDF predicate.
297 **WARNING: this is a non-functional property, hence, if the parameter
298 is None, any existing value will be removed!**
300 :param thing_res: If not None, the specific object value that will be removed from the property
301 related to this method (defaults to None)
302 :type thing_res: URIRef
303 :raises TypeError: if the parameter is of the wrong type
304 :return: None
305 """
306 if thing_res is not None:
307 self.g.remove((self.res, MetadataEntity.iri_subject, RDFTerm("uri", str(thing_res))))
308 else:
309 self.g.remove((self.res, MetadataEntity.iri_subject, None))
311 # HAS LANDING PAGE
312 def get_landing_page(self) -> str | None:
313 """
314 Getter method corresponding to the ``dcat:landingPage`` RDF predicate.
316 :return: The requested value if found, None otherwise
317 """
318 return self._get_uri_reference(MetadataEntity.iri_landing_page)
320 def has_landing_page(self, thing_res: str) -> None:
321 """
322 Setter method corresponding to the ``dcat:landingPage`` RDF predicate.
324 **WARNING: this is a functional property, hence any existing value will be overwritten!**
326 `An HTML page (indicated by its URL) representing a browsable page for the dataset.`
328 :param thing_res: The value that will be set as the object of the property related to this method
329 :type thing_res: URIRef
330 :raises TypeError: if the parameter is of the wrong type
331 :return: None
332 """
333 self.remove_landing_page()
334 self.g.add((self.res, MetadataEntity.iri_landing_page, RDFTerm("uri", str(thing_res))))
336 def remove_landing_page(self) -> None:
337 """
338 Remover method corresponding to the ``dcat:landingPage`` RDF predicate.
340 :return: None
341 """
342 self.g.remove((self.res, MetadataEntity.iri_landing_page, None))
344 # HAS SUB-DATASET
345 def get_sub_datasets(self) -> List[Dataset]:
346 """
347 Getter method corresponding to the ``void:subset`` RDF predicate.
349 :return: A list containing the requested values if found, None otherwise
350 """
351 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_subset, "_dataset_")
352 result: List[Dataset] = []
353 for uri in uri_list:
354 result.append(self.m_set.add_dataset(self.dataset_name, self.resp_agent or "", self.source, uri))
355 return result
357 @accepts_only("_dataset_")
358 def has_sub_dataset(self, obj: Dataset) -> None:
359 """
360 Setter method corresponding to the ``void:subset`` RDF predicate.
362 `A link to a subset of the present dataset.`
364 :param obj: The value that will be set as the object of the property related to this method
365 :type obj: Dataset
366 :raises TypeError: if the parameter is of the wrong type
367 :return: None
368 """
369 self.g.add((self.res, MetadataEntity.iri_subset, RDFTerm("uri", str(obj.res))))
371 @accepts_only("_dataset_")
372 def remove_sub_dataset(self, dataset_res: Dataset | None = None) -> None:
373 """
374 Remover method corresponding to the ``void:subset`` RDF predicate.
376 **WARNING: this is a non-functional property, hence, if the parameter
377 is None, any existing value will be removed!**
379 :param dataset_res: If not None, the specific object value that will be removed from the property
380 related to this method (defaults to None)
381 :type dataset_res: Dataset
382 :raises TypeError: if the parameter is of the wrong type
383 :return: None
384 """
385 if dataset_res is not None:
386 self.g.remove((self.res, MetadataEntity.iri_subset, RDFTerm("uri", str(dataset_res.res))))
387 else:
388 self.g.remove((self.res, MetadataEntity.iri_subset, None))
390 # HAS SPARQL ENDPOINT
391 def get_sparql_endpoint(self) -> str | None:
392 """
393 Getter method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
395 :return: The requested value if found, None otherwise
396 """
397 uri: str | None = self._get_uri_reference(MetadataEntity.iri_sparql_endpoint)
398 return uri
400 def has_sparql_endpoint(self, thing_res: str) -> None:
401 """
402 Setter method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
404 **WARNING: this is a functional property, hence any existing value will be overwritten!**
406 `The link to the SPARQL endpoint for querying the dataset.`
408 :param thing_res: The value that will be set as the object of the property related to this method
409 :type thing_res: URIRef
410 :raises TypeError: if the parameter is of the wrong type
411 :return: None
412 """
413 self.remove_sparql_endpoint()
414 self.g.add((self.res, MetadataEntity.iri_sparql_endpoint, RDFTerm("uri", str(thing_res))))
416 def remove_sparql_endpoint(self) -> None:
417 """
418 Remover method corresponding to the ``void:sparqlEndpoint`` RDF predicate.
420 :return: None
421 """
422 self.g.remove((self.res, MetadataEntity.iri_sparql_endpoint, None))
424 # HAS DISTRIBUTION (Distribution)
425 def get_distributions(self) -> List[Distribution]:
426 """
427 Getter method corresponding to the ``dcat:distribution`` RDF predicate.
429 :return: The requested value if found, None otherwise
430 """
431 uri_list: List[str] = self._get_multiple_uri_references(MetadataEntity.iri_distribution, "di")
432 result: List[Distribution] = []
433 for uri in uri_list:
434 result.append(self.m_set.add_di(self.dataset_name, self.resp_agent or "", self.source, uri))
435 return result
437 @accepts_only("di")
438 def has_distribution(self, obj: Distribution) -> None:
439 """
440 Setter method corresponding to the ``dcat:distribution`` RDF predicate.
442 `A distribution of the dataset.`
444 :param obj: The value that will be set as the object of the property related to this method
445 :type obj: Distribution
446 :raises TypeError: if the parameter is of the wrong type
447 :return: None
448 """
449 self.g.add((self.res, MetadataEntity.iri_distribution, RDFTerm("uri", str(obj.res))))
451 @accepts_only("di")
452 def remove_distribution(self, di_res: Distribution | None = None) -> None:
453 """
454 Remover method corresponding to the ``dcat:distribution`` RDF predicate.
456 **WARNING: this is a non-functional property, hence, if the parameter
457 is None, any existing value will be removed!**
459 :param di_res: If not None, the specific object value that will be removed from the property
460 related to this method (defaults to None)
461 :type di_res: Distribution
462 :raises TypeError: if the parameter is of the wrong type
463 :return: None
464 """
465 if di_res is not None:
466 self.g.remove((self.res, MetadataEntity.iri_distribution, RDFTerm("uri", str(di_res.res))))
467 else:
468 self.g.remove((self.res, MetadataEntity.iri_distribution, None))