Coverage for portality / models / v2 / bibjson.py: 93%

687 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-04 09:41 +0100

1from portality.lib.seamless import SeamlessMixin, to_utf8_unicode 

2from portality.models.v2 import shared_structs 

3from portality import datasets 

4from portality.lib import coerce 

5 

6class JournalLikeBibJSON(SeamlessMixin): 

7 

8 __SEAMLESS_STRUCT__ = shared_structs.JOURNAL_BIBJSON.get("structs", {}).get("bibjson") 

9 

10 __SEAMLESS_COERCE__ = coerce.COERCE_MAP 

11 

12 # constructor 

13 def __init__(self, bibjson=None, **kwargs): 

14 super(JournalLikeBibJSON, self).__init__(raw=bibjson, **kwargs) 

15 

16 @property 

17 def data(self): 

18 return self.__seamless__.data 

19 

20 #################################################### 

21 # Current getters and setters 

22 

23 @property 

24 def alternative_title(self): 

25 return self.__seamless__.get_single("alternative_title") 

26 

27 @alternative_title.setter 

28 def alternative_title(self, val): 

29 self.__seamless__.set_with_struct("alternative_title", val) 

30 

31 @property 

32 def boai(self): 

33 return self.__seamless__.get_single("boai") 

34 

35 @boai.setter 

36 def boai(self, val): 

37 self.__seamless__.set_with_struct("boai", val) 

38 

39 @property 

40 def discontinued_date(self): 

41 return self.__seamless__.get_single("discontinued_date") 

42 

43 @discontinued_date.setter 

44 def discontinued_date(self, val): 

45 self.__seamless__.set_with_struct("discontinued_date", val) 

46 

47 @discontinued_date.deleter 

48 def discontinued_date(self): 

49 self.__seamless__.delete("discontinued_date") 

50 

51 @property 

52 def discontinued_datestamp(self): 

53 return self.__seamless__.get_single("discontinued_date", coerce=coerce.to_datestamp()) 

54 

55 @property 

56 def eissn(self): 

57 return self.__seamless__.get_single("eissn") 

58 

59 @eissn.setter 

60 def eissn(self, val): 

61 self.__seamless__.set_with_struct("eissn", val) 

62 

63 @eissn.deleter 

64 def eissn(self): 

65 self.__seamless__.delete("eissn") 

66 

67 @property 

68 def pissn(self): 

69 return self.__seamless__.get_single("pissn") 

70 

71 @pissn.setter 

72 def pissn(self, val): 

73 self.__seamless__.set_with_struct("pissn", val) 

74 

75 @pissn.deleter 

76 def pissn(self): 

77 self.__seamless__.delete("pissn") 

78 

79 @property 

80 def oa_start(self): 

81 return self.__seamless__.get_single("oa_start") 

82 

83 @oa_start.setter 

84 def oa_start(self, val): 

85 self.__seamless__.set_with_struct("oa_start", val) 

86 

87 @oa_start.deleter 

88 def oa_start(self): 

89 self.__seamless__.delete("oa_start") 

90 

91 @property 

92 def publication_time_weeks(self): 

93 return self.__seamless__.get_single("publication_time_weeks") 

94 

95 @publication_time_weeks.setter 

96 def publication_time_weeks(self, weeks): 

97 self.__seamless__.set_with_struct("publication_time_weeks", weeks) 

98 

99 @property 

100 def title(self): 

101 return self.__seamless__.get_single("title") 

102 

103 @title.setter 

104 def title(self, val): 

105 self.__seamless__.set_with_struct("title", val) 

106 

107 @property 

108 def is_replaced_by(self): 

109 return self.__seamless__.get_list("is_replaced_by") 

110 

111 @is_replaced_by.setter 

112 def is_replaced_by(self, val): 

113 self.__seamless__.set_with_struct("is_replaced_by", val) 

114 

115 @is_replaced_by.deleter 

116 def is_replaced_by(self): 

117 self.__seamless__.delete("is_replaced_by") 

118 

119 def add_is_replaced_by(self, val): 

120 self.__seamless__.add_to_list_with_struct("is_replaced_by", val) 

121 

122 @property 

123 def keywords(self): 

124 return self.__seamless__.get_list("keywords") 

125 

126 def add_keyword(self, keyword): 

127 if keyword is not None: 

128 self.__seamless__.add_to_list_with_struct("keywords", keyword.lower()) 

129 

130 @keywords.setter 

131 def keywords(self, keywords): 

132 self.__seamless__.set_with_struct("keywords", keywords) 

133 

134 @property 

135 def language(self): 

136 return self.__seamless__.get_list("language") 

137 

138 @language.setter 

139 def language(self, language): 

140 self.__seamless__.set_with_struct("language", language) 

141 

142 def add_language(self, language): 

143 self.__seamless__.add_to_list_with_struct("language", language) 

144 

145 @property 

146 def licenses(self): 

147 return self.__seamless__.get_list("license") 

148 

149 @property 

150 def licences(self): 

151 return self.licenses 

152 

153 def add_licence(self, license_type, url=None, by=None, sa=None, nc=None, nd=None): 

154 self.add_license(license_type, url, by, sa, nc, nd) 

155 

156 def add_license(self, license_type, url=None, by=None, sa=None, nc=None, nd=None): 

157 lobj = {"type": license_type} 

158 if url is not None: 

159 lobj["url"] = url 

160 if by is not None: 

161 lobj["BY"] = by 

162 if sa is not None: 

163 lobj["SA"] = sa 

164 if nc is not None: 

165 lobj["NC"] = nc 

166 if nd is not None: 

167 lobj["ND"] = nd 

168 

169 self.__seamless__.add_to_list_with_struct("license", lobj) 

170 

171 def remove_licenses(self): 

172 self.__seamless__.delete("license") 

173 

174 @property 

175 def replaces(self): 

176 return self.__seamless__.get_list("replaces") 

177 

178 @replaces.setter 

179 def replaces(self, val): 

180 self.__seamless__.set_with_struct("replaces", val) 

181 

182 @replaces.deleter 

183 def replaces(self): 

184 self.__seamless__.delete("replaces") 

185 

186 def add_replaces(self, val): 

187 self.__seamless__.add_to_list_with_struct("replaces", val) 

188 

189 @property 

190 def subject(self): 

191 return self.__seamless__.get_list("subject") 

192 

193 @subject.setter 

194 def subject(self, subjects): 

195 self.__seamless__.set_with_struct("subject", subjects) 

196 

197 @subject.deleter 

198 def subject(self): 

199 self.__seamless__.delete("subject") 

200 

201 def add_subject(self, scheme, term, code=None): 

202 sobj = {"scheme": scheme, "term": term} 

203 if code is not None: 

204 sobj["code"] = code 

205 self.__seamless__.add_to_list_with_struct("subject", sobj) 

206 

207 @property 

208 def apc(self): 

209 return self.__seamless__.get_list("apc.max") 

210 

211 def add_apc(self, currency, price): 

212 self.__seamless__.add_to_list_with_struct("apc.max", {"currency": currency, "price" : price}) 

213 self.__seamless__.set_with_struct("apc.has_apc", True) 

214 

215 def clear_apcs(self): 

216 self.__seamless__.delete("apc.max") 

217 

218 @property 

219 def apc_url(self): 

220 return self.__seamless__.get_single("apc.url") 

221 

222 @apc_url.setter 

223 def apc_url(self, url): 

224 self.__seamless__.set_with_struct("apc.url", url) 

225 

226 @property 

227 def has_apc(self): 

228 return self.__seamless__.get_single("apc.has_apc") 

229 

230 @has_apc.setter 

231 def has_apc(self, val): 

232 self.__seamless__.set_with_struct("apc.has_apc", val) 

233 if val is False: 

234 self.clear_apcs() 

235 

236 @property 

237 def article_license_display(self): 

238 return self.__seamless__.get_list("article.license_display") 

239 

240 @article_license_display.setter 

241 def article_license_display(self, val): 

242 self.__seamless__.set_with_struct("article.license_display", val) 

243 

244 # I've taken this out but left the commented code here to remind us. It used to be that you could 

245 # have multiple license displays, but now you can't. The data model still allows for it, but the 

246 # model should not, unless we reverse that decision at some point in the future 

247 # def add_article_license_display(self, val): 

248 # self.__seamless__.add_to_list_with_struct("article.license_display", val) 

249 

250 @property 

251 def article_license_display_example_url(self): 

252 return self.__seamless__.get_single("article.license_display_example_url") 

253 

254 @article_license_display_example_url.setter 

255 def article_license_display_example_url(self, url): 

256 self.__seamless__.set_with_struct("article.license_display_example_url", url) 

257 

258 @property 

259 def author_retains_copyright(self): 

260 return self.__seamless__.get_single("copyright.author_retains") 

261 

262 @author_retains_copyright.setter 

263 def author_retains_copyright(self, val): 

264 self.__seamless__.set_single("copyright.author_retains", val) 

265 

266 @property 

267 def copyright_url(self): 

268 return self.__seamless__.get_single("copyright.url") 

269 

270 @copyright_url.setter 

271 def copyright_url(self, url): 

272 self.__seamless__.set_with_struct("copyright.url", url) 

273 

274 @property 

275 def deposit_policy(self): 

276 return self.__seamless__.get_list("deposit_policy.service") 

277 

278 @deposit_policy.setter 

279 def deposit_policy(self, policies): 

280 self.__seamless__.set_with_struct("deposit_policy.service", policies) 

281 if len(policies) > 0: 

282 self.__seamless__.set_with_struct("deposit_policy.has_policy", True) 

283 

284 def add_deposit_policy(self, policy): 

285 self.__seamless__.add_to_list_with_struct("deposit_policy.service", policy) 

286 self.__seamless__.set_with_struct("deposit_policy.has_policy", True) 

287 

288 def remove_deposit_policy(self, policy): 

289 self.__seamless__.delete_from_list("deposit_policy.service", policy) 

290 if len(self.deposit_policy) == 0: 

291 self.__seamless__.set_with_struct("deposit_policy.has_policy", False) 

292 

293 @property 

294 def has_deposit_policy(self): 

295 return self.__seamless__.get_single("deposit_policy.has_policy") 

296 

297 @has_deposit_policy.setter 

298 def has_deposit_policy(self, val): 

299 self.__seamless__.set_with_struct("deposit_policy.has_policy", val) 

300 

301 @property 

302 def deposit_policy_url(self): 

303 return self.__seamless__.get_single("deposit_policy.url") 

304 

305 @deposit_policy_url.setter 

306 def deposit_policy_url(self, url): 

307 self.__seamless__.set_with_struct("deposit_policy.url", url) 

308 

309 def set_unregistered_journal_policy(self, url): 

310 self.deposit_policy_url = url 

311 self.has_deposit_policy = True 

312 

313 def set_editorial_review(self, process, review_url, board_url=None): 

314 self.__seamless__.set_with_struct("editorial.review_process", process) 

315 self.__seamless__.set_with_struct("editorial.review_url", review_url) 

316 if board_url is not None: 

317 self.__seamless__.set_with_struct("editorial.board_url", board_url) 

318 

319 def add_editorial_review_process(self, process): 

320 self.__seamless__.add_to_list_with_struct("editorial.review_process", process) 

321 

322 def remove_editorial_review_process(self, process): 

323 self.__seamless__.delete_from_list("editorial.review_process", process) 

324 

325 @property 

326 def editorial_review_process(self): 

327 return self.__seamless__.get_list("editorial.review_process") 

328 

329 @property 

330 def editorial_review_url(self): 

331 return self.__seamless__.get_single("editorial.review_url") 

332 

333 @editorial_review_url.setter 

334 def editorial_review_url(self, url): 

335 self.__seamless__.set_with_struct("editorial.review_url", url) 

336 

337 @property 

338 def editorial_board_url(self): 

339 return self.__seamless__.get_single("editorial.board_url") 

340 

341 @editorial_board_url.setter 

342 def editorial_board_url(self, url): 

343 self.__seamless__.set_with_struct("editorial.board_url", url) 

344 

345 @property 

346 def institution_name(self): 

347 return self.__seamless__.get_single("institution.name") 

348 

349 @institution_name.setter 

350 def institution_name(self, val): 

351 self.__seamless__.set_with_struct("institution.name", val) 

352 

353 @property 

354 def institution_country(self): 

355 return self.__seamless__.get_single("institution.country") 

356 

357 @institution_country.setter 

358 def institution_country(self, country): 

359 self.__seamless__.set_with_struct("institution.country", country) 

360 

361 @property 

362 def has_other_charges(self): 

363 return self.__seamless__.get_single("other_charges.has_other_charges") 

364 

365 @has_other_charges.setter 

366 def has_other_charges(self, val): 

367 self.__seamless__.set_with_struct("other_charges.has_other_charges", val) 

368 if val is False: 

369 del self.other_charges_url 

370 

371 @property 

372 def other_charges_url(self): 

373 return self.__seamless__.get_single("other_charges.url") 

374 

375 @other_charges_url.setter 

376 def other_charges_url(self, url): 

377 self.__seamless__.set_with_struct("other_charges.url", url) 

378 

379 @other_charges_url.deleter 

380 def other_charges_url(self): 

381 self.__seamless__.delete("other_charges.url") 

382 

383 @property 

384 def pid_scheme(self): 

385 return self.__seamless__.get_list("pid_scheme.scheme") 

386 

387 @pid_scheme.setter 

388 def pid_scheme(self, schemes): 

389 self.__seamless__.set_with_struct("pid_scheme.scheme", schemes) 

390 if len(schemes) > 0: 

391 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", True) 

392 else: 

393 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", False) 

394 

395 def add_pid_scheme(self, scheme): 

396 self.__seamless__.add_to_list_with_struct("pid_scheme.scheme", scheme) 

397 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", True) 

398 

399 @property 

400 def has_pid_scheme(self): 

401 return self.__seamless__.get_single("pid_scheme.has_pid_scheme") 

402 

403 @has_pid_scheme.setter 

404 def has_pid_scheme(self, val): 

405 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", val) 

406 

407 def set_plagiarism_detection(self, url, has_detection=True): 

408 self.__seamless__.set_with_struct("plagiarism.detection", has_detection) 

409 self.__seamless__.set_with_struct("plagiarism.url", url) 

410 

411 @property 

412 def plagiarism_detection(self): 

413 return self.__seamless__.get_single("plagiarism.detection") 

414 

415 @property 

416 def plagiarism_url(self): 

417 return self.__seamless__.get_single("plagiarism.url") 

418 

419 @plagiarism_url.setter 

420 def plagiarism_url(self, url): 

421 self.__seamless__.set_with_struct("plagiarism.url", url) 

422 

423 @property 

424 def preservation(self): 

425 return self.__seamless__.get_single("preservation") 

426 

427 @property 

428 def preservation_services(self): 

429 pres = self.preservation 

430 if pres is None: 

431 return [] 

432 if "service" in pres: 

433 return pres["service"] 

434 else: 

435 return [] 

436 

437 @property 

438 def preservation_library(self): 

439 pres = self.preservation 

440 if pres is None: 

441 return None 

442 if "national_library" in pres: 

443 return pres["national_library"] 

444 return None 

445 

446 @property 

447 def preservation_summary(self): 

448 summary = [] 

449 summary += self.preservation_services 

450 libs = self.preservation_library 

451 if libs is not None: 

452 for lib in libs: 

453 summary.append(["A national library", lib]) 

454 return summary 

455 

456 def add_preservation_library(self, library): 

457 self.__seamless__.add_to_list_with_struct("preservation.national_library", library) 

458 self.has_preservation = True 

459 

460 def set_preservation(self, services, policy_url): 

461 obj = {} 

462 known = [] 

463 for p in services: 

464 if isinstance(p, list): 

465 k, v = p 

466 if k.lower() == "a national library": 

467 if "national_library" in obj: 

468 obj["national_library"].append(v) 

469 else: 

470 obj["national_library"] = [v] 

471 else: 

472 known.append(p) 

473 if len(known) > 0: 

474 obj["service"] = known 

475 if policy_url is not None: 

476 obj["url"] = policy_url 

477 

478 self.__seamless__.set_with_struct("preservation", obj) 

479 

480 if self.preservation_services is not None or self.preservation_library is not None: 

481 self.has_preservation = True 

482 

483 def add_preservation(self, services=None, libraries=None): 

484 if services is not None: 

485 if not isinstance(services, list): 

486 services = [services] 

487 for s in services: 

488 self.__seamless__.add_to_list_with_struct("preservation.service", s) 

489 if libraries is not None: 

490 if not isinstance(libraries, list): 

491 libraries = [libraries] 

492 for l in libraries: 

493 self.__seamless__.add_to_list_with_struct("preservation.national_library", l) 

494 if self.preservation_services is not None or self.preservation_library is not None: 

495 self.has_preservation = True 

496 

497 @property 

498 def has_preservation(self): 

499 return self.__seamless__.get_single("preservation.has_preservation") 

500 

501 @has_preservation.setter 

502 def has_preservation(self, has_preservation): 

503 self.__seamless__.set_single("preservation.has_preservation", has_preservation) 

504 

505 @property 

506 def preservation_url(self): 

507 return self.__seamless__.get_single("preservation.url") 

508 

509 @preservation_url.setter 

510 def preservation_url(self, url): 

511 self.__seamless__.set_with_struct("preservation.url", url) 

512 

513 @property 

514 def publisher_name(self): 

515 return self.__seamless__.get_single("publisher.name") 

516 

517 @publisher_name.setter 

518 def publisher_name(self, val): 

519 self.__seamless__.set_with_struct("publisher.name", val) 

520 

521 @property 

522 def publisher_country(self): 

523 return self.__seamless__.get_single("publisher.country") 

524 

525 @publisher_country.setter 

526 def publisher_country(self, country): 

527 self.__seamless__.set_with_struct("publisher.country", country) 

528 

529 @property 

530 def review_process(self): 

531 return self.__seamless__.get_list("editorial.review_proccess") 

532 

533 @review_process.setter 

534 def review_process(self, review_process): 

535 self.__seamless__.add_to_list_with_struct("editorial.review_process", review_process) 

536 

537 @property 

538 def review_process_url(self): 

539 return self.__seamless__.editorial.review_url 

540 

541 @review_process_url.setter 

542 def review_process_url(self, url): 

543 self.__seamless__.set_with_struct("editorial.review_url", url) 

544 

545 @property 

546 def oa_statement_url(self): 

547 return self.__seamless__.get_single("ref.oa_statement") 

548 

549 @oa_statement_url.setter 

550 def oa_statement_url(self, url): 

551 self.__seamless__.set_with_struct("ref.oa_statement", url) 

552 

553 @property 

554 def journal_url(self): 

555 return self.__seamless__.get_single("ref.journal") 

556 

557 @journal_url.setter 

558 def journal_url(self, url): 

559 self.__seamless__.set_with_struct("ref.journal", url) 

560 

561 @property 

562 def aims_scope_url(self): 

563 return self.__seamless__.get_single("ref.aims_scope") 

564 

565 @aims_scope_url.setter 

566 def aims_scope_url(self, url): 

567 self.__seamless__.set_with_struct("ref.aims_scope", url) 

568 

569 @property 

570 def author_instructions_url(self): 

571 return self.__seamless__.get_single("ref.author_instructions") 

572 

573 @author_instructions_url.setter 

574 def author_instructions_url(self, url): 

575 self.__seamless__.set_with_struct("ref.author_instructions", url) 

576 

577 @property 

578 def license_terms_url(self): 

579 return self.__seamless__.get_single("ref.license_terms") 

580 

581 @license_terms_url.setter 

582 def license_terms_url(self, url): 

583 self.__seamless__.set_with_struct("ref.license_terms", url) 

584 

585 @property 

586 def has_waiver(self): 

587 return self.__seamless__.get_single("waiver.has_waiver") 

588 

589 @has_waiver.setter 

590 def has_waiver(self, val): 

591 self.__seamless__.set_with_struct("waiver.has_waiver", val) 

592 if val is False: 

593 del self.waiver_url 

594 

595 @property 

596 def waiver_url(self): 

597 return self.__seamless__.get_single("waiver.url") 

598 

599 @waiver_url.setter 

600 def waiver_url(self, url): 

601 self.__seamless__.set_with_struct("waiver.url", url) 

602 

603 @waiver_url.deleter 

604 def waiver_url(self): 

605 self.__seamless__.delete("waiver.url") 

606 

607 @property 

608 def labels(self): 

609 return self.__seamless__.get_list("labels") 

610 

611 @labels.setter 

612 def labels(self, val): 

613 self.__seamless__.set_with_struct("labels", val) 

614 

615 def add_label(self, val): 

616 self.__seamless__.add_to_list_with_struct("labels", val) 

617 

618 def clear_labels(self): 

619 self.__seamless__.delete("labels") 

620 

621 ##################################################### 

622 ## External utility functions 

623 

624 def issns(self) -> list: 

625 issns = [] 

626 if self.pissn: 

627 issns.append(self.pissn) 

628 if self.eissn: 

629 issns.append(self.eissn) 

630 return issns 

631 

632 def issns_as_text(self) -> str: 

633 return ", ".join(issn for issn in self.issns()) 

634 

635 def publisher_country_name(self): 

636 if self.publisher_country is not None: 

637 return datasets.get_country_name(self.publisher_country) 

638 return None 

639 

640 def institution_country_name(self): 

641 if self.institution_country is not None: 

642 return datasets.get_country_name(self.institution_country) 

643 return None 

644 

645 def language_name(self): 

646 # copy the languages and convert them to their english forms 

647 langs = [datasets.name_for_lang(l) for l in self.language] 

648 langs = [to_utf8_unicode(l) for l in langs] 

649 return list(set(langs)) 

650 

651 def term_path(self, term): 

652 from portality.lcc import lcc 

653 return lcc.term_path(term) 

654 

655 def lcc_paths(self): 

656 classification_paths = [] 

657 

658 # calculate the classification paths 

659 from portality.lcc import lcc # inline import since this hits the database 

660 for subs in self.subjects(): 

661 scheme = subs.get("scheme") 

662 term = subs.get("term") 

663 if scheme == "LCC": 

664 p = lcc.pathify(term) 

665 if p is not None: 

666 classification_paths.append(p) 

667 

668 # normalise the classification paths, so we only store the longest ones 

669 classification_paths = lcc.longest(classification_paths) 

670 

671 return classification_paths 

672 

673 def lcc_codes_full_list(self): 

674 full_list = set() 

675 

676 from portality.lcc import lcc # inline import since this hits the database 

677 for subs in self.subjects(): 

678 scheme = subs.get("scheme") 

679 if scheme != "LCC": 

680 continue 

681 code = subs.get("code") 

682 expanded = lcc.expand_codes(code) 

683 full_list.update(expanded) 

684 

685 return ["LCC:" + x for x in full_list if x is not None] 

686 

687 def lcc_paths_and_codes(self): 

688 paths_and_codes = {} 

689 

690 # calculate the classification paths 

691 from portality.lcc import lcc # inline import since this hits the database 

692 for subs in self.subjects(): 

693 scheme = subs.get("scheme") 

694 if scheme != "LCC": 

695 continue 

696 term = subs.get("term") 

697 code = subs.get("code") 

698 p = lcc.pathify(term) 

699 if p is not None: 

700 paths_and_codes[p] = "LCC:" + code 

701 

702 return [(x, paths_and_codes[x]) for x in lcc.longest(list(paths_and_codes.keys()))] 

703 

704 # to help with ToC - we prefer to refer to a journal by E-ISSN, or 

705 # if not, then P-ISSN 

706 def get_preferred_issn(self): 

707 if self.eissn: 

708 return self.eissn 

709 if self.pissn: 

710 return self.pissn 

711 

712 ##################################################### 

713 ## Internal utility functions 

714 

715 def _normalise_issn(self, issn): 

716 if issn is None: 

717 return issn 

718 issn = issn.upper() 

719 if len(issn) > 8: return issn 

720 if len(issn) == 8: 

721 if "-" in issn: return "0" + issn 

722 else: return issn[:4] + "-" + issn[4:] 

723 if len(issn) < 8: 

724 if "-" in issn: return ("0" * (9 - len(issn))) + issn 

725 else: 

726 issn = ("0" * (8 - len(issn))) + issn 

727 return issn[:4] + "-" + issn[4:] 

728 

729 ##################################################### 

730 ## Back Compat methods for v1 of the model 

731 ## ALL DEPRECATED 

732 

733 @property 

734 def publication_time(self): 

735 return self.publication_time_weeks 

736 

737 @publication_time.setter 

738 def publication_time(self, weeks): 

739 self.publication_time_weeks = weeks 

740 

741 @property 

742 def publisher(self): 

743 return self.publisher_name 

744 

745 @publisher.setter 

746 def publisher(self, val): 

747 self.publisher_name = val 

748 

749 @property 

750 def institution(self): 

751 return self.institution_name 

752 

753 @institution.setter 

754 def institution(self, val): 

755 self.institution_name = val 

756 

757 def set_keywords(self, keywords): 

758 self.keywords = keywords 

759 

760 def set_language(self, language): 

761 self.language = language 

762 

763 @property 

764 def persistent_identifier_scheme(self): 

765 return self.pid_scheme 

766 

767 @persistent_identifier_scheme.setter 

768 def persistent_identifier_scheme(self, schemes): 

769 self.pid_scheme = schemes 

770 

771 def add_persistent_identifier_scheme(self, scheme): 

772 self.add_pid_scheme(scheme) 

773 

774 def subjects(self): 

775 return self.subject 

776 

777 def set_subjects(self, subjects): 

778 self.subject = subjects 

779 

780 def remove_subjects(self): 

781 del self.subject 

782 

783 def set_archiving_policy(self, policies, policy_url): 

784 self.set_preservation(policies, policy_url) 

785 

786 def add_archiving_policy(self, policy_name): 

787 self.add_preservation(policy_name) 

788 

789 @property 

790 def flattened_archiving_policies(self): 

791 summary = self.preservation_summary 

792 if summary is None: 

793 return [] 

794 return [": ".join(p) if isinstance(p, list) else p for p in self.preservation_summary] 

795 

796 # vocab of known identifier types 

797 P_ISSN = "pissn" 

798 E_ISSN = "eissn" 

799 DOI = "doi" 

800 

801 IDENTIFIER_MAP = { 

802 P_ISSN : "pissn", 

803 E_ISSN : "eissn", 

804 DOI : "doi" 

805 } 

806 

807 def add_identifier(self, idtype, value): 

808 field = self.IDENTIFIER_MAP.get(idtype) 

809 if field is not None: 

810 setattr(self, field, value) 

811 return 

812 raise RuntimeError("This object does not accept unrecognised identifier types") 

813 

814 def get_identifiers(self, idtype=None): 

815 if idtype is None: 

816 idents = [] 

817 if self.eissn: 

818 idents.append({"type" : self.E_ISSN, "id" : self.eissn}) 

819 if self.pissn: 

820 idents.append({"type" : self.P_ISSN, "id" : self.pissn}) 

821 return idents 

822 field = self.IDENTIFIER_MAP.get(idtype) 

823 if field is None: 

824 raise RuntimeError("No identifier of type {x} known".format(x=idtype)) 

825 

826 ident = getattr(self, field) 

827 if ident is not None: 

828 return [getattr(self, field)] 

829 return [] 

830 

831 def get_one_identifier(self, idtype=None): 

832 if idtype is None: 

833 raise RuntimeError("This object cannot return a generic identifier") 

834 results = self.get_identifiers(idtype=idtype) 

835 if len(results) > 0: 

836 return results[0] 

837 else: 

838 return None 

839 

840 def _set_attr_with_no_check(self, name, value): 

841 self.__setattr__(name, value, allow_coerce_failure=True) 

842 

843 # allowable values for the url types 

844 HOMEPAGE = "homepage" 

845 WAIVER_POLICY = "waiver_policy" 

846 EDITORIAL_BOARD = "editorial_board" 

847 AIMS_SCOPE = "aims_scope" 

848 AUTHOR_INSTRUCTIONS = "author_instructions" 

849 OA_STATEMENT = "oa_statement" 

850 #FULLTEXT = "fulltext" 

851 

852 LINK_MAP = { 

853 HOMEPAGE: "journal_url", 

854 WAIVER_POLICY: "waiver_url", 

855 EDITORIAL_BOARD: "editorial_board_url", 

856 AIMS_SCOPE: "aims_scope_url", 

857 AUTHOR_INSTRUCTIONS: "author_instructions_url", 

858 OA_STATEMENT: "oa_statement_url" 

859 } 

860 

861 def add_url(self, url, urltype=None, content_type=None): 

862 if url is None: 

863 # do not add empty URL-s 

864 return 

865 

866 field = self.LINK_MAP.get(urltype) 

867 if field is not None: 

868 setattr(self, field, url) 

869 return 

870 raise RuntimeError("This object does not accept unrecognised url types") 

871 

872 def get_urls(self, urltype=None, unpack_urlobj=True): 

873 if urltype is None: 

874 raise RuntimeError("This object cannot return lists of urls") 

875 

876 field = self.LINK_MAP.get(urltype) 

877 if field is None: 

878 raise RuntimeError("No url of type {x} known".format(x=urltype)) 

879 

880 url = getattr(self, field) 

881 if unpack_urlobj: 

882 return [url] 

883 else: 

884 return [{"type" : urltype, "url" : url}] 

885 

886 def get_single_url(self, urltype, unpack_urlobj=True): 

887 urls = self.get_urls(urltype=urltype, unpack_urlobj=unpack_urlobj) 

888 if len(urls) > 0: 

889 return urls[0] 

890 return None 

891 

892 @property 

893 def first_pissn(self): 

894 return self.pissn 

895 

896 @property 

897 def first_eissn(self): 

898 return self.eissn 

899 

900 @property 

901 def country(self): 

902 return self.publisher_country 

903 

904 @country.setter 

905 def country(self, val): 

906 self.publisher_country = val 

907 

908 @property 

909 def open_access(self): 

910 return self.boai 

911 

912 def set_open_access(self, open_access): 

913 self.boai = open_access 

914 

915 def country_name(self): 

916 return self.publisher_country_name() 

917 

918 ##################################################### 

919 ## Incompatible functions from v1 

920 

921 def set_license(self, license_type, url=None, version=None, open_access=None, 

922 by=None, sa=None, nc=None, nd=None, 

923 display=None, display_example_url=None): 

924 """ 

925 # FIXME: why is there not a "remove license" function 

926 if not license_title and not license_type: # something wants to delete the license 

927 self._delete("license") 

928 return 

929 

930 lobj = {"title": license_title, "type": license_type} 

931 if url is not None: 

932 lobj["url"] = url 

933 if version is not None: 

934 lobj["version"] = version 

935 if open_access is not None: 

936 lobj["open_access"] = open_access 

937 if by is not None: 

938 lobj["BY"] = by 

939 if sa is not None: 

940 lobj["SA"] = sa 

941 if nc is not None: 

942 lobj["NC"] = nc 

943 if nd is not None: 

944 lobj["ND"] = nd 

945 if embedded is not None: 

946 lobj["embedded"] = embedded 

947 if embedded_example_url is not None: 

948 lobj["embedded_example_url"] = embedded_example_url 

949 

950 self._set_with_struct("license", [lobj]) 

951 """ 

952 raise RuntimeError("set_license is not back compat") 

953 

954 def get_license(self): 

955 """ 

956 ll = self._get_list("license") 

957 if len(ll) > 0: 

958 return ll[0] 

959 return None 

960 """ 

961 raise RuntimeError("get_license is not back compat") 

962 

963 def get_license_type(self): 

964 """ 

965 lobj = self.get_license() 

966 if lobj is not None: 

967 return lobj['type'] 

968 return None 

969 """ 

970 raise RuntimeError("get_license_type is not back compat") 

971 

972 @property 

973 def editorial_review(self): 

974 """ 

975 return self._get_single("editorial_review", default={}) 

976 """ 

977 raise RuntimeError("editorial_review is not back compat") 

978 

979 @property 

980 def archiving_policy(self): 

981 """ 

982 ap = self._get_single("archiving_policy", default={}) 

983 ret = {"policy" : []} 

984 if "url" in ap: 

985 ret["url"] = ap["url"] 

986 if "known" in ap: 

987 ret["policy"] += ap["known"] 

988 if "nat_lib" in ap: 

989 ret["policy"].append(["A national library", ap["nat_lib"]]) 

990 if "other" in ap: 

991 ret["policy"].append(["Other", ap["other"]]) 

992 return ret 

993 """ 

994 raise RuntimeError("archiving_policy is not back compat") 

995 

996 def remove_identifiers(self, idtype=None, id=None): 

997 raise RuntimeError("remove_identifiers is not back compat") 

998 

999 def remove_urls(self, urltype=None, url=None): 

1000 raise RuntimeError("remove_urls is not back compat") 

1001