"""Handles citation information for Taurex."""importtypingastfromfunctoolsimportlru_cachefromurllib.errorimportHTTPError,URLErrorfromtaurex.log.loggerimportsetup_log_log=setup_log(__name__)try:frompybtex.databaseimportEntryhas_pybtex=TrueexceptImportError:_log.warning("Pybtex not installed. Citation functionality disabled")has_pybtex=FalseEntry=None
[docs]defcleanup_string(string:str)->str:"""Cleans up a string for bibtex."""returnstring.replace("{","").replace("}","").replace("\\","")
[docs]defrecurse_bibtex(obj:"Citable",entries:t.Optional[t.List[str]]=None)->t.List[str]:"""Recursively search for bibtex entries in base classes."""entries=entriesor[]forbinobj.__class__.__bases__:ifissubclass(b,Citable):entries.extend(b.BIBTEX_ENTRIES)recurse_bibtex(b,entries)returnentries
[docs]defstringify_people(authors:t.List[str])->str:"""Converts authors to a string."""return", ".join([cleanup_string(str(p))forpinauthors])
[docs]defto_bibtex(citations:t.List[str])->str:"""Converts citations to bibtex."""importuuidtry:frompybtex.databaseimportBibliographyDataexceptImportError:returnstr(citations)entries={str(uuid.uuid4())[:8]:bforbincitations}bib_data=BibliographyData(entries=entries)returnbib_data.to_string("bibtex")
[docs]defconstruct_nice_printable_string(entry:str,indent:int=0)->str:"""Constructs a nice printable string for each entry."""mystring=""indent="".join(["\t"]*indent)form=f"{indent}%s\n"ifisinstance(entry,str)ornothas_pybtex:returnf"Found non bibtex citation or pybtex not installed: {entry}\n"if"title"inentry.fields:mystring+=form%cleanup_string(entry.fields["title"])people=entry.personsif"author"inpeople:mystring+=form%stringify_people(people["author"])mystring+=form%handle_publication(entry.fields)returnmystring
[docs]classCitable:"""Defines a class that contains citation information."""BIBTEX_ENTRIES=[]"""List of bibtex entries."""
[docs]defcitations(self)->t.List[str]:"""Returns a list of citations."""entries=self.BIBTEX_ENTRIES[:]entries=recurse_bibtex(self,entries)ifnothas_pybtex:returnunique_citations_only(entries)all_citations=[Entry.from_string(b,"bibtex")forbinentries]returnunique_citations_only(all_citations)
[docs]defnice_citation(self,prefix:t.Optional[str]="",start_idx:t.Optional[int]=0,indent:t.Optional[int]=0,)->str:"""Returns a nice printable string of citations. Parameters ---------- prefix: str, optional Prefix to add to each citation start_idx: int, optional Starting index of citation indent: int, optional Indentation of citation """entries=self.citations()iflen(entries)==0:return""return"\n".join([construct_nice_printable_string(e)foreinentries])
[docs]@lru_cache(maxsize=100)defdoi_to_bibtex(doi:str)->t.Optional[str]:"""Converts a doi to bibtex. Parameters ---------- doi: str DOI to convert """importurllibbase_url="http://dx.doi.org/"url=base_url+doireq=urllib.request.Request(url)req.add_header("Accept","application/x-bibtex")try:withurllib.request.urlopen(req)asf:# noqa: S310returnf.read().decode()exceptHTTPErrorase:ife.code==404:print("DOI not found.")else:print("Service unavailable.")returnNoneexceptURLError:returnNone