Coverage for oc_ocdm / graph / entities / bibliographic / citation.py: 98%

86 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-07-06 20:05 +0000

1#!/usr/bin/python 

2 

3# SPDX-FileCopyrightText: 2020-2022 Simone Persiani <iosonopersia@gmail.com> 

4# 

5# SPDX-License-Identifier: ISC 

6 

7# -*- coding: utf-8 -*- 

8from __future__ import annotations 

9 

10from typing import TYPE_CHECKING 

11 

12from triplelite import RDFTerm 

13 

14from oc_ocdm.constants import XSD_DURATION 

15from oc_ocdm.decorators import accepts_only 

16from oc_ocdm.support.support import get_datatype_from_iso_8601 

17 

18if TYPE_CHECKING: 

19 from typing import Optional 

20 

21 from oc_ocdm.graph.entities.bibliographic.bibliographic_resource import BibliographicResource 

22from oc_ocdm.graph.entities.bibliographic_entity import BibliographicEntity 

23from oc_ocdm.graph.graph_entity import GraphEntity 

24 

25 

26class Citation(BibliographicEntity): 

27 """Citation (short: ci): a permanent conceptual directional link from the citing 

28 bibliographic resource to a cited bibliographic resource. A citation is created by the 

29 performative act of an author citing a published work that is relevant to the current 

30 work by using a particular textual device. Typically, citations are made by including a 

31 bibliographic reference in the reference list of the citing work and by denoting such a 

32 bibliographic reference using one or more in-text reference pointers (e.g. '[1]'), or by 

33 the inclusion within the citing work of a link, in the form of an HTTP Uniform Resource 

34 Locator (URL), to the cited bibliographic resource on the World Wide Web.""" 

35 

36 def _merge_properties(self, other: GraphEntity, prefer_self: bool) -> None: 

37 """ 

38 The merge operation allows combining two ``Citation`` entities into a single one, 

39 by marking the second entity as to be deleted while also copying its data into the current 

40 ``Citation``. Moreover, every triple from the containing ``GraphSet`` referring to the second 

41 entity gets "redirected" to the current entity: **every other reference contained inside a 

42 different source (e.g. a triplestore) must be manually handled by the user!** 

43 

44 By default, functional values from the current entity get overwritten by values 

45 from the second entity. When ``prefer_self`` is True, existing functional values 

46 from the current entity are kept. Non-functional values from the second entity 

47 are appended to those of the current entity. In this context, 

48 ``rdfs:label`` is considered as a functional property, while ``rdf:type`` is not. 

49 

50 :param other: The entity which will be marked as to be deleted and whose properties will 

51 be merged into the current entity. 

52 :type other: Citation 

53 :raises TypeError: if the parameter is of the wrong type 

54 :return: None 

55 """ 

56 super()._merge_properties(other, prefer_self) 

57 assert isinstance(other, Citation) 

58 

59 citing_br: Optional[BibliographicResource] = other.get_citing_entity() 

60 if citing_br is not None and self._should_merge_functional_property(self.get_citing_entity(), prefer_self): 

61 self.has_citing_entity(citing_br) 

62 

63 cited_br: Optional[BibliographicResource] = other.get_cited_entity() 

64 if cited_br is not None and self._should_merge_functional_property(self.get_cited_entity(), prefer_self): 

65 self.has_cited_entity(cited_br) 

66 

67 creation_date: Optional[str] = other.get_citation_creation_date() 

68 if creation_date is not None and self._should_merge_functional_property( 

69 self.get_citation_creation_date(), 

70 prefer_self, 

71 ): 

72 self.has_citation_creation_date(creation_date) 

73 

74 time_span: Optional[str] = other.get_citation_time_span() 

75 if time_span is not None and self._should_merge_functional_property( 

76 self.get_citation_time_span(), 

77 prefer_self, 

78 ): 

79 self.has_citation_time_span(time_span) 

80 

81 characterization: Optional[str] = other.get_citation_characterization() 

82 if characterization is not None and self._should_merge_functional_property( 

83 self.get_citation_characterization(), 

84 prefer_self, 

85 ): 

86 self.has_citation_characterization(characterization) 

87 

88 # HAS CITING DOCUMENT (BibliographicResource) 

89 def get_citing_entity(self) -> Optional[BibliographicResource]: 

90 """ 

91 Getter method corresponding to the ``cito:hasCitingEntity`` RDF predicate. 

92 

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

94 """ 

95 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_has_citing_entity, "br") 

96 if uri is not None: 

97 return self.g_set.add_br(self.resp_agent, self.source, uri) 

98 

99 @accepts_only("br") 

100 def has_citing_entity(self, citing_res: BibliographicResource) -> None: 

101 """ 

102 Setter method corresponding to the ``cito:hasCitingEntity`` RDF predicate. 

103 

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

105 

106 `The bibliographic resource which acts as the source for the citation.` 

107 

108 :param citing_res: The value that will be set as the object of the property related to this method 

109 :type citing_res: BibliographicResource 

110 :raises TypeError: if the parameter is of the wrong type 

111 :return: None 

112 """ 

