importrequestsimportjsonimportosfromtcutilityimportspell_check,cache# @cache.cache_file('dois')@cache.cachedef_get_doi_data(doi:str)->dict:''' Get information about an article using the crossref.org API. Args: doi: the DOI to get information about. '''print(f'http://api.crossref.org/works/{doi}')data=requests.get(f'http://api.crossref.org/works/{doi}').textifdata=='Resource not found.':raiseValueError(f'Could not find DOI {doi}.')data=json.loads(data)returndata# @cache.cache_file('journal_abbrvs')@cache.cachedef_get_journal_abbreviation(journal:str)->str:''' Get the journal name abbreviation using the abbreviso API. Args: journal: the name of the journal to get the abbreviation of. '''returnrequests.get(f"https://abbreviso.toolforge.org/a/{journal}").text@cache.cachedef_get_publisher_city(publisher:str)->str:''' Get the city of a publisher. '''withopen(os.path.join(os.path.split(__file__)[0],'data','cite','_publisher_cities.json'))ascities:cities=json.loads(cities.read())returncities.get(publisher)
[docs]defcite(doi:str,style:str='wiley',mode='html')->str:''' Format an article in a certain style. Args: doi: the article DOI to generate a citation for. style: the style formatting to use. Can be ``['wiley', 'acs', 'rsc']``. mode: the formatting mode. Can be ``['html', 'latex', 'plain']``. '''# check if the style was correctly givenspell_check.check(style,['wiley','acs','rsc'])spell_check.check(mode,['html','latex','plain'])# get the information about the DOIdata=_get_doi_data(doi)ifdata['message']['type']=='journal-article':citation=_format_article(data,style)ifdata['message']['type']=='book-chapter'or(data['message']['type']=='other'and'ISBN'indata['message']):citation=_format_book_chapter(data,style)ifmode=='plain':citation=citation.replace('<i>','')citation=citation.replace('</i>','')citation=citation.replace('<b>','')citation=citation.replace('</b>','')ifmode=='latex':citation=citation.replace('<i>',r'\textit{')citation=citation.replace('</i>','}')citation=citation.replace('<b>',r'\textbf{')citation=citation.replace('</b>','}')returncitation
def_format_article(data:dict,style:str)->str:# grab usefull datajournal=data['message']['container-title'][0]journal_abbreviation=_get_journal_abbreviation(journal)year=data['message']['issued']['date-parts'][0][0]volume=data['message'].get('volume','')pages=get_pages(data)title=data['message']['title'][0]doi=data['message']['DOI']# accepted = is_accepted(data) # not using this one yet# Get the initials from the author given names# also store the family namesinitials=[]last_names=[]forauthorindata['message']['author']:# we get the capital letters from the first names# these will become the initials for this authorfirsts=[char+'.'forcharinauthor['given'].title()ifchar.isupper()]firsts=" ".join(firsts)initials.append(firsts)last_names.append(author['family'].title())# format the citation correctlyifstyle=='wiley':names=[f'{first}{last}'forfirst,lastinzip(initials,last_names)]citation=f'{", ".join(names)}, <i>{journal_abbreviation}</i> <b>{year}</b>, <i>{volume}</i>'ifpages:citation+=f', {pages}'citation+='.'elifstyle=='acs':names=[f'{last}, {first}'forfirst,lastinzip(initials,last_names)]citation=f'{"; ".join(names)}{title} <i>{journal_abbreviation}</i> <b>{year}</b>, <i>{volume}</i>'ifpages:citation+=f', {pages}'citation+=f'. DOI: {doi}'elifstyle=='rsc':names=[f'{first}{last}'forfirst,lastinzip(initials,last_names)]citation=f'{", ".join(names)}, <i>{journal_abbreviation}</i> {year}, <b>{volume}</b>'ifpages:citation+=f', {pages}'citation+='.'returncitationdef_format_book_chapter(data:dict,style:str)->str:# grab usefull datapublisher=data['message']['publisher']year=data['message']['published-print']['date-parts'][0][0]pages=data['message'].get('page')book_title=data['message']['container-title'][0]chapter_title=data['message']['title'][0]city=_get_publisher_city(publisher)forisbnindata['message']['isbn-type']:ifisbn['type']=='electronic':original_book_data=_get_doi_data(f"{data['message']['prefix']}/{isbn['value']}")break# Get the initials from the author given names# also store the family namesn_authors=len(data['message']['author'])initials=[]last_names=[]forauthorindata['message']['author']:# we get the capital letters from the first names# these will become the initials for this authorfirsts=[char+'.'forcharinauthor['given'].title()ifchar.isupper()]firsts=" ".join(firsts)initials.append(firsts)last_names.append(author['family'].title())n_editors=len(original_book_data['message']['editor'])editor_initials=[]editor_last_names=[]forauthorinoriginal_book_data['message']['editor']:# we get the capital letters from the first names# these will become the initials for this authorfirsts=[char+'.'forcharinauthor['given'].title()ifchar.isupper()]firsts=" ".join(firsts)editor_initials.append(firsts)editor_last_names.append(author['family'].title())# format the citation correctlyifstyle=='wiley':names=[f'{last}, {first}'forfirst,lastinzip(initials,last_names)]editors=[f'{first}{last}'forfirst,lastinzip(editor_initials,editor_last_names)]ifn_authors==1:names=names[0]if1<n_authors<4:names=", ".join(names[:-1])+' and '+names[-1]ifn_authors>=4:names=", ".join(names[:3])+' et al.'ifn_editors==1:editors=editors[0]if1<n_editors<4:editors=", ".join(editors[:-1])+' and '+editors[-1]ifn_editors>=4:editors=", ".join(editors[:3])+' et al.'citation=f'{names} ({year}). {chapter_title}. In: <i>{book_title}</i> (ed. {editors}), {pages}. {city}: {publisher}'elifstyle=='acs':raiseNotImplementedError('No support for ACS style yet')elifstyle=='rsc':raiseNotImplementedError('No support for RSC style yet')returncitation