Coverage for oc_ocdm / graph / entities / identifier.py: 94%

67 statements  

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

1#!/usr/bin/python 

2 

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

4# SPDX-FileCopyrightText: 2022-2023 Arcangelo Massari <arcangelo.massari@unibo.it> 

5# 

6# SPDX-License-Identifier: ISC 

7 

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

9from __future__ import annotations 

10 

11import re 

12from typing import TYPE_CHECKING 

13 

14if TYPE_CHECKING: 

15 from typing import Optional 

16 

17from triplelite import RDFTerm 

18 

19from oc_ocdm.graph.graph_entity import GraphEntity 

20from oc_ocdm.support.support import encode_url, is_string_empty 

21 

22 

23class Identifier(GraphEntity): 

24 """Identifier (short: id): an external identifier (e.g. DOI, ORCID, PubMedID, Open 

25 Citation Identifier) associated with the bibliographic entity. Members of this class of 

26 metadata are themselves given unique corpus identifiers e.g. 'id/0420129'.""" 

27 

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

29 """ 

30 The merge operation allows combining two ``Identifier`` entities into a single one, 

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

32 ``Identifier``. Moreover, every triple from the containing ``GraphSet`` referring to the second 

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

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

35 

36 In case of functional properties, values from the current entity get overwritten 

37 by those coming from the second entity while, in all other cases, values from the 

38 second entity are simply appended to those of the current entity. In this context, 

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

40 

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

42 be merged into the current entity. 

43 :type other: Identifier 

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

45 :return: None 

46 """ 

47 super()._merge_properties(other, prefer_self) 

48 assert isinstance(other, Identifier) 

49 

50 literal_value: Optional[str] = other.get_literal_value() 

51 scheme: Optional[str] = other.get_scheme() 

52 if literal_value is not None and scheme is not None: 

53 self._associate_identifier_with_scheme(literal_value, scheme) 

54 

55 # HAS LITERAL VALUE and HAS SCHEME 

56 def get_literal_value(self) -> Optional[str]: 

57 """ 

58 Getter method corresponding to the ``literal:hasLiteralValue`` RDF predicate. 

59 

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

61 """ 

62 return self._get_literal(GraphEntity.iri_has_literal_value) 

63 

64 def get_scheme(self) -> Optional[str]: 

65 """ 

66 Getter method corresponding to the ``datacite:usesIdentifierScheme`` RDF predicate. 

67 

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

69 """ 

70 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_uses_identifier_scheme) 

71 return uri 

72 

73 def create_oci(self, string: str) -> None: 

74 """ 

75 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

76 ``datacite:usesIdentifierScheme`` RDF predicate. 

77 It implicitly sets the object value ``datacite:oci`` for the 

78 ``datacite:usesIdentifierScheme`` RDF predicate. 

79 

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

81 

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

83 :type string: str 

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

85 :return: None 

86 """ 

87 self._associate_identifier_with_scheme(string, GraphEntity.iri_oci) 

88 

89 def create_orcid(self, string: str) -> None: 

90 """ 

91 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

92 ``datacite:usesIdentifierScheme`` RDF predicate. 

93 It implicitly sets the object value ``datacite:orcid`` for the 

94 ``datacite:usesIdentifierScheme`` RDF predicate. 

95 

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

97 

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

99 :type string: str 

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

101 :return: None 

102 """ 

103 self._associate_identifier_with_scheme(string, GraphEntity.iri_orcid) 

104 

105 def create_openalex(self, string: str) -> None: 

106 """ 

107 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

108 ``datacite:usesIdentifierScheme`` RDF predicate. 

109 It implicitly sets the object value ``datacite:openalex`` for the 

110 ``datacite:usesIdentifierScheme`` RDF predicate. 

111 

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

113 

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

115 :type string: str 

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

117 :return: None 

118 """ 

119 self._associate_identifier_with_scheme(string, GraphEntity.iri_openalex) 

120 

121 def create_doi(self, string: str) -> None: 

122 """ 

123 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

124 ``datacite:usesIdentifierScheme`` RDF predicate. 

125 It implicitly sets the object value ``datacite:doi`` for the 

126 ``datacite:usesIdentifierScheme`` RDF predicate. 

127 

128 The string gets internally preprocessed by converting it to lowercase 

129 (e.g. 'DOI:10.1111/HEX.12487' becomes 'doi:10.1111/hex.12487'). 

130 

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

132 

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

134 :type string: str 

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

136 :return: None 

137 """ 