113 self.remove_citing_entity() 

114 self.g.add((self.res, GraphEntity.iri_has_citing_entity, RDFTerm("uri", str(citing_res.res)))) 

115 

116 def remove_citing_entity(self) -> None: 

117 """ 

118 Remover method corresponding to the ``cito:hasCitingEntity`` RDF predicate. 

119 

120 :return: None 

121 """ 

122 self.g.remove((self.res, GraphEntity.iri_has_citing_entity, None)) 

123 

124 # HAS CITED DOCUMENT (BibliographicResource) 

125 def get_cited_entity(self) -> Optional[BibliographicResource]: 

126 """ 

127 Getter method corresponding to the ``cito:hasCitedEntity`` RDF predicate. 

128 

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

130 """ 

131 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_has_cited_entity, "br") 

132 if uri is not None: 

133 return self.g_set.add_br(self.resp_agent, self.source, uri) 

134 

135 @accepts_only("br") 

136 def has_cited_entity(self, cited_res: BibliographicResource) -> None: 

137 """ 

138 Setter method corresponding to the ``cito:hasCitedEntity`` RDF predicate. 

139 

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

141 

142 `The bibliographic resource which acts as the target for the citation.` 

143 

144 :param cited_res: The value that will be set as the object of the property related to this method 

145 :type cited_res: BibliographicResource 

146 :raises TypeError: if the parameter is of the wrong type 

147 :return: None 

148 """ 

149 self.remove_cited_entity() 

150 self.g.add((self.res, GraphEntity.iri_has_cited_entity, RDFTerm("uri", str(cited_res.res)))) 

151 

152 def remove_cited_entity(self) -> None: 

153 """ 

154 Remover method corresponding to the ``c4o:hasCitedEntity`` RDF predicate. 

155 

156 :return: None 

157 """ 

158 self.g.remove((self.res, GraphEntity.iri_has_cited_entity, None)) 

159 

160 # HAS CITATION CREATION DATE 

161 def get_citation_creation_date(self) -> Optional[str]: 

162 """ 

163 Getter method corresponding to the ``cito:hasCitationCreationDate`` RDF predicate. 

164 

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

166 """ 

167 return self._get_literal(GraphEntity.iri_has_citation_creation_date) 

168 

169 def has_citation_creation_date(self, string: str) -> None: 

170 """ 

171 Setter method corresponding to the ``cito:hasCitationCreationDate`` RDF predicate. 

172 

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

174 

175 `The date on which the citation was created. This has the same numerical value 

176 as the publication date of the citing bibliographic resource, but is a property 

177 of the citation itself. When combined with the citation time span, it permits 

178 that citation to be located in history.` 

179 

180 :param string: The value that will be set as the object of the property related to this method. **It must 

181 be a string compliant with the** ``ISO 8601`` **standard.** 

182 :type string: str 

183 :raises TypeError: if the parameter is of the wrong type 

184 :return: None 

185 """ 

186 cur_type, string = get_datatype_from_iso_8601(string) 

187 self.remove_citation_creation_date() 

188 self._create_literal(GraphEntity.iri_has_citation_creation_date, string, cur_type, False) 

189 

190 def remove_citation_creation_date(self) -> None: 

191 """ 

192 Remover method corresponding to the ``c4o:hasCitationCreationDate`` RDF predicate. 

193 

194 :return: None 

195 """ 

196 self.g.remove((self.res, GraphEntity.iri_has_citation_creation_date, None)) 

197 

198 # HAS CITATION TIME SPAN 

199 def get_citation_time_span(self) -> Optional[str]: 

200 """ 

201 Getter method corresponding to the ``cito:hasCitationTimeSpan`` RDF predicate. 

202 

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

204 """ 

205 return self._get_literal(GraphEntity.iri_has_citation_time_span) 

206 

207 def has_citation_time_span(self, string: str) -> None: 

208 """ 

209 Setter method corresponding to the ``cito:hasCitationTimeSpan`` RDF predicate. 

210 

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

212 

213 `The date interval between the publication date of the cited bibliographic resource and 

214 the publication date of the citing bibliographic resource.` 

215 

216 :param string: The value that will be set as the object of the property related to this method. **It must 

217 be a string compliant with the** ``xsd:duration`` **datatype.** 

218 :type string: str 

219 :raises TypeError: if the parameter is of the wrong type 

220 :return: None 

221 """ 

222 self.remove_citation_time_span() 

223 self._create_literal(GraphEntity.iri_has_citation_time_span, string, XSD_DURATION, False) 

224 

225 def remove_citation_time_span(self) -> None: 

226 """ 

227 Remover method corresponding to the ``c4o:hasCitationTimeSpan`` RDF predicate. 

228 

229 :return: None 

230 """ 

231 self.g.remove((self.res, GraphEntity.iri_has_citation_time_span, None)) 

232 

233 # HAS CITATION CHARACTERIZATION 

234 def get_citation_characterization(self) -> Optional[str]: 

235 """ 

236 Getter method corresponding to the ``cito:hasCitationCharacterisation`` RDF predicate. 

237 

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

239 """ 

240 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_citation_characterisation) 

241 return uri 

242 

243 def has_citation_characterization(self, thing_res: str) -> None: 

244 """ 

245 Setter method corresponding to the ``cito:hasCitationCharacterisation`` RDF predicate. 

246 

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

248 

249 `The citation function characterizing the purpose of the citation.` 

250 

251 :param thing_res: The value that will be set as the object of the property related to this method 

252 :type thing_res: URIRef 

253 :raises TypeError: if the parameter is of the wrong type 

254 :return: None 

255 """ 

256 self.remove_citation_characterization() 

257 self.g.add((self.res, GraphEntity.iri_citation_characterisation, RDFTerm("uri", str(thing_res)))) 

258 

259 def remove_citation_characterization(self) -> None: 

260 """ 

261 Remover method corresponding to the ``c4o:hasCitationCharacterisation`` RDF predicate. 

262 

263 :return: None 

264 """ 

265 self.g.remove((self.res, GraphEntity.iri_citation_characterisation, None)) 

266 

267 # HAS TYPE 

268 def create_self_citation(self) -> None: 

269 """ 

270 Setter method corresponding to the ``rdf:type`` RDF predicate. 

271 It implicitly sets the object value ``cito:SelfCitation``. 

272 

273 **WARNING: the OCDM specification admits at most two types for an entity. 

274 The main type cannot be edited or removed. Any existing secondary type 

275 will be overwritten!** 

276 

277 :return: None 

278 """ 

279 self._create_type(GraphEntity.iri_self_citation) 

280 

281 def create_affiliation_self_citation(self) -> None: 

282 """ 

283 Setter method corresponding to the ``rdf:type`` RDF predicate. 

284 It implicitly sets the object value ``cito:AffiliationSelfCitation``. 

285 

286 **WARNING: the OCDM specification admits at most two types for an entity. 

287 The main type cannot be edited or removed. Any existing secondary type 

288 will be overwritten!** 

289 

290 :return: None 

291 """ 

292 self._create_type(GraphEntity.iri_affiliation_self_citation) 

293 

294 def create_author_network_self_citation(self) -> None: 

295 """ 

296 Setter method corresponding to the ``rdf:type`` RDF predicate. 

297 It implicitly sets the object value ``cito:AuthorNetworkSelfCitation``. 

298 

299 **WARNING: the OCDM specification admits at most two types for an entity. 

300 The main type cannot be edited or removed. Any existing secondary type 

301 will be overwritten!** 

302 

303 :return: None 

304 """ 

305 self._create_type(GraphEntity.iri_author_network_self_citation) 

306 

307 def create_author_self_citation(self) -> None: 

308 """ 

309 Setter method corresponding to the ``rdf:type`` RDF predicate. 

310 It implicitly sets the object value ``cito:AuthorSelfCitation``. 

311 

312 **WARNING: the OCDM specification admits at most two types for an entity. 

313 The main type cannot be edited or removed. Any existing secondary type 

314 will be overwritten!** 

315 

316 :return: None 

317 """ 

318 self._create_type(GraphEntity.iri_author_self_citation) 

319 

320 def create_funder_self_citation(self) -> None: 

321 """ 

322 Setter method corresponding to the ``rdf:type`` RDF predicate. 

323 It implicitly sets the object value ``cito:FunderSelfCitation``. 

324 

325 **WARNING: the OCDM specification admits at most two types for an entity. 

326 The main type cannot be edited or removed. Any existing secondary type 

327 will be overwritten!** 

328 

329 :return: None 

330 """ 

331 self._create_type(GraphEntity.iri_funder_self_citation) 

332 

333 def create_journal_self_citation(self) -> None: 

334 """ 

335 Setter method corresponding to the ``rdf:type`` RDF predicate. 

336 It implicitly sets the object value ``cito:JournalSelfCitation``. 

337 

338 **WARNING: the OCDM specification admits at most two types for an entity. 

339 The main type cannot be edited or removed. Any existing secondary type 

340 will be overwritten!** 

341 

342 :return: None 

343 """ 

344 self._create_type(GraphEntity.iri_journal_self_citation) 

345 

346 def create_journal_cartel_citation(self) -> None: 

347 """ 

348 Setter method corresponding to the ``rdf:type`` RDF predicate. 

349 It implicitly sets the object value ``cito:JournalCartelCitation``. 

350 

351 **WARNING: the OCDM specification admits at most two types for an entity. 

352 The main type cannot be edited or removed. Any existing secondary type 

353 will be overwritten!** 

354 

355 :return: None 

356 """ 

357 self._create_type(GraphEntity.iri_journal_cartel_citation) 

358 

359 def create_distant_citation(self) -> None: 

360 """ 

361 Setter method corresponding to the ``rdf:type`` RDF predicate. 

362 It implicitly sets the object value ``cito:DistantCitation``. 

363 

364 **WARNING: the OCDM specification admits at most two types for an entity. 

365 The main type cannot be edited or removed. Any existing secondary type 

366 will be overwritten!** 

367 

368 :return: None 

369 """ 

370 self._create_type(GraphEntity.iri_distant_citation)