def updateArXiv(entry): """Look for new versions of arXiv entry `entry` Returns False if no new versions or not an arXiv entry, Returns the new bibtex otherwise. """ bibtex = getBibtex(entry) # Check arXiv if('archiveprefix' not in bibtex or 'arXiv' not in bibtex['archiveprefix']): return False arxiv_id = bibtex['eprint'] arxiv_id_no_v = re.sub(r'v\d+\Z', '', arxiv_id) ids = set(arxiv_id) for entry in getEntries(): if('archiveprefix' not in bibtex or 'arXiv' not in bibtex['archiveprefix']): continue ids.add(bibtex['eprint']) last_bibtex = BibTexParser(fetcher.arXiv2Bib(arxiv_id_no_v)) last_bibtex = last_bibtex.get_entry_dict() last_bibtex = last_bibtex[list(last_bibtex.keys())[0]] if last_bibtex['eprint'] not in ids: return last_bibtex else: return False
def getBibtex(entry, file_id='both', clean=False): """Returns the bibtex entry corresponding to entry, as a dict entry is either a filename or a bibtex ident file_id is file or id or both to search for a file / id / both clean is to clean the ignored fields specified in config """ try: with open(config.get("folder")+'index.bib', 'r', encoding='utf-8') \ as fh: bibtex = BibTexParser(fh.read()) bibtex = bibtex.get_entry_dict() except (TypeError, IOError): tools.warning("Unable to open index file.") return False bibtex_entry = False if file_id == 'both' or file_id == 'id': try: bibtex_entry = bibtex[entry] except KeyError: pass if file_id == 'both' or file_id == 'file': if os.path.isfile(entry): for key in bibtex.keys(): if os.path.samefile(bibtex[key]['file'], entry): bibtex_entry = bibtex[key] break if clean: for field in config.get("ignore_fields"): try: del(bibtex_entry[field]) except KeyError: pass return bibtex_entry
def deleteId(ident): """Delete a file based on its id in the bibtex file""" try: with open(config.get("folder")+'index.bib', 'r', encoding='utf-8') \ as fh: bibtex = BibTexParser(fh.read()) bibtex = bibtex.get_entry_dict() except (IOError, TypeError): tools.warning("Unable to open index file.") return False if ident not in bibtex.keys(): return False try: os.remove(bibtex[ident]['file']) except (KeyError, OSError): tools.warning("Unable to delete file associated to id "+ident+" : " + bibtex[ident]['file']) try: if not os.listdir(os.path.dirname(bibtex[ident]['file'])): os.rmdir(os.path.dirname(bibtex[ident]['file'])) except (KeyError, OSError): tools.warning("Unable to delete empty tag dir " + os.path.dirname(bibtex[ident]['file'])) try: del(bibtex[ident]) bibtexRewrite(bibtex) except KeyError: tools.warning("No associated bibtex entry in index for file " + bibtex[ident]['file']) return True
def getEntries(): """Returns the list of all entries in the bibtex index""" try: with open(config.get("folder")+'index.bib', 'r', encoding='utf-8') \ as fh: bibtex = BibTexParser(fh.read()) bibtex = bibtex.get_entry_dict() except (TypeError, IOError): tools.warning("Unable to open index file.") return False return list(bibtex.keys())
def openFile(ident): try: with open(config.get("folder")+'index.bib', 'r', encoding='utf-8') \ as fh: bibtex = BibTexParser(fh.read()) bibtex = bibtex.get_entry_dict() except (TypeError, IOError): tools.warning("Unable to open index file.") return False if ident not in list(bibtex.keys()): return False else: subprocess.Popen(['xdg-open', bibtex[ident]['file']]) return True
def arXiv2Bib(arxiv): """Returns bibTeX string of metadata for a given arXiv id arxiv is an arxiv id """ bibtex = arxiv_metadata.arxiv2bib([arxiv]) for bib in bibtex: if isinstance(bib, arxiv_metadata.ReferenceErrorInfo): continue else: fetched_bibtex = BibTexParser(bib.bibtex()) fetched_bibtex = fetched_bibtex.get_entry_dict() fetched_bibtex = fetched_bibtex[list(fetched_bibtex.keys())[0]] try: del(fetched_bibtex['file']) except KeyError: pass return tools.parsed2Bibtex(fetched_bibtex) return ''
def deleteFile(filename): """Delete a file based on its filename""" try: with open(config.get("folder")+'index.bib', 'r', encoding='utf-8') \ as fh: bibtex = BibTexParser(fh.read()) bibtex = bibtex.get_entry_dict() except (TypeError, IOError): tools.warning("Unable to open index file.") return False found = False for key in list(bibtex.keys()): try: if os.path.samefile(bibtex[key]['file'], filename): found = True try: os.remove(bibtex[key]['file']) except (KeyError, OSError): tools.warning("Unable to delete file associated to id " + key+" : "+bibtex[key]['file']) try: if not os.listdir(os.path.dirname(filename)): os.rmdir(os.path.dirname(filename)) except OSError: tools.warning("Unable to delete empty tag dir " + os.path.dirname(filename)) try: del(bibtex[key]) except KeyError: tools.warning("No associated bibtex entry in index for " + "file " + bibtex[key]['file']) except (KeyError, OSError): pass if found: bibtexRewrite(bibtex) elif os.path.isfile(filename): os.remove(filename) return found
class TestFetcher(unittest.TestCase): def setUp(self): config.set("folder", tempfile.mkdtemp()+"/") self.bibtex_article_string = """ @article{1303.3130v1, abstract={We study the role of the dipolar interaction, correctly accounting for the Dipolar-Induced Resonance (DIR), in a quasi-one-dimensional system of ultracold bosons. We first show how the DIR affects the lowest-energy states of two particles in a harmonic trap. Then, we consider a deep optical lattice loaded with ultracold dipolar bosons. We describe this many-body system using an atom-dimer extended Bose-Hubbard model. We analyze the impact of the DIR on the phase diagram at T=0 by exact diagonalization of a small-sized system. In particular, the resonance strongly modifies the range of parameters for which a mass density wave should occur.}, archiveprefix={arXiv}, author={N. Bartolo and D. J. Papoular and L. Barbiero and C. Menotti and A. Recati}, eprint={1303.3130v1}, file={%sN_Bartolo_A_Recati-j-2013.pdf}, link={http://arxiv.org/abs/1303.3130v1}, month={Mar}, primaryclass={cond-mat.quant-gas}, tag={}, title={Dipolar-Induced Resonance for Ultracold Bosons in a Quasi-1D Optical Lattice}, year={2013}, }""" % config.get("folder") self.bibtex_article = BibTexParser(self.bibtex_article_string).get_entry_dict() self.bibtex_article = self.bibtex_article[list(self.bibtex_article.keys())[0]] self.bibtex_book_string = """ @book{9780521846516, author={C. J. Pethick and H. Smith}, isbn={9780521846516}, publisher={Cambridge University Press}, title={Bose-Einstein Condensation In Dilute Gases}, year={2008}, } """ self.bibtex_book = BibTexParser(self.bibtex_book_string).get_entry_dict() self.bibtex_book = self.bibtex_book[list(self.bibtex_book.keys())[0]] def test_getNewName_article(self): self.assertEqual(getNewName("test.pdf", self.bibtex_article), config.get("folder")+"N_Bartolo_A_Recati-j-2013-v1.pdf") def test_getNewName_article_override(self): self.assertEqual(getNewName("test.pdf", self.bibtex_article, override_format="%f"), config.get("folder")+"N_Bartolo.pdf") def test_getNewName_book(self): self.assertEqual(getNewName("test.pdf", self.bibtex_book), config.get("folder")+"C_J_Pethick_H_Smith-Bose-Einstein_Condensation_In_Dilute_Gases.pdf") def test_getNewName_book_override(self): self.assertEqual(getNewName("test.pdf", self.bibtex_book, override_format="%a"), config.get("folder")+"C_J_Pethick_H_Smith.pdf") def test_bibtexAppend(self): bibtexAppend(self.bibtex_article) with open(config.get("folder")+'index.bib', 'r') as fh: self.assertEqual(fh.read(), '@article{1303.3130v1,\n\tabstract={We study the role of the dipolar interaction, correctly accounting for the\nDipolar-Induced Resonance (DIR), in a quasi-one-dimensional system of ultracold\nbosons. We first show how the DIR affects the lowest-energy states of two\nparticles in a harmonic trap. Then, we consider a deep optical lattice loaded\nwith ultracold dipolar bosons. We describe this many-body system using an\natom-dimer extended Bose-Hubbard model. We analyze the impact of the DIR on the\nphase diagram at T=0 by exact diagonalization of a small-sized system. In\nparticular, the resonance strongly modifies the range of parameters for which a\nmass density wave should occur.},\n\tarchiveprefix={arXiv},\n\tauthor={N. Bartolo and D. J. Papoular and L. Barbiero and C. Menotti and A. Recati},\n\teprint={1303.3130v1},\n\tfile={'+config.get("folder")+'N_Bartolo_A_Recati-j-2013.pdf},\n\tlink={http://arxiv.org/abs/1303.3130v1},\n\tmonth={Mar},\n\tprimaryclass={cond-mat.quant-gas},\n\ttag={},\n\ttitle={Dipolar-Induced Resonance for Ultracold Bosons in a Quasi-1D Optical\nLattice},\n\tyear={2013},\n}\n\n\n') def test_bibtexEdit(self): bibtexAppend(self.bibtex_article) bibtexEdit(self.bibtex_article['id'], {'id': 'bidule'}) with open(config.get("folder")+'index.bib', 'r') as fh: self.assertEqual(fh.read(), '@article{bidule,\n\tabstract={We study the role of the dipolar interaction, correctly accounting for the\nDipolar-Induced Resonance (DIR), in a quasi-one-dimensional system of ultracold\nbosons. We first show how the DIR affects the lowest-energy states of two\nparticles in a harmonic trap. Then, we consider a deep optical lattice loaded\nwith ultracold dipolar bosons. We describe this many-body system using an\natom-dimer extended Bose-Hubbard model. We analyze the impact of the DIR on the\nphase diagram at T=0 by exact diagonalization of a small-sized system. In\nparticular, the resonance strongly modifies the range of parameters for which a\nmass density wave should occur.},\n\tarchiveprefix={arXiv},\n\tauthor={N. Bartolo and D. J. Papoular and L. Barbiero and C. Menotti and A. Recati},\n\teprint={1303.3130v1},\n\tfile={'+config.get("folder")+'N_Bartolo_A_Recati-j-2013.pdf},\n\tlink={http://arxiv.org/abs/1303.3130v1},\n\tmonth={Mar},\n\tprimaryclass={cond-mat.quant-gas},\n\ttag={},\n\ttitle={Dipolar-Induced Resonance for Ultracold Bosons in a Quasi-1D Optical\nLattice},\n\tyear={2013},\n}\n\n\n') def test_bibtexRewrite(self): bibtexAppend(self.bibtex_book) bibtexRewrite({0: self.bibtex_article}) with open(config.get("folder")+'index.bib', 'r') as fh: self.assertEqual(fh.read(), '@article{1303.3130v1,\n\tabstract={We study the role of the dipolar interaction, correctly accounting for the\nDipolar-Induced Resonance (DIR), in a quasi-one-dimensional system of ultracold\nbosons. We first show how the DIR affects the lowest-energy states of two\nparticles in a harmonic trap. Then, we consider a deep optical lattice loaded\nwith ultracold dipolar bosons. We describe this many-body system using an\natom-dimer extended Bose-Hubbard model. We analyze the impact of the DIR on the\nphase diagram at T=0 by exact diagonalization of a small-sized system. In\nparticular, the resonance strongly modifies the range of parameters for which a\nmass density wave should occur.},\n\tarchiveprefix={arXiv},\n\tauthor={N. Bartolo and D. J. Papoular and L. Barbiero and C. Menotti and A. Recati},\n\teprint={1303.3130v1},\n\tfile={%sN_Bartolo_A_Recati-j-2013.pdf},\n\tlink={http://arxiv.org/abs/1303.3130v1},\n\tmonth={Mar},\n\tprimaryclass={cond-mat.quant-gas},\n\ttag={},\n\ttitle={Dipolar-Induced Resonance for Ultracold Bosons in a Quasi-1D Optical\nLattice},\n\tyear={2013},\n}\n\n\n' % config.get("folder")) def test_deleteId(self): self.bibtex_article['file'] = config.get("folder")+'test.pdf' bibtexAppend(self.bibtex_article) open(config.get("folder")+'test.pdf', 'w').close() deleteId(self.bibtex_article['id']) with open(config.get("folder")+'index.bib', 'r') as fh: self.assertEqual(fh.read().strip(), "") self.assertFalse(os.path.isfile(config.get("folder")+'test.pdf')) def test_deleteFile(self): self.bibtex_article['file'] = config.get("folder")+'test.pdf' bibtexAppend(self.bibtex_article) open(config.get("folder")+'test.pdf', 'w').close() deleteFile(self.bibtex_article['file']) with open(config.get("folder")+'index.bib', 'r') as fh: self.assertEqual(fh.read().strip(), "") self.assertFalse(os.path.isfile(config.get("folder")+'test.pdf')) def test_diffFilesIndex(self): # TODO return def test_getBibtex(self): bibtexAppend(self.bibtex_article) got = getBibtex(self.bibtex_article['id']) self.assertEqual(got, self.bibtex_article) def test_getBibtex_id(self): bibtexAppend(self.bibtex_article) got = getBibtex(self.bibtex_article['id'], file_id='id') self.assertEqual(got, self.bibtex_article) def test_getBibtex_file(self): self.bibtex_article['file'] = config.get("folder")+'test.pdf' open(config.get("folder")+'test.pdf', 'w').close() bibtexAppend(self.bibtex_article) got = getBibtex(self.bibtex_article['file'], file_id='file') self.assertEqual(got, self.bibtex_article) def test_getBibtex_clean(self): config.set("ignore_fields", ['id', 'abstract']) bibtexAppend(self.bibtex_article) got = getBibtex(self.bibtex_article['id'], clean=True) for i in config.get("ignore_fields"): self.assertNotIn(i, got) def test_getEntries(self): bibtexAppend(self.bibtex_article) self.assertEqual(getEntries(), [self.bibtex_article['id']]) def test_updateArxiv(self): # TODO return def test_search(self): # TODO return def tearDown(self): shutil.rmtree(config.get("folder"))
def addFile(src, filetype, manual, autoconfirm, tag): """ Add a file to the library """ doi = False arxiv = False isbn = False if not manual: try: if filetype == 'article' or filetype is None: id_type, article_id = fetcher.findArticleID(src) if id_type == "DOI": doi = article_id elif id_type == "arXiv": arxiv = article_id if filetype == 'book' or (doi is False and arxiv is False and filetype is None): isbn = fetcher.findISBN(src) except KeyboardInterrupt: doi = False arxiv = False isbn = False if doi is False and isbn is False and arxiv is False: if filetype is None: tools.warning("Could not determine the DOI nor the arXiv id nor " + "the ISBN for "+src+". Switching to manual entry.") doi_arxiv_isbn = '' while(doi_arxiv_isbn not in ['doi', 'arxiv', 'isbn', 'manual', 'skip']): doi_arxiv_isbn = (tools.rawInput("DOI / arXiv " + "/ ISBN / manual / skip? "). lower()) if doi_arxiv_isbn == 'doi': doi = tools.rawInput('DOI? ') elif doi_arxiv_isbn == 'arxiv': arxiv = tools.rawInput('arXiv id? ') elif doi_arxiv_isbn == 'isbn': isbn = tools.rawInput('ISBN? ') elif doi_arxiv_isbn == 'skip': return False elif filetype == 'article': tools.warning("Could not determine the DOI nor the arXiv id for " + src+", switching to manual entry.") doi_arxiv = '' while doi_arxiv not in ['doi', 'arxiv', 'manual', 'skip']: doi_arxiv = (tools.rawInput("DOI / arXiv / manual / skip? "). lower()) if doi_arxiv == 'doi': doi = tools.rawInput('DOI? ') elif doi_arxiv == 'arxiv': arxiv = tools.rawInput('arXiv id? ') elif doi_arxiv == 'skip': return False elif filetype == 'book': isbn_manual = '' while isbn_manual not in ['isbn', 'manual', 'skip']: isbn_manual = tools.rawInput("ISBN / manual / skip? ").lower() if isbn_manual == 'isbn': isbn = (tools.rawInput('ISBN? '). replace(' ', ''). replace('-', '')) elif isbn_manual == 'skip': return False elif doi is not False: print("DOI for "+src+" is "+doi+".") elif arxiv is not False: print("ArXiv id for "+src+" is "+arxiv+".") elif isbn is not False: print("ISBN for "+src+" is "+isbn+".") if doi is not False and doi != '': # Add extra \n for bibtexparser bibtex = fetcher.doi2Bib(doi).strip().replace(',', ",\n")+"\n" elif arxiv is not False and arxiv != '': bibtex = fetcher.arXiv2Bib(arxiv).strip().replace(',', ",\n")+"\n" elif isbn is not False and isbn != '': # Idem bibtex = fetcher.isbn2Bib(isbn).strip()+"\n" else: bibtex = '' bibtex = BibTexParser(bibtex) bibtex = bibtex.get_entry_dict() if len(bibtex) > 0: bibtex_name = list(bibtex.keys())[0] bibtex = bibtex[bibtex_name] bibtex_string = tools.parsed2Bibtex(bibtex) else: bibtex_string = '' if not autoconfirm: bibtex = checkBibtex(src, bibtex_string) if not autoconfirm: tag = tools.rawInput("Tag for this paper (leave empty for default) ? ") else: tag = args.tag bibtex['tag'] = tag new_name = backend.getNewName(src, bibtex, tag) while os.path.exists(new_name): tools.warning("file "+new_name+" already exists.") default_rename = new_name.replace(tools.getExtension(new_name), " (2)"+tools.getExtension(new_name)) rename = tools.rawInput("New name ["+default_rename+"]? ") if rename == '': new_name = default_rename else: new_name = rename bibtex['file'] = new_name try: shutil.copy2(src, new_name) except shutil.Error: new_name = False sys.exit("Unable to move file to library dir " + config.get("folder")+".") # Remove first page of IOP papers try: if 'IOP' in bibtex['publisher'] and bibtex['type'] == 'article': tearpages.tearpage(new_name) except (KeyError, shutil.Error, IOError): pass backend.bibtexAppend(bibtex) return new_name
def checkBibtex(filename, bibtex_string): print("The bibtex entry found for "+filename+" is:") bibtex = BibTexParser(bibtex_string) bibtex = bibtex.get_entry_dict() try: bibtex = bibtex[list(bibtex.keys())[0]] # Check entries are correct assert bibtex['title'] if bibtex['type'] == 'article': assert bibtex['authors'] elif bibtex['type'] == 'book': assert bibtex['author'] assert bibtex['year'] # Print the bibtex and confirm print(tools.parsed2Bibtex(bibtex)) check = tools.rawInput("Is it correct? [Y/n] ") except KeyboardInterrupt: sys.exit() except (IndexError, KeyError, AssertionError): check = 'n' try: old_filename = bibtex['file'] except KeyError: old_filename = False while check.lower() == 'n': with tempfile.NamedTemporaryFile(suffix=".tmp") as tmpfile: tmpfile.write(bibtex_string.encode('utf-8')) tmpfile.flush() subprocess.call([EDITOR, tmpfile.name]) tmpfile.seek(0) bibtex = BibTexParser(tmpfile.read().decode('utf-8')+"\n") bibtex = bibtex.get_entry_dict() try: bibtex = bibtex[list(bibtex.keys())[0]] except (IndexError, KeyError): tools.warning("Invalid bibtex entry") bibtex_string = '' tools.rawInput("Press Enter to go back to editor.") continue if('authors' not in bibtex and 'title' not in bibtex and 'year' not in bibtex): tools.warning("Invalid bibtex entry") bibtex_string = '' tools.rawInput("Press Enter to go back to editor.") continue if old_filename is not False and 'file' not in bibtex: tools.warning("Invalid bibtex entry. No filename given.") tools.rawInput("Press Enter to go back to editor.") check = 'n' else: bibtex_string = tools.parsed2Bibtex(bibtex) print("\nThe bibtex entry for "+filename+" is:") print(bibtex_string) check = tools.rawInput("Is it correct? [Y/n] ") if old_filename is not False and old_filename != bibtex['file']: try: print("Moving file to new location…") shutil.move(old_filename, bibtex['file']) except shutil.Error: tools.warning("Unable to move file "+old_filename+" to " + bibtex['file']+". You should check it manually.") return bibtex