Coverage for oc_ocdm / graph / entities / bibliographic / resource_embodiment.py: 94%
62 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
10import re
11from typing import TYPE_CHECKING
13if TYPE_CHECKING:
14 from typing import Optional
16from triplelite import RDFTerm
18from oc_ocdm.graph.entities.bibliographic_entity import BibliographicEntity
19from oc_ocdm.graph.graph_entity import GraphEntity
22class ResourceEmbodiment(BibliographicEntity):
23 """Resource embodiment (short: re): the particular physical or digital format in which a
24 bibliographic resource was made available by its publisher."""
26 def _merge_properties(self, other: GraphEntity, prefer_self: bool) -> None:
27 """
28 The merge operation allows combining two ``ResourceEmbodiment`` entities into a single one,
29 by marking the second entity as to be deleted while also copying its data into the current
30 ``ResourceEmbodiment``. Moreover, every triple from the containing ``GraphSet`` referring to the second
31 entity gets "redirected" to the current entity: **every other reference contained inside a
32 different source (e.g. a triplestore) must be manually handled by the user!**
34 In case of functional properties, values from the current entity get overwritten
35 by those coming from the second entity while, in all other cases, values from the
36 second entity are simply appended to those of the current entity. In this context,
37 ``rdfs:label`` is considered as a functional property, while ``rdf:type`` is not.
39 :param other: The entity which will be marked as to be deleted and whose properties will
40 be merged into the current entity.
41 :type other: ResourceEmbodiment
42 :raises TypeError: if the parameter is of the wrong type
43 :return: None
44 """
45 super()._merge_properties(other, prefer_self)
46 assert isinstance(other, ResourceEmbodiment)
48 media_type: Optional[str] = other.get_media_type()
49 if media_type is not None:
50 self.has_media_type(media_type)
52 starting_page: Optional[str] = other.get_starting_page()
53 if starting_page is not None:
54 self.has_starting_page(starting_page)
56 ending_page: Optional[str] = other.get_ending_page()
57 if ending_page is not None:
58 self.has_ending_page(ending_page)
60 url: Optional[str] = other.get_url()
61 if url is not None:
62 self.has_url(url)
64 # HAS FORMAT
65 def get_media_type(self) -> Optional[str]:
66 """
67 Getter method corresponding to the ``dcterms:format`` RDF predicate.
69 :return: The requested value if found, None otherwise
70 """
71 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_has_format)
72 return uri
74 def has_media_type(self, thing_res: str) -> None:
75 """
76 Setter method corresponding to the ``dcterms:format`` RDF predicate.
78 **WARNING: this is a functional property, hence any existing value will be overwritten!**
80 `It allows one to specify the IANA media type of the embodiment.`
82 :param thing_res: The value that will be set as the object of the property related to this method
83 :type thing_res: URIRef
84 :raises TypeError: if the parameter is of the wrong type
85 :return: None
86 """
87 self.remove_media_type()
88 self.g.add((self.res, GraphEntity.iri_has_format, RDFTerm("uri", str(thing_res))))
90 def remove_media_type(self) -> None:
91 """
92 Remover method corresponding to the ``dcterms:format`` RDF predicate.
94 :return: None
95 """
96 self.g.remove((self.res, GraphEntity.iri_has_format, None))
98 # HAS FIRST PAGE
99 def get_starting_page(self) -> Optional[str]:
100 """
101 Getter method corresponding to the ``prism:startingPage`` RDF predicate.
103 :return: The requested value if found, None otherwise
104 """
105 return self._get_literal(GraphEntity.iri_starting_page)
107 def has_starting_page(self, string: str) -> None:
108 """
109 Setter method corresponding to the ``prism:startingPage`` RDF predicate.
111 The string gets internally preprocessed by eventually removing dashes and everything
112 that follows them (e.g. '22-45' becomes '22').
114 **WARNING: this is a functional property, hence any existing value will be overwritten!**
116 `The first page of the bibliographic resource according to the current embodiment.`
118 :param string: The value that will be set as the object of the property related to this method. **It must
119 be a string that starts with an integer number.**
120 :type string: str
121 :raises TypeError: if the parameter is of the wrong type
122 :return: None
123 """
124 self.remove_starting_page()
125 if re.search("[-–]+", string) is None:
126 page_number = string
127 else:
128 page_number = re.sub("[-–]+.*$", "", string)
129 self._create_literal(GraphEntity.iri_starting_page, page_number)
131 def remove_starting_page(self) -> None:
132 """
133 Remover method corresponding to the ``prism:startingPage`` RDF predicate.
135 :return: None
136 """
137 self.g.remove((self.res, GraphEntity.iri_starting_page, None))
139 # HAS LAST PAGE
140 def get_ending_page(self) -> Optional[str]:
141 """
142 Getter method corresponding to the ``prism:endingPage`` RDF predicate.
144 :return: The requested value if found, None otherwise
145 """
146 return self._get_literal(GraphEntity.iri_ending_page)
148 def has_ending_page(self, string: str) -> None:
149 """
150 Setter method corresponding to the ``prism:endingPage`` RDF predicate.
152 The string gets internally preprocessed by eventually removing dashes and everything
153 that comes before them (e.g. '22-45' becomes '45').
155 **WARNING: this is a functional property, hence any existing value will be overwritten!**
157 `The last page of the bibliographic resource according to the current embodiment.`
159 :param string: The value that will be set as the object of the property related to this method. **It must
160 be a string that ends with an integer number.**
161 :type string: str
162 :raises TypeError: if the parameter is of the wrong type
163 :return: None
164 """
165 self.remove_ending_page()
166 if re.search("[-–]+", string) is None:
167 page_number = string
168 else:
169 page_number = re.sub("^.*[-–]+", "", string)
170 self._create_literal(GraphEntity.iri_ending_page, page_number)
172 def remove_ending_page(self) -> None:
173 """
174 Remover method corresponding to the ``prism:endingPage`` RDF predicate.
176 :return: None
177 """
178 self.g.remove((self.res, GraphEntity.iri_ending_page, None))
180 # HAS URL
181 def get_url(self) -> Optional[str]:
182 """
183 Getter method corresponding to the ``frbr:exemplar`` RDF predicate.
185 :return: The requested value if found, None otherwise
186 """
187 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_has_url)
188 return uri
190 def has_url(self, thing_res: str) -> None:
191 """
192 Setter method corresponding to the ``frbr:exemplar`` RDF predicate.
194 **WARNING: this is a functional property, hence any existing value will be overwritten!**
196 `The URL at which the embodiment of the bibliographic resource is available.`
198 :param thing_res: The value that will be set as the object of the property related to this method
199 :type thing_res: URIRef
200 :raises TypeError: if the parameter is of the wrong type
201 :return: None
202 """
203 self.remove_url()
204 self.g.add((self.res, GraphEntity.iri_has_url, RDFTerm("uri", str(thing_res))))
206 def remove_url(self) -> None:
207 """
208 Remover method corresponding to the ``frbr:exemplar`` RDF predicate.
210 :return: None
211 """
212 self.g.remove((self.res, GraphEntity.iri_has_url, None))
214 # HAS TYPE
215 def create_digital_embodiment(self) -> None:
216 """
217 Setter method corresponding to the ``rdf:type`` RDF predicate.
218 It implicitly sets the object value ``fabio:DigitalManifestation``.
220 **WARNING: the OCDM specification admits at most two types for an entity.
221 The main type cannot be edited or removed. Any existing secondary type
222 will be overwritten!**
224 `It identifies the particular type of the embodiment, either digital or print.`
226 :return: None
227 """
228 self._create_type(GraphEntity.iri_digital_manifestation)
230 def create_print_embodiment(self) -> None:
231 """
232 Setter method corresponding to the ``rdf:type`` RDF predicate.
233 It implicitly sets the object value ``fabio:PrintObject``.
235 **WARNING: the OCDM specification admits at most two types for an entity.
236 The main type cannot be edited or removed. Any existing secondary type
237 will be overwritten!**
239 `It identifies the particular type of the embodiment, either digital or print.`
241 :return: None
242 """
243 self._create_type(GraphEntity.iri_print_object)