Coverage for oc_ocdm/graph/entities/bibliographic/discourse_element.py: 54%
147 statements
« prev ^ index » next coverage.py v6.5.0, created at 2025-05-30 22:05 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2025-05-30 22:05 +0000
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2016, Silvio Peroni <essepuntato@gmail.com>
4#
5# Permission to use, copy, modify, and/or distribute this software for any purpose
6# with or without fee is hereby granted, provided that the above copyright notice
7# and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
12# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
13# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15# SOFTWARE.
16from __future__ import annotations
18from typing import TYPE_CHECKING
20from oc_ocdm.decorators import accepts_only
22if TYPE_CHECKING:
23 from typing import Optional, List
24 from rdflib import URIRef
25 from oc_ocdm.graph.entities.bibliographic.reference_pointer import ReferencePointer
26 from oc_ocdm.graph.entities.bibliographic.pointer_list import PointerList
27from oc_ocdm.graph.graph_entity import GraphEntity
28from oc_ocdm.graph.entities.bibliographic_entity import BibliographicEntity
29from oc_ocdm.support.support import create_type
32class DiscourseElement(BibliographicEntity):
33 """Discourse element (short: de): a document component, either structural (e.g.
34 paragraph, section, chapter, table, caption, footnote, title) or rhetorical (e.g.
35 introduction, discussion, acknowledgements, reference list, figure, appendix), in which
36 the content of a bibliographic resource can be organized."""
38 @accepts_only('de')
39 def merge(self, other: DiscourseElement) -> None:
40 """
41 The merge operation allows combining two ``DiscourseElement`` entities into a single one,
42 by marking the second entity as to be deleted while also copying its data into the current
43 ``DiscourseElement``. Moreover, every triple from the containing ``GraphSet`` referring to the second
44 entity gets "redirected" to the current entity: **every other reference contained inside a
45 different source (e.g. a triplestore) must be manually handled by the user!**
47 In case of functional properties, values from the current entity get overwritten
48 by those coming from the second entity while, in all other cases, values from the
49 second entity are simply appended to those of the current entity. In this context,
50 ``rdfs:label`` is considered as a functional property, while ``rdf:type`` is not.
52 :param other: The entity which will be marked as to be deleted and whose properties will
53 be merged into the current entity.
54 :type other: DiscourseElement
55 :raises TypeError: if the parameter is of the wrong type
56 :return: None
57 """
58 super(DiscourseElement, self).merge(other)
60 title: Optional[str] = other.get_title()
61 if title is not None:
62 self.has_title(title)
64 de_list: List[DiscourseElement] = other.get_contained_discourse_elements()
65 for cur_de in de_list:
66 self.contains_discourse_element(cur_de)
68 next_de: Optional[DiscourseElement] = other.get_next_de()
69 if next_de is not None:
70 self.has_next_de(next_de)
72 rp_list: List[ReferencePointer] = other.get_is_context_of_rp()
73 for cur_rp in rp_list:
74 self.is_context_of_rp(cur_rp)
76 pl_list: List[PointerList] = other.get_is_context_of_pl()
77 for cur_pl in pl_list:
78 self.is_context_of_pl(cur_pl)
80 content: Optional[str] = other.get_content()
81 if content is not None:
82 self.has_content(content)
84 number: Optional[str] = other.get_number()
85 if number is not None:
86 self.has_number(number)
88 # HAS TITLE
89 def get_title(self) -> Optional[str]:
90 """
91 Getter method corresponding to the ``dcterms:title`` RDF predicate.
93 :return: The requested value if found, None otherwise
94 """
95 return self._get_literal(GraphEntity.iri_title)
97 @accepts_only('literal')
98 def has_title(self, string: str) -> None:
99 """
100 Setter method corresponding to the ``dcterms:title`` RDF predicate.
102 **WARNING: this is a functional property, hence any existing value will be overwritten!**
104 `The title of the discourse element, such as the title of a figure or a section in an article.`
106 :param string: The value that will be set as the object of the property related to this method
107 :type string: str
108 :raises TypeError: if the parameter is of the wrong type
109 :return: None
110 """
111 self.remove_title()
112 self._create_literal(GraphEntity.iri_title, string)
114 def remove_title(self) -> None:
115 """
116 Remover method corresponding to the ``dcterms:title`` RDF predicate.
118 :return: None
119 """
120 self.g.remove((self.res, GraphEntity.iri_title, None))
122 # HAS PART (DiscourseElement)
123 def get_contained_discourse_elements(self) -> List[DiscourseElement]:
124 """
125 Getter method corresponding to the ``frbr:part`` RDF predicate.
127 :return: A list containing the requested values if found, None otherwise
128 """
129 uri_list: List[URIRef] = self._get_multiple_uri_references(GraphEntity.iri_contains_de, 'de')
130 result: List[DiscourseElement] = []
131 for uri in uri_list:
132 result.append(self.g_set.add_de(self.resp_agent, self.source, uri))
133 return result
135 @accepts_only('de')
136 def contains_discourse_element(self, de_res: DiscourseElement) -> None:
137 """
138 Setter method corresponding to the ``frbr:part`` RDF predicate.
140 `The discourse element hierarchically nested within the parent element, such as a
141 sentence within a paragraph, or a paragraph within a section.`
143 :param de_res: The value that will be set as the object of the property related to this method
144 :type de_res: DiscourseElement
145 :raises TypeError: if the parameter is of the wrong type
146 :return: None
147 """
148 self.g.add((self.res, GraphEntity.iri_contains_de, de_res.res))
150 @accepts_only('de')
151 def remove_contained_discourse_element(self, de_res: DiscourseElement = None) -> None:
152 """
153 Remover method corresponding to the ``frbr:part`` RDF predicate.
155 **WARNING: this is a non-functional property, hence, if the parameter
156 is None, any existing value will be removed!**
158 :param de_res: If not None, the specific object value that will be removed from the property
159 related to this method (defaults to None)
160 :type de_res: DiscourseElement
161 :raises TypeError: if the parameter is of the wrong type
162 :return: None
163 """
164 if de_res is not None:
165 self.g.remove((self.res, GraphEntity.iri_contains_de, de_res.res))
166 else:
167 self.g.remove((self.res, GraphEntity.iri_contains_de, None))
169 # HAS NEXT (DiscourseElement)
170 def get_next_de(self) -> Optional[DiscourseElement]:
171 """
172 Getter method corresponding to the ``oco:hasNext`` RDF predicate.
174 :return: The requested value if found, None otherwise
175 """
176 uri: Optional[URIRef] = self._get_uri_reference(GraphEntity.iri_has_next, 'de')
177 if uri is not None:
178 return self.g_set.add_de(self.resp_agent, self.source, uri)
180 @accepts_only('de')
181 def has_next_de(self, de_res: DiscourseElement) -> None:
182 """
183 Setter method corresponding to the ``oco:hasNext`` RDF predicate.
185 **WARNING: this is a functional property, hence any existing value will be overwritten!**
187 `The following discourse element that includes at least one in-text reference pointer.`
189 :param de_res: The value that will be set as the object of the property related to this method
190 :type de_res: DiscourseElement
191 :raises TypeError: if the parameter is of the wrong type
192 :return: None
193 """
194 self.remove_next_de()
195 self.g.add((self.res, GraphEntity.iri_has_next, de_res.res))
197 def remove_next_de(self) -> None:
198 """
199 Remover method corresponding to the ``oco:hasNext`` RDF predicate.
201 :return: None
202 """
203 self.g.remove((self.res, GraphEntity.iri_has_next, None))
205 # IS CONTEXT OF (ReferencePointer)
206 def get_is_context_of_rp(self) -> List[ReferencePointer]:
207 """
208 Getter method corresponding to the ``c4o:isContextOf`` RDF predicate.
210 :return: A list containing the requested values if found, None otherwise
211 """
212 uri_list: List[URIRef] = self._get_multiple_uri_references(GraphEntity.iri_is_context_of, 'rp')
213 result: List[ReferencePointer] = []
214 for uri in uri_list:
215 result.append(self.g_set.add_rp(self.resp_agent, self.source, uri))
216 return result
218 @accepts_only('rp')
219 def is_context_of_rp(self, rp_res: ReferencePointer) -> None:
220 """
221 Setter method corresponding to the ``c4o:isContextOf`` RDF predicate.
223 `Provides the textual and semantic context of the in-text reference pointer
224 that appears within the discourse element.`
226 :param rp_res: The value that will be set as the object of the property related to this method
227 :type rp_res: ReferencePointer
228 :raises TypeError: if the parameter is of the wrong type
229 :return: None
230 """
231 self.g.add((self.res, GraphEntity.iri_is_context_of, rp_res.res))
233 @accepts_only('rp')
234 def remove_is_context_of_rp(self, rp_res: ReferencePointer = None) -> None:
235 """
236 Remover method corresponding to the ``c4o:isContextOf`` RDF predicate.
238 **WARNING: this is a non-functional property, hence, if the parameter
239 is None, any existing value will be removed!**
241 :param rp_res: If not None, the specific object value that will be removed from the property
242 related to this method (defaults to None)
243 :type rp_res: ReferencePointer
244 :raises TypeError: if the parameter is of the wrong type
245 :return: None
246 """
247 if rp_res is not None:
248 self.g.remove((self.res, GraphEntity.iri_is_context_of, rp_res.res))
249 else:
250 self.g.remove((self.res, GraphEntity.iri_is_context_of, None))
252 # IS CONTEXT OF (PointerList)
253 def get_is_context_of_pl(self) -> List[PointerList]:
254 """
255 Getter method corresponding to the ``c4o:isContextOf`` RDF predicate.
257 :return: A list containing the requested values if found, None otherwise
258 """
259 uri_list: List[URIRef] = self._get_multiple_uri_references(GraphEntity.iri_is_context_of, 'pl')
260 result: List[PointerList] = []
261 for uri in uri_list:
262 result.append(self.g_set.add_pl(self.resp_agent, self.source, uri))
263 return result
265 @accepts_only('pl')
266 def is_context_of_pl(self, pl_res: PointerList) -> None:
267 """
268 Setter method corresponding to the ``c4o:isContextOf`` RDF predicate.
270 `Provides the textual and semantic context of the list of
271 in-text reference pointers that appears within the discourse element.`
273 :param pl_res: The value that will be set as the object of the property related to this method
274 :type pl_res: PointerList
275 :raises TypeError: if the parameter is of the wrong type
276 :return: None
277 """
278 self.g.add((self.res, GraphEntity.iri_is_context_of, pl_res.res))
280 @accepts_only('pl')
281 def remove_is_context_of_pl(self, pl_res: PointerList = None) -> None:
282 """
283 Remover method corresponding to the ``c4o:isContextOf`` RDF predicate.
285 **WARNING: this is a non-functional property, hence, if the parameter
286 is None, any existing value will be removed!**
288 :param pl_res: If not None, the specific object value that will be removed from the property
289 related to this method (defaults to None)
290 :type pl_res: PointerList
291 :raises TypeError: if the parameter is of the wrong type
292 :return: None
293 """
294 if pl_res is not None:
295 self.g.remove((self.res, GraphEntity.iri_is_context_of, pl_res.res))
296 else:
297 self.g.remove((self.res, GraphEntity.iri_is_context_of, None))
299 # HAS CONTENT
300 def get_content(self) -> Optional[str]:
301 """
302 Getter method corresponding to the ``c4o:hasContent`` RDF predicate.
304 :return: The requested value if found, None otherwise
305 """
306 return self._get_literal(GraphEntity.iri_has_content)
308 @accepts_only('literal')
309 def has_content(self, string: str) -> None:
310 """
311 Setter method corresponding to the ``c4o:hasContent`` RDF predicate.
313 **WARNING: this is a functional property, hence any existing value will be overwritten!**
315 `The literal document text contained by the discourse element.`
317 :param string: The value that will be set as the object of the property related to this method
318 :type string: str
319 :raises TypeError: if the parameter is of the wrong type
320 :return: None
321 """
322 self.remove_content()
323 self._create_literal(GraphEntity.iri_has_content, string)
325 def remove_content(self) -> None:
326 """
327 Remover method corresponding to the ``c4o:hasContent`` RDF predicate.
329 :return: None
330 """
331 self.g.remove((self.res, GraphEntity.iri_has_content, None))
333 # HAS NUMBER
334 def get_number(self) -> Optional[str]:
335 """
336 Getter method corresponding to the ``fabio:hasSequenceIdentifier`` RDF predicate.
338 :return: The requested value if found, None otherwise
339 """
340 return self._get_literal(GraphEntity.iri_has_sequence_identifier)
342 @accepts_only('literal')
343 def has_number(self, string: str) -> None:
344 """
345 Setter method corresponding to the ``fabio:hasSequenceIdentifier`` RDF predicate.
347 **WARNING: this is a functional property, hence any existing value will be overwritten!**
349 :param string: The value that will be set as the object of the property related to this method
350 :type string: str
351 :raises TypeError: if the parameter is of the wrong type
352 :return: None
353 """
354 self.remove_number()
355 self._create_literal(GraphEntity.iri_has_sequence_identifier, string)
357 def remove_number(self) -> None:
358 """
359 Remover method corresponding to the ``fabio:hasSequenceIdentifier`` RDF predicate.
361 :return: None
362 """
363 self.g.remove((self.res, GraphEntity.iri_has_sequence_identifier, None))
365 # HAS TYPE
366 @accepts_only('thing')
367 def create_discourse_element(self, de_class: URIRef = None) -> None:
368 """
369 Setter method corresponding to the ``rdf:type`` RDF predicate.
370 If parameter is None, it implicitly sets the object value ``deo:DiscourseElement``.
372 **WARNING: the OCDM specification admits at most two types for an entity.
373 The main type cannot be edited or removed. Any existing secondary type
374 will be overwritten!**
376 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
377 “acknowledgements”, “reference list” or “figure”.`
379 :param de_class: The value that will be set as the object of the property related to this method
380 :type de_class: URIRef
381 :raises TypeError: if the parameter is of the wrong type
382 :return: None
383 """
384 if de_class is not None:
385 self._create_type(de_class)
386 else:
387 self._create_type(GraphEntity.iri_discourse_element)
389 def create_section(self) -> None:
390 """
391 Setter method corresponding to the ``rdf:type`` RDF predicate.
392 It implicitly sets the object value ``doco:Section``.
394 **WARNING: the OCDM specification admits at most two types for an entity.
395 The main type cannot be edited or removed. Any existing secondary type
396 will be overwritten!**
398 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
399 “acknowledgements”, “reference list” or “figure”.`
401 :return: None
402 """
403 self._create_type(GraphEntity.iri_section)
405 def create_section_title(self) -> None:
406 """
407 Setter method corresponding to the ``rdf:type`` RDF predicate.
408 It implicitly sets the object value ``doco:SectionTitle``.
410 **WARNING: the OCDM specification admits at most two types for an entity.
411 The main type cannot be edited or removed. Any existing secondary type
412 will be overwritten!**
414 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
415 “acknowledgements”, “reference list” or “figure”.`
417 :return: None
418 """
419 self._create_type(GraphEntity.iri_section_title)
421 def create_paragraph(self) -> None:
422 """
423 Setter method corresponding to the ``rdf:type`` RDF predicate.
424 It implicitly sets the object value ``doco:Paragraph``.
426 **WARNING: the OCDM specification admits at most two types for an entity.
427 The main type cannot be edited or removed. Any existing secondary type
428 will be overwritten!**
430 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
431 “acknowledgements”, “reference list” or “figure”.`
433 :return: None
434 """
435 self._create_type(GraphEntity.iri_paragraph)
437 def create_sentence(self) -> None:
438 """
439 Setter method corresponding to the ``rdf:type`` RDF predicate.
440 It implicitly sets the object value ``doco:Sentence``.
442 **WARNING: the OCDM specification admits at most two types for an entity.
443 The main type cannot be edited or removed. Any existing secondary type
444 will be overwritten!**
446 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
447 “acknowledgements”, “reference list” or “figure”.`
449 :return: None
450 """
451 self._create_type(GraphEntity.iri_sentence)
453 def create_text_chunk(self) -> None:
454 """
455 Setter method corresponding to the ``rdf:type`` RDF predicate.
456 It implicitly sets the object value ``doco:TextChunk``.
458 **WARNING: the OCDM specification admits at most two types for an entity.
459 The main type cannot be edited or removed. Any existing secondary type
460 will be overwritten!**
462 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
463 “acknowledgements”, “reference list” or “figure”.`
465 :return: None
466 """
467 self._create_type(GraphEntity.iri_text_chunk)
469 def create_table(self) -> None:
470 """
471 Setter method corresponding to the ``rdf:type`` RDF predicate.
472 It implicitly sets the object value ``doco:Table``.
474 **WARNING: the OCDM specification admits at most two types for an entity.
475 The main type cannot be edited or removed. Any existing secondary type
476 will be overwritten!**
478 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
479 “acknowledgements”, “reference list” or “figure”.`
481 :return: None
482 """
483 self._create_type(GraphEntity.iri_table)
485 def create_footnote(self) -> None:
486 """
487 Setter method corresponding to the ``rdf:type`` RDF predicate.
488 It implicitly sets the object value ``doco:Footnote``.
490 **WARNING: the OCDM specification admits at most two types for an entity.
491 The main type cannot be edited or removed. Any existing secondary type
492 will be overwritten!**
494 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
495 “acknowledgements”, “reference list” or “figure”.`
497 :return: None
498 """
499 self._create_type(GraphEntity.iri_footnote)
501 def create_caption(self) -> None:
502 """
503 Setter method corresponding to the ``rdf:type`` RDF predicate.
504 It implicitly sets the object value ``deo:Caption``.
506 **WARNING: the OCDM specification admits at most two types for an entity.
507 The main type cannot be edited or removed. Any existing secondary type
508 will be overwritten!**
510 `The type of discourse element – such as “paragraph”, “section”, “sentence”,
511 “acknowledgements”, “reference list” or “figure”.`
513 :return: None
514 """
515 self._create_type(GraphEntity.iri_caption)
518 def create_introduction(self) -> None:
519 """
520 Setter method corresponding to the ``rdf:type`` RDF predicate.
521 It implicitly sets the object value ``deo:Introduction``.
523 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
524 """
526 create_type(self.g, self.res, GraphEntity.iri_introduction)
528 def create_methods(self) -> None:
529 """
530 Setter method corresponding to the ``rdf:type`` RDF predicate.
531 It implicitly sets the object value ``deo:Methods``.
533 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
534 """
535 create_type(self.g, self.res, GraphEntity.iri_methods)
537 def create_materials(self) -> None:
538 """
539 Setter method corresponding to the ``rdf:type`` RDF predicate.
540 It implicitly sets the object value ``deo:Materials``.
542 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
543 """
544 create_type(self.g, self.res, GraphEntity.iri_materials)
546 def create_related_work(self) -> None:
547 """
548 Setter method corresponding to the ``rdf:type`` RDF predicate.
549 It implicitly sets the object value ``deo:RelatedWork``.
551 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
552 """
553 create_type(self.g, self.res, GraphEntity.iri_related_work)
555 def create_results(self) -> None:
556 """
557 Setter method corresponding to the ``rdf:type`` RDF predicate.
558 It implicitly sets the object value ``deo:Results``.
560 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
561 """
562 create_type(self.g, self.res, GraphEntity.iri_results)
564 def create_discussion(self) -> None:
565 """
566 Setter method corresponding to the ``rdf:type`` RDF predicate.
567 It implicitly sets the object value ``deo:Discussion``.
569 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
570 """
571 create_type(self.g, self.res, GraphEntity.iri_discussion)
573 def create_conclusion(self) -> None:
574 """
575 Setter method corresponding to the ``rdf:type`` RDF predicate.
576 It implicitly sets the object value ``deo:Conclusion``.
578 **WARNING: any existing rhetorical type WILL NOT be overwritten.**
579 """
580 create_type(self.g, self.res, GraphEntity.iri_conclusion)