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