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

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 

17 

18import re 

19from typing import TYPE_CHECKING 

20 

21if TYPE_CHECKING: 

22 from typing import Optional 

23 from rdflib import URIRef 

24 

25from oc_ocdm.graph.graph_entity import GraphEntity 

26from oc_ocdm.decorators import accepts_only 

27from oc_ocdm.graph.entities.bibliographic_entity import BibliographicEntity 

28 

29 

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.""" 

33 

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!** 

42 

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. 

47 

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) 

55 

56 media_type: Optional[URIRef] = other.get_media_type() 

57 if media_type is not None: 

58 self.has_media_type(media_type) 

59 

60 starting_page: Optional[str] = other.get_starting_page() 

61 if starting_page is not None: 

62 self.has_starting_page(starting_page) 

63 

64 ending_page: Optional[str] = other.get_ending_page() 

65 if ending_page is not None: 

66 self.has_ending_page(ending_page) 

67 

68 url: Optional[URIRef] = other.get_url() 

69 if url is not None: 

70 self.has_url(url) 

71 

72 # HAS FORMAT 

73 def get_media_type(self) -> Optional[URIRef]: 

74 """ 

75 Getter method corresponding to the ``dcterms:format`` RDF predicate. 

76 

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 

81 

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. 

86 

87 **WARNING: this is a functional property, hence any existing value will be overwritten!** 

88 

89 `It allows one to specify the IANA media type of the embodiment.` 

90 

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)) 

98 

99 def remove_media_type(self) -> None: 

100 """ 

101 Remover method corresponding to the ``dcterms:format`` RDF predicate. 

102 

103 :return: None 

104 """ 

105 self.g.remove((self.res, GraphEntity.iri_has_format, None)) 

106 

107 # HAS FIRST PAGE 

108 def get_starting_page(self) -> Optional[str]: 

109 """ 

110 Getter method corresponding to the ``prism:startingPage`` RDF predicate. 

111 

112 :return: The requested value if found, None otherwise 

113 """ 

114 return self._get_literal(GraphEntity.iri_starting_page) 

115 

116 @accepts_only('literal') 

117 def has_starting_page(self, string: str) -> None: 

118 """ 

119 Setter method corresponding to the ``prism:startingPage`` RDF predicate. 

120 

121 The string gets internally preprocessed by eventually removing dashes and everything 

122 that follows them (e.g. '22-45' becomes '22'). 

123 

124 **WARNING: this is a functional property, hence any existing value will be overwritten!** 

125 

126 `The first page of the bibliographic resource according to the current embodiment.` 

127 

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) 

140 

141 def remove_starting_page(self) -> None: 

142 """ 

143 Remover method corresponding to the ``prism:startingPage`` RDF predicate. 

144 

145 :return: None 

146 """ 

147 self.g.remove((self.res, GraphEntity.iri_starting_page, None)) 

148 

149 # HAS LAST PAGE 

150 def get_ending_page(self) -> Optional[str]: 

151 """ 

152 Getter method corresponding to the ``prism:endingPage`` RDF predicate. 

153 

154 :return: The requested value if found, None otherwise 

155 """ 

156 return self._get_literal(GraphEntity.iri_ending_page) 

157 

158 @accepts_only('literal') 

159 def has_ending_page(self, string: str) -> None: 

160 """ 

161 Setter method corresponding to the ``prism:endingPage`` RDF predicate. 

162 

163 The string gets internally preprocessed by eventually removing dashes and everything 

164 that comes before them (e.g. '22-45' becomes '45'). 

165 

166 **WARNING: this is a functional property, hence any existing value will be overwritten!** 

167 

168 `The last page of the bibliographic resource according to the current embodiment.` 

169 

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) 

182 

183 def remove_ending_page(self) -> None: 

184 """ 

185 Remover method corresponding to the ``prism:endingPage`` RDF predicate. 

186 

187 :return: None 

188 """ 

189 self.g.remove((self.res, GraphEntity.iri_ending_page, None)) 

190 

191 # HAS URL 

192 def get_url(self) -> Optional[URIRef]: 

193 """ 

194 Getter method corresponding to the ``frbr:exemplar`` RDF predicate. 

195 

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 

200 

201 @accepts_only('thing') 

202 def has_url(self, thing_res: URIRef) -> None: 

203 """ 

204 Setter method corresponding to the ``frbr:exemplar`` RDF predicate. 

205 

206 **WARNING: this is a functional property, hence any existing value will be overwritten!** 

207 

208 `The URL at which the embodiment of the bibliographic resource is available.` 

209 

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)) 

217 

218 def remove_url(self) -> None: 

219 """ 

220 Remover method corresponding to the ``frbr:exemplar`` RDF predicate. 

221 

222 :return: None 

223 """ 

224 self.g.remove((self.res, GraphEntity.iri_has_url, None)) 

225 

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``. 

231 

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!** 

235 

236 `It identifies the particular type of the embodiment, either digital or print.` 

237 

238 :return: None 

239 """ 

240 self._create_type(GraphEntity.iri_digital_manifestation) 

241 

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``. 

246 

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!** 

250 

251 `It identifies the particular type of the embodiment, either digital or print.` 

252 

253 :return: None 

254 """ 

255 self._create_type(GraphEntity.iri_print_object)