138 self._associate_identifier_with_scheme(string.lower(), GraphEntity.iri_doi) 

139 

140 def create_jid(self, string: str) -> None: 

141 """ 

142 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

143 ``datacite:usesIdentifierScheme`` RDF predicate. 

144 It implicitly sets the object value ``datacite:jid`` for the 

145 ``datacite:usesIdentifierScheme`` RDF predicate. 

146 

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

148 

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

150 :type string: str 

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

152 :return: None 

153 """ 

154 self._associate_identifier_with_scheme(string, GraphEntity.iri_jid) 

155 

156 def create_pmid(self, string: str) -> None: 

157 """ 

158 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

159 ``datacite:usesIdentifierScheme`` RDF predicate. 

160 It implicitly sets the object value ``datacite:pmid`` for the 

161 ``datacite:usesIdentifierScheme`` RDF predicate. 

162 

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

164 

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

166 :type string: str 

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

168 :return: None 

169 """ 

170 self._associate_identifier_with_scheme(string, GraphEntity.iri_pmid) 

171 

172 def create_pmcid(self, string: str) -> None: 

173 """ 

174 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

175 ``datacite:usesIdentifierScheme`` RDF predicate. 

176 It implicitly sets the object value ``datacite:pmcid`` for the 

177 ``datacite:usesIdentifierScheme`` RDF predicate. 

178 

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

180 

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

182 :type string: str 

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

184 :return: None 

185 """ 

186 self._associate_identifier_with_scheme(string, GraphEntity.iri_pmcid) 

187 

188 def create_issn(self, string: str) -> None: 

189 """ 

190 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

191 ``datacite:usesIdentifierScheme`` RDF predicate. 

192 It implicitly sets the object value ``datacite:issn`` for the 

193 ``datacite:usesIdentifierScheme`` RDF predicate. 

194 

195 The string gets internally preprocessed by eventually replacing long dashes with short ones 

196 (e.g. '1522–4501' becomes '1522-4501'). 

197 

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

199 

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

201 must be a string different from '0000-0000'.** 

202 :type string: str 

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

204 :return: None 

205 """ 

206 cur_string = re.sub("–", "-", string) 

207 if cur_string != "0000-0000": 

208 self._associate_identifier_with_scheme(cur_string, GraphEntity.iri_issn) 

209 

210 def create_isbn(self, string: str) -> None: 

211 """ 

212 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

213 ``datacite:usesIdentifierScheme`` RDF predicate. 

214 It implicitly sets the object value ``datacite:isbn`` for the 

215 ``datacite:usesIdentifierScheme`` RDF predicate. 

216 

217 The string gets internally preprocessed by eventually replacing long dashes with short ones 

218 (e.g. '817525766–0' becomes '817525766-0'). 

219 

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

221 

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

223 :type string: str 

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

225 :return: None 

226 """ 

227 self._associate_identifier_with_scheme(re.sub("–", "-", string), GraphEntity.iri_isbn) 

228 

229 def create_url(self, string: str) -> None: 

230 """ 

231 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

232 ``datacite:usesIdentifierScheme`` RDF predicate. 

233 It implicitly sets the object value ``datacite:url`` for the 

234 ``datacite:usesIdentifierScheme`` RDF predicate. 

235 

236 The string gets internally preprocessed both by converting it to lowercase 

237 (e.g. 'https://OPENCITATIONS.NET/' becomes 'https://opencitations.net/') and by 

238 applying `URL encoding` on it (e.g. 'https://opencitations.net/file name.txt' 

239 becomes 'https://opencitations.net/file%20name.txt'). 

240 

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

242 

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

244 :type string: str 

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

246 :return: None 

247 """ 

248 self._associate_identifier_with_scheme(encode_url(string.lower()), GraphEntity.iri_url) 

249 

250 def create_xpath(self, string: str) -> None: 

251 """ 

252 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

253 ``datacite:usesIdentifierScheme`` RDF predicate. 

254 It implicitly sets the object value `datacite:local-resource-identifier-scheme` for the 

255 ``datacite:usesIdentifierScheme`` RDF predicate. 

256 

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

258 

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

260 :type string: str 

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

262 :return: None 

263 """ 

264 self._associate_identifier_with_scheme(string, GraphEntity.iri_xpath) 

265 

266 def create_intrepid(self, string: str) -> None: 

267 """ 

268 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

269 ``datacite:usesIdentifierScheme`` RDF predicate. 

270 It implicitly sets the object value ``datacite:intrepid`` for the 

271 ``datacite:usesIdentifierScheme`` RDF predicate. 

272 

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

274 

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

276 :type string: str 

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

278 :return: None 

279 """ 

280 self._associate_identifier_with_scheme(string, GraphEntity.iri_intrepid) 

281 

282 def create_xmlid(self, string: str) -> None: 

283 """ 

284 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

285 ``datacite:usesIdentifierScheme`` RDF predicate. 

286 It implicitly sets the object value `datacite:local-resource-identifier-scheme` for the 

287 ``datacite:usesIdentifierScheme`` RDF predicate. 

288 

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

290 

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

292 :type string: str 

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

294 :return: None 

295 """ 

296 self._associate_identifier_with_scheme(string, GraphEntity.iri_xmlid) 

297 

298 def create_wikidata(self, string: str) -> None: 

299 """ 

300 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

301 ``datacite:usesIdentifierScheme`` RDF predicate. 

302 It implicitly sets the object value ``datacite:wikidata`` for the 

303 ``datacite:usesIdentifierScheme`` RDF predicate. 

304 

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

306 

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

308 :type string: str 

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

310 :return: None 

311 """ 

312 self._associate_identifier_with_scheme(string, GraphEntity.iri_wikidata) 

313 

314 def create_wikipedia(self, string: str) -> None: 

315 """ 

316 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

317 ``datacite:usesIdentifierScheme`` RDF predicate. 

318 It implicitly sets the object value ``datacite:wikipedia`` for the 

319 ``datacite:usesIdentifierScheme`` RDF predicate. 

320 

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

322 

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

324 :type string: str 

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

326 :return: None 

327 """ 

328 self._associate_identifier_with_scheme(string, GraphEntity.iri_wikipedia) 

329 

330 def create_arxiv(self, string: str) -> None: 

331 """ 

332 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

333 ``datacite:usesIdentifierScheme`` RDF predicate. 

334 It implicitly sets the object value ``datacite:crossref`` for the 

335 ``datacite:usesIdentifierScheme`` RDF predicate. 

336 

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

338 

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

340 :type string: str 

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

342 :return: None 

343 """ 

344 self._associate_identifier_with_scheme(string, GraphEntity.iri_arxiv) 

345 

346 def create_crossref(self, string: str) -> None: 

347 """ 

348 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

349 ``datacite:usesIdentifierScheme`` RDF predicate. 

350 It implicitly sets the object value ``datacite:crossref`` for the 

351 ``datacite:usesIdentifierScheme`` RDF predicate. 

352 

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

354 

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

356 :type string: str 

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

358 :return: None 

359 """ 

360 self._associate_identifier_with_scheme(string, GraphEntity.iri_crossref) 

361 

362 def create_datacite(self, string: str) -> None: 

363 """ 

364 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

365 ``datacite:usesIdentifierScheme`` RDF predicate. 

366 It implicitly sets the object value ``datacite:datacite`` for the 

367 ``datacite:usesIdentifierScheme`` RDF predicate. 

368 

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

370 

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

372 :type string: str 

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

374 :return: None 

375 """ 

376 self._associate_identifier_with_scheme(string, GraphEntity.iri_datacite) 

377 

378 def create_viaf(self, string: str) -> None: 

379 """ 

380 Setter method corresponding to both the ``literal:hasLiteralValue`` and the 

381 ``datacite:usesIdentifierScheme`` RDF predicate. 

382 It implicitly sets the object value ``datacite:viaf`` for the 

383 ``datacite:usesIdentifierScheme`` RDF predicate. 

384 

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

386 

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

388 :type string: str 

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

390 :return: None 

391 """ 

392 self._associate_identifier_with_scheme(string, GraphEntity.iri_viaf) 

393 

394 def _associate_identifier_with_scheme(self, string: str, id_type: str) -> None: 

395 if not is_string_empty(string): 

396 self.remove_identifier_with_scheme() 

397 self._create_literal(GraphEntity.iri_has_literal_value, string) 

398 self.g.add((self.res, GraphEntity.iri_uses_identifier_scheme, RDFTerm("uri", str(id_type)))) 

399 

400 def remove_identifier_with_scheme(self) -> None: 

401 """ 

402 Remover method corresponding to both the ``literal:hasLiteralValue`` and the 

403 ``datacite:usesIdentifierScheme`` RDF predicate. 

404 

405 :return: None 

406 """ 

407 self.g.remove((self.res, GraphEntity.iri_has_literal_value, None)) 

408 self.g.remove((self.res, GraphEntity.iri_uses_identifier_scheme, None))