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
« 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
6class JournalLikeBibJSON(SeamlessMixin):
8 __SEAMLESS_STRUCT__ = shared_structs.JOURNAL_BIBJSON.get("structs", {}).get("bibjson")
10 __SEAMLESS_COERCE__ = coerce.COERCE_MAP
12 # constructor
13 def __init__(self, bibjson=None, **kwargs):
14 super(JournalLikeBibJSON, self).__init__(raw=bibjson, **kwargs)
16 @property
17 def data(self):
18 return self.__seamless__.data
20 ####################################################
21 # Current getters and setters
23 @property
24 def alternative_title(self):
25 return self.__seamless__.get_single("alternative_title")
27 @alternative_title.setter
28 def alternative_title(self, val):
29 self.__seamless__.set_with_struct("alternative_title", val)
31 @property
32 def boai(self):
33 return self.__seamless__.get_single("boai")
35 @boai.setter
36 def boai(self, val):
37 self.__seamless__.set_with_struct("boai", val)
39 @property
40 def discontinued_date(self):
41 return self.__seamless__.get_single("discontinued_date")
43 @discontinued_date.setter
44 def discontinued_date(self, val):
45 self.__seamless__.set_with_struct("discontinued_date", val)
47 @discontinued_date.deleter
48 def discontinued_date(self):
49 self.__seamless__.delete("discontinued_date")
51 @property
52 def discontinued_datestamp(self):
53 return self.__seamless__.get_single("discontinued_date", coerce=coerce.to_datestamp())
55 @property
56 def eissn(self):
57 return self.__seamless__.get_single("eissn")
59 @eissn.setter
60 def eissn(self, val):
61 self.__seamless__.set_with_struct("eissn", val)
63 @eissn.deleter
64 def eissn(self):
65 self.__seamless__.delete("eissn")
67 @property
68 def pissn(self):
69 return self.__seamless__.get_single("pissn")
71 @pissn.setter
72 def pissn(self, val):
73 self.__seamless__.set_with_struct("pissn", val)
75 @pissn.deleter
76 def pissn(self):
77 self.__seamless__.delete("pissn")
79 @property
80 def oa_start(self):
81 return self.__seamless__.get_single("oa_start")
83 @oa_start.setter
84 def oa_start(self, val):
85 self.__seamless__.set_with_struct("oa_start", val)
87 @oa_start.deleter
88 def oa_start(self):
89 self.__seamless__.delete("oa_start")
91 @property
92 def publication_time_weeks(self):
93 return self.__seamless__.get_single("publication_time_weeks")
95 @publication_time_weeks.setter
96 def publication_time_weeks(self, weeks):
97 self.__seamless__.set_with_struct("publication_time_weeks", weeks)
99 @property
100 def title(self):
101 return self.__seamless__.get_single("title")
103 @title.setter
104 def title(self, val):
105 self.__seamless__.set_with_struct("title", val)
107 @property
108 def is_replaced_by(self):
109 return self.__seamless__.get_list("is_replaced_by")
111 @is_replaced_by.setter
112 def is_replaced_by(self, val):
113 self.__seamless__.set_with_struct("is_replaced_by", val)
115 @is_replaced_by.deleter
116 def is_replaced_by(self):
117 self.__seamless__.delete("is_replaced_by")
119 def add_is_replaced_by(self, val):
120 self.__seamless__.add_to_list_with_struct("is_replaced_by", val)
122 @property
123 def keywords(self):
124 return self.__seamless__.get_list("keywords")
126 def add_keyword(self, keyword):
127 if keyword is not None:
128 self.__seamless__.add_to_list_with_struct("keywords", keyword.lower())
130 @keywords.setter
131 def keywords(self, keywords):
132 self.__seamless__.set_with_struct("keywords", keywords)
134 @property
135 def language(self):
136 return self.__seamless__.get_list("language")
138 @language.setter
139 def language(self, language):
140 self.__seamless__.set_with_struct("language", language)
142 def add_language(self, language):
143 self.__seamless__.add_to_list_with_struct("language", language)
145 @property
146 def licenses(self):
147 return self.__seamless__.get_list("license")
149 @property
150 def licences(self):
151 return self.licenses
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)
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
169 self.__seamless__.add_to_list_with_struct("license", lobj)
171 def remove_licenses(self):
172 self.__seamless__.delete("license")
174 @property
175 def replaces(self):
176 return self.__seamless__.get_list("replaces")
178 @replaces.setter
179 def replaces(self, val):
180 self.__seamless__.set_with_struct("replaces", val)
182 @replaces.deleter
183 def replaces(self):
184 self.__seamless__.delete("replaces")
186 def add_replaces(self, val):
187 self.__seamless__.add_to_list_with_struct("replaces", val)
189 @property
190 def subject(self):
191 return self.__seamless__.get_list("subject")
193 @subject.setter
194 def subject(self, subjects):
195 self.__seamless__.set_with_struct("subject", subjects)
197 @subject.deleter
198 def subject(self):
199 self.__seamless__.delete("subject")
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)
207 @property
208 def apc(self):
209 return self.__seamless__.get_list("apc.max")
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)
215 def clear_apcs(self):
216 self.__seamless__.delete("apc.max")
218 @property
219 def apc_url(self):
220 return self.__seamless__.get_single("apc.url")
222 @apc_url.setter
223 def apc_url(self, url):
224 self.__seamless__.set_with_struct("apc.url", url)
226 @property
227 def has_apc(self):
228 return self.__seamless__.get_single("apc.has_apc")
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()
236 @property
237 def article_license_display(self):
238 return self.__seamless__.get_list("article.license_display")
240 @article_license_display.setter
241 def article_license_display(self, val):
242 self.__seamless__.set_with_struct("article.license_display", val)
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)
250 @property
251 def article_license_display_example_url(self):
252 return self.__seamless__.get_single("article.license_display_example_url")
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)
258 @property
259 def author_retains_copyright(self):
260 return self.__seamless__.get_single("copyright.author_retains")
262 @author_retains_copyright.setter
263 def author_retains_copyright(self, val):
264 self.__seamless__.set_single("copyright.author_retains", val)
266 @property
267 def copyright_url(self):
268 return self.__seamless__.get_single("copyright.url")
270 @copyright_url.setter
271 def copyright_url(self, url):
272 self.__seamless__.set_with_struct("copyright.url", url)
274 @property
275 def deposit_policy(self):
276 return self.__seamless__.get_list("deposit_policy.service")
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)
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)
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)
293 @property
294 def has_deposit_policy(self):
295 return self.__seamless__.get_single("deposit_policy.has_policy")
297 @has_deposit_policy.setter
298 def has_deposit_policy(self, val):
299 self.__seamless__.set_with_struct("deposit_policy.has_policy", val)
301 @property
302 def deposit_policy_url(self):
303 return self.__seamless__.get_single("deposit_policy.url")
305 @deposit_policy_url.setter
306 def deposit_policy_url(self, url):
307 self.__seamless__.set_with_struct("deposit_policy.url", url)
309 def set_unregistered_journal_policy(self, url):
310 self.deposit_policy_url = url
311 self.has_deposit_policy = True
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)
319 def add_editorial_review_process(self, process):
320 self.__seamless__.add_to_list_with_struct("editorial.review_process", process)
322 def remove_editorial_review_process(self, process):
323 self.__seamless__.delete_from_list("editorial.review_process", process)
325 @property
326 def editorial_review_process(self):
327 return self.__seamless__.get_list("editorial.review_process")
329 @property
330 def editorial_review_url(self):
331 return self.__seamless__.get_single("editorial.review_url")
333 @editorial_review_url.setter
334 def editorial_review_url(self, url):
335 self.__seamless__.set_with_struct("editorial.review_url", url)
337 @property
338 def editorial_board_url(self):
339 return self.__seamless__.get_single("editorial.board_url")
341 @editorial_board_url.setter
342 def editorial_board_url(self, url):
343 self.__seamless__.set_with_struct("editorial.board_url", url)
345 @property
346 def institution_name(self):
347 return self.__seamless__.get_single("institution.name")
349 @institution_name.setter
350 def institution_name(self, val):
351 self.__seamless__.set_with_struct("institution.name", val)
353 @property
354 def institution_country(self):
355 return self.__seamless__.get_single("institution.country")
357 @institution_country.setter
358 def institution_country(self, country):
359 self.__seamless__.set_with_struct("institution.country", country)
361 @property
362 def has_other_charges(self):
363 return self.__seamless__.get_single("other_charges.has_other_charges")
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
371 @property
372 def other_charges_url(self):
373 return self.__seamless__.get_single("other_charges.url")
375 @other_charges_url.setter
376 def other_charges_url(self, url):
377 self.__seamless__.set_with_struct("other_charges.url", url)
379 @other_charges_url.deleter
380 def other_charges_url(self):
381 self.__seamless__.delete("other_charges.url")
383 @property
384 def pid_scheme(self):
385 return self.__seamless__.get_list("pid_scheme.scheme")
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)
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)
399 @property
400 def has_pid_scheme(self):
401 return self.__seamless__.get_single("pid_scheme.has_pid_scheme")
403 @has_pid_scheme.setter
404 def has_pid_scheme(self, val):
405 self.__seamless__.set_with_struct("pid_scheme.has_pid_scheme", val)
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)
411 @property
412 def plagiarism_detection(self):
413 return self.__seamless__.get_single("plagiarism.detection")
415 @property
416 def plagiarism_url(self):
417 return self.__seamless__.get_single("plagiarism.url")
419 @plagiarism_url.setter
420 def plagiarism_url(self, url):
421 self.__seamless__.set_with_struct("plagiarism.url", url)
423 @property
424 def preservation(self):
425 return self.__seamless__.get_single("preservation")
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 []
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
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
456 def add_preservation_library(self, library):
457 self.__seamless__.add_to_list_with_struct("preservation.national_library", library)
458 self.has_preservation = True
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
478 self.__seamless__.set_with_struct("preservation", obj)
480 if self.preservation_services is not None or self.preservation_library is not None:
481 self.has_preservation = True
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
497 @property
498 def has_preservation(self):
499 return self.__seamless__.get_single("preservation.has_preservation")
501 @has_preservation.setter
502 def has_preservation(self, has_preservation):
503 self.__seamless__.set_single("preservation.has_preservation", has_preservation)
505 @property
506 def preservation_url(self):
507 return self.__seamless__.get_single("preservation.url")
509 @preservation_url.setter
510 def preservation_url(self, url):
511 self.__seamless__.set_with_struct("preservation.url", url)
513 @property
514 def publisher_name(self):
515 return self.__seamless__.get_single("publisher.name")
517 @publisher_name.setter
518 def publisher_name(self, val):
519 self.__seamless__.set_with_struct("publisher.name", val)
521 @property
522 def publisher_country(self):
523 return self.__seamless__.get_single("publisher.country")
525 @publisher_country.setter
526 def publisher_country(self, country):
527 self.__seamless__.set_with_struct("publisher.country", country)
529 @property
530 def review_process(self):
531 return self.__seamless__.get_list("editorial.review_proccess")
533 @review_process.setter
534 def review_process(self, review_process):
535 self.__seamless__.add_to_list_with_struct("editorial.review_process", review_process)
537 @property
538 def review_process_url(self):
539 return self.__seamless__.editorial.review_url
541 @review_process_url.setter
542 def review_process_url(self, url):
543 self.__seamless__.set_with_struct("editorial.review_url", url)
545 @property
546 def oa_statement_url(self):
547 return self.__seamless__.get_single("ref.oa_statement")
549 @oa_statement_url.setter
550 def oa_statement_url(self, url):
551 self.__seamless__.set_with_struct("ref.oa_statement", url)
553 @property
554 def journal_url(self):
555 return self.__seamless__.get_single("ref.journal")
557 @journal_url.setter
558 def journal_url(self, url):
559 self.__seamless__.set_with_struct("ref.journal", url)
561 @property
562 def aims_scope_url(self):
563 return self.__seamless__.get_single("ref.aims_scope")
565 @aims_scope_url.setter
566 def aims_scope_url(self, url):
567 self.__seamless__.set_with_struct("ref.aims_scope", url)
569 @property
570 def author_instructions_url(self):
571 return self.__seamless__.get_single("ref.author_instructions")
573 @author_instructions_url.setter
574 def author_instructions_url(self, url):
575 self.__seamless__.set_with_struct("ref.author_instructions", url)
577 @property
578 def license_terms_url(self):
579 return self.__seamless__.get_single("ref.license_terms")
581 @license_terms_url.setter
582 def license_terms_url(self, url):
583 self.__seamless__.set_with_struct("ref.license_terms", url)
585 @property
586 def has_waiver(self):
587 return self.__seamless__.get_single("waiver.has_waiver")
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
595 @property
596 def waiver_url(self):
597 return self.__seamless__.get_single("waiver.url")
599 @waiver_url.setter
600 def waiver_url(self, url):
601 self.__seamless__.set_with_struct("waiver.url", url)
603 @waiver_url.deleter
604 def waiver_url(self):
605 self.__seamless__.delete("waiver.url")
607 @property
608 def labels(self):
609 return self.__seamless__.get_list("labels")
611 @labels.setter
612 def labels(self, val):
613 self.__seamless__.set_with_struct("labels", val)
615 def add_label(self, val):
616 self.__seamless__.add_to_list_with_struct("labels", val)
618 def clear_labels(self):
619 self.__seamless__.delete("labels")
621 #####################################################
622 ## External utility functions
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
632 def issns_as_text(self) -> str:
633 return ", ".join(issn for issn in self.issns())
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
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
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))
651 def term_path(self, term):
652 from portality.lcc import lcc
653 return lcc.term_path(term)
655 def lcc_paths(self):
656 classification_paths = []
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)
668 # normalise the classification paths, so we only store the longest ones
669 classification_paths = lcc.longest(classification_paths)
671 return classification_paths
673 def lcc_codes_full_list(self):
674 full_list = set()
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)
685 return ["LCC:" + x for x in full_list if x is not None]
687 def lcc_paths_and_codes(self):
688 paths_and_codes = {}
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
702 return [(x, paths_and_codes[x]) for x in lcc.longest(list(paths_and_codes.keys()))]
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
712 #####################################################
713 ## Internal utility functions
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:]
729 #####################################################
730 ## Back Compat methods for v1 of the model
731 ## ALL DEPRECATED
733 @property
734 def publication_time(self):
735 return self.publication_time_weeks
737 @publication_time.setter
738 def publication_time(self, weeks):
739 self.publication_time_weeks = weeks
741 @property
742 def publisher(self):
743 return self.publisher_name
745 @publisher.setter
746 def publisher(self, val):
747 self.publisher_name = val
749 @property
750 def institution(self):
751 return self.institution_name
753 @institution.setter
754 def institution(self, val):
755 self.institution_name = val
757 def set_keywords(self, keywords):
758 self.keywords = keywords
760 def set_language(self, language):
761 self.language = language
763 @property
764 def persistent_identifier_scheme(self):
765 return self.pid_scheme
767 @persistent_identifier_scheme.setter
768 def persistent_identifier_scheme(self, schemes):
769 self.pid_scheme = schemes
771 def add_persistent_identifier_scheme(self, scheme):
772 self.add_pid_scheme(scheme)
774 def subjects(self):
775 return self.subject
777 def set_subjects(self, subjects):
778 self.subject = subjects
780 def remove_subjects(self):
781 del self.subject
783 def set_archiving_policy(self, policies, policy_url):
784 self.set_preservation(policies, policy_url)
786 def add_archiving_policy(self, policy_name):
787 self.add_preservation(policy_name)
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]
796 # vocab of known identifier types
797 P_ISSN = "pissn"
798 E_ISSN = "eissn"
799 DOI = "doi"
801 IDENTIFIER_MAP = {
802 P_ISSN : "pissn",
803 E_ISSN : "eissn",
804 DOI : "doi"
805 }
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")
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))
826 ident = getattr(self, field)
827 if ident is not None:
828 return [getattr(self, field)]
829 return []
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
840 def _set_attr_with_no_check(self, name, value):
841 self.__setattr__(name, value, allow_coerce_failure=True)
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"
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 }
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
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")
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")
876 field = self.LINK_MAP.get(urltype)
877 if field is None:
878 raise RuntimeError("No url of type {x} known".format(x=urltype))
880 url = getattr(self, field)
881 if unpack_urlobj:
882 return [url]
883 else:
884 return [{"type" : urltype, "url" : url}]
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
892 @property
893 def first_pissn(self):
894 return self.pissn
896 @property
897 def first_eissn(self):
898 return self.eissn
900 @property
901 def country(self):
902 return self.publisher_country
904 @country.setter
905 def country(self, val):
906 self.publisher_country = val
908 @property
909 def open_access(self):
910 return self.boai
912 def set_open_access(self, open_access):
913 self.boai = open_access
915 def country_name(self):
916 return self.publisher_country_name()
918 #####################################################
919 ## Incompatible functions from v1
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
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
950 self._set_with_struct("license", [lobj])
951 """
952 raise RuntimeError("set_license is not back compat")
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")
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")
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")
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")
996 def remove_identifiers(self, idtype=None, id=None):
997 raise RuntimeError("remove_identifiers is not back compat")
999 def remove_urls(self, urltype=None, url=None):
1000 raise RuntimeError("remove_urls is not back compat")