def cellDoubleClick(self, index): """Process event when mouse double clicks an item. Opens a link if some columns Parameter: index: a `QModelIndex` instance """ if index.isValid(): row = index.row() col = index.column() else: return idExp = str(self.proxyModel.sibling(row, 0, index).data()) if self.colContents[col] == "inspire" or self.colContents[col] == "homepage": link = self.proxyModel.sibling(row, col, index).data() if link == "" or link is None: self.parent().reloadMainContent(pBDB.bibs.getByExp(idExp)) return if self.colContents[col] == "inspire": link = pbConfig.inspireExperimentsLink + link pBLogger.debug(ewstr.opening % link) try: pBGuiView.openLink(link, "link") except Exception: pBLogger.warning(ewstr.openLinkFailed % link, exc_info=True) else: self.parent().reloadMainContent(pBDB.bibs.getByExp(idExp)) return True
def openLink(self, key, arg="arxiv", fileArg=None): """Uses the getLink method to generate the web link and opens it in an external application Parameters: key, arg, fileArg as in the getLink method """ if isinstance(key, list): for k in key: self.openLink(k, arg, fileArg) else: if arg == "file": self.getLink(key, arg=arg, fileArg=fileArg) return elif arg == "link": link = key else: link = self.getLink(key, arg=arg, fileArg=fileArg) if link: if self.webApp != "": pBLogger.info(vstr.opening % link) try: subprocess.Popen( [self.webApp, link], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) except OSError: pBLogger.warning(vstr.openingFailed % ("link", key)) else: pBLogger.warning(vstr.errorLink % (arg, key))
def switchLines(self, ix): """Save the current form content, switch the order of the rows as required, create a new form with the new order. Parameter: ix: the index of the first of the two rows involved in the switch (e.g., to switch the first and second rows, use ix = 0) """ currentValues = {} currentOrder = [] for el in self.elements[:len(pbConfig.profiles)]: tmp = {} tmp["db"] = el["f"].text() tmp["d"] = el["d"].text() tmp["r"] = el["r"].isChecked() tmp["x"] = el["x"].isChecked() currentValues[el["n"].text()] = tmp currentOrder.append(el["n"].text()) newLine = { "r": self.elements[-1]["r"].isChecked(), "n": self.elements[-1]["n"].text(), "db": self.elements[-1]["f"].currentText(), "d": self.elements[-1]["d"].text(), } tempOrder = list(currentOrder) try: tempOrder[ix] = currentOrder[ix + 1] tempOrder[ix + 1] = currentOrder[ix] except IndexError: pBLogger.warning(pmstr.errorSwitchLines) return False self.cleanLayout() self.createForm(currentValues, tempOrder, newLine) return True
def openLink(self, key, arg="", fileArg=None): """Use `QDesktopServices` to open an url using the system default applications Parameters: key: the entry key or the link (if `arg` == "link") arg: if `arg` == "file", `fileArg` must be the file name if `arg` == "link", `key` must be the link to be opened for any other values, the link will be generated using the `physbiblio.view.viewWntry.getLink` method fileArg: the file name if `arg` == "file", or the argument passed to `physbiblio.view.viewWntry.getLink` if needed """ if isinstance(key, list): for k in key: self.openLink(k, arg, fileArg) else: if arg == "file": url = QUrl.fromLocalFile(fileArg) elif arg == "link": url = QUrl(key) else: link = self.getLink(key, arg=arg, fileArg=fileArg) url = QUrl(link) if QDesktopServices.openUrl(url): pBLogger.debug(ccstr.openSuccess % (url.toString(), key)) else: pBLogger.warning(ccstr.openFailed % key)
def run(self): """Start the receiver, import the required entries and finish """ self.receiver.start() db = bibtexparser.bibdatabase.BibDatabase() inserted = [] failed = [] for key in sorted(self.found): if not self.runningImport: continue el = self.found[key] if pBDB.bibs.loadAndInsert(el["bibpars"]["eprint"]): try: newKey = pBDB.bibs.getByKey(key)[0]["bibkey"] except IndexError: newKey = pBDB.bibs.getByBibtex(key)[0]["bibkey"] inserted.append(newKey) else: db.entries = [{ "ID": el["bibpars"]["eprint"], "ENTRYTYPE": "article", "title": el["bibpars"]["title"], "author": el["bibpars"]["author"], "archiveprefix": "arXiv", "eprint": el["bibpars"]["eprint"], "primaryclass": el["bibpars"]["primaryclass"], }] entry = pbWriter.write(db) data = pBDB.bibs.prepareInsert(entry) if pBDB.bibs.insert(data): pBLogger.info(thestr.elementInserted % key) inserted.append(key) else: pBLogger.warning(thestr.elementFailed % key) failed.append(key) continue try: eid = pBDB.bibs.updateInspireID(key) pBDB.bibs.searchOAIUpdates( 0, entries=pBDB.bibs.getByBibkey(key), force=True, reloadAll=True, ) newKey = pBDB.bibs.getByKey(key)[0]["bibkey"] if key != newKey: inserted[-1] = newKey except: pBLogger.warning(thestr.failedComplete % (key), exc_info=True) failed.append(key) pBLogger.info(thestr.elementImported % (inserted)) pBLogger.info(thestr.errorsEntries % (failed)) self.parent().importArXivResults = (inserted, failed) time.sleep(0.1) self.receiver.running = False
def getSeries(url): response = self.http.get(url, timeout=self.timeout) text = response.content.decode("utf-8") try: return json.loads(text)["hits"]["hits"] except ValueError: pBLogger.warning(isstr.emptyResponse) return [] except Exception: pBLogger.exception(isstr.errorReadPage) return []
def getLink(self, key, arg="arxiv", fileArg=None): """Uses database information to construct and print the web link, or the pdf module to open a pdf Parameters: key: the bibtex identifier as stored in the database. It may be a list (calls recursively itself) arg: the string defining the type of link/action ("arxiv", "doi", "inspire", "file") fileArg: additional argument for the PDF module, used only if arg == "file" Output: link: the string of the web link if arg in ("arxiv", "doi", "inspire"), True if arg == "file", False if arg is invalid """ if isinstance(key, list): links = [] for k in key: if arg != "file": links.append(self.getLink(k, arg, fileArg)) else: links.append(fileArg) return links ads = pBDB.bibs.getField(key, "ads") arxiv = pBDB.bibs.getField(key, "arxiv") doi = pBDB.bibs.getField(key, "doi") inspire = pBDB.bibs.getField(key, "inspire") if arg == "ads" and ads: link = pBDB.bibs.getAdsUrl(key) elif arg == "arxiv" and arxiv: link = pBDB.bibs.getArxivUrl(key, "abs") elif arg == "doi" and doi: link = pBDB.bibs.getDoiUrl(key) elif arg == "inspire" and inspire: link = self.inspireRecord + inspire elif arg == "inspire" and arxiv: link = self.inspireSearch + "arxiv:" + arxiv elif arg == "inspire": link = self.inspireSearch + key elif arg == "file": pBPDF.openFile(key, fileArg) return fileArg else: pBLogger.warning(vstr.warningInvalidUse % key) return False return link
def textFromUrl(self, url, headers=None): """Use urllib to get the html content of the given url. Parameters: url: the url to be opened headers (default None): the additional headers to be passed to urllib.Request Output: text: the content of the url """ http = PBSession() if not isinstance(headers, dict): headers = {} try: data = http.get(url, headers=headers, timeout=self.urlTimeout).content except URLError: pBLogger.warning(self.errorRetrieve % self.name) return "" except HTTPError: pBLogger.warning(self.errorNotFound % url) return "" except (ssl.SSLError, socket.timeout): pBLogger.warning(self.errorTimedOut % self.name) return "" try: text = data.decode("utf-8") except Exception: pBLogger.warning(self.errorBadCodification % self.name) return "" http.close() return text
def getYear(string): """Use the arxiv id to compute the year""" identif = re.compile("([0-9]{2})([0-9]{2}.[0-9]{4,5}|[0-9]{5})") try: for t in identif.finditer(string): if len(t.group()) > 0: a = t.group(1) if int(a) > 90: return "19" + a else: return "20" + a except Exception: pBLogger.warning(ArxivStrings.errorYearConversion % string) return None
def retrieveUrlAllFrom(self, search, method): """Calls the function retrieveUrlAll given the subclass method. Parameters: search: the search string method: the key of the method in `self.webSearch` Output: None in the default implementation (must be subclassed) """ try: return getattr(self.webSearch[method], retrieveUrlAll)(search) except KeyError: pBLogger.warning(self.methodNotAvailable % method) return ""
def getField(self, string, field): """Perform a search and return the value of a specific field as given by the ADS API Parameters: string: the search string field: the field name (must be in self.loadFields) Output: a list with the field values for all the obtained entries """ if not field in self.loadFields: pBLogger.warning(self.invalidField % field) return [] a = self.getGenericInfo(string, self.loadFields) return [getattr(p, field) for p in a]
def run(self): """Run the thread, using `outdated.check_outdated` and checking for errors """ try: outdated, newVersion = check_outdated("physbiblio", __version__) self.result.emit(outdated, newVersion) except ValueError: pBLogger.warning( thestr.outdatedError, exc_info=True, ) except (URLError, ConnectionError): pBLogger.warning( thestr.outdatedWarning, exc_info=True, )
def editFile(self, paramkey="logFileName", text=dwstr.logFileName, filter="*.log"): """Open a dialog to select a new file name for a configuration parameter, and save the result in the `ConfigWindow` interface Parameters: paramkey: the parameter name in the configuration dictionary text: description in the file dialog filter: filter the folder content in the file dialog """ if paramkey not in pbConfig.paramOrder: pBLogger.warning(dwstr.invalidParamkey % paramkey) return ix = pbConfig.paramOrder.index(paramkey) fname = askSaveFileName(parent=None, title=text, dir=self.textValues[ix][1].text(), filter=filter) if fname.strip() != "": self.textValues[ix][1].setText(str(fname))
def __init__(self, cats, rootElements, parent=None, previous=[], multipleRecords=False): """Initialize the model, save the data and the initial selection Parameters: cats: the list of categories records from the database rootElements: the list of root elements of the tree parent: the parent widget (default: None) previous: the list of previously selected categories (default: an empty list) multipleRecords: activate tristate for selecting categories for multiple records (default False) """ self.cats = cats self.rootElements = rootElements TreeModel.__init__(self) self.parentObj = parent self.selectedCats = {} self.previousSaved = {} for cat in self.cats: self.selectedCats[cat["idCat"]] = False self.previousSaved[cat["idCat"]] = False for prevIx in previous: if prevIx in [cat["idCat"] for cat in self.cats]: if multipleRecords: self.previousSaved[prevIx] = True self.selectedCats[prevIx] = "p" else: self.selectedCats[prevIx] = True else: pBLogger.warning(cwstr.invalidCat % prevIx)
def readForm(self): """Read the form content""" self.update = self.updateCheck.isChecked() self.remove = self.removeCheck.isChecked() self.reorder = self.reorderCheck.isChecked() self.bibName = self.bibButton.text() if self.bibName == dwstr.selFile: self.bibName = "" self.texFileNames = [] for button in self.texButtons: txt = button.text() if "[" in txt: try: txt = ast.literal_eval(txt) except ValueError: pBLogger.warning(dwstr.invalidText % s) self.texFileNames.append(txt) tmp = [] for fn in self.texFileNames: if isinstance(fn, list): tmp += fn else: tmp.append(fn) self.texNames = [f for f in tmp if f != dwstr.selFile and f != ""]
def plotStats( self, paper=False, author=False, show=False, save=False, path=".", markPapers=False, pickVal=6, ): """Plot the collected information, using matplotlib.pyplot. Parameters: paper (boolean, default False): plot statistics for the last analyzed paper author (boolean, default False): plot statistics for the last analyzed author show (boolean, default False): True to show the plots in a separate window (with matplotlib.pyplot.show()) save (boolean, default False): True to save the plots into files. path (string): where to save the plots markPapers (boolean, default False): True to draw a vertical lines at the dates corresponding to a paper appearing pickVal (float, default 6): the picker tolerance Output: False if paper==False and author==False, the matplotlib.pyplot figure containing the citation plot if paper==True, a list of matplotlib.pyplot figures containing the various plots if author==True """ if paper and self.paperPlotInfo is not None: if len(self.paperPlotInfo["citList"][0]) > 0: pBLogger.info(isstr.plotPaper % self.paperPlotInfo["id"]) fig, ax = plt.subplots() plt.plot( self.paperPlotInfo["citList"][0], self.paperPlotInfo["citList"][1], picker=True, pickradius=pickVal, ) fig.autofmt_xdate() if save: pdf = PdfPages( osp.join(path, self.paperPlotInfo["id"] + ".pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() return fig elif author and self.authorPlotInfo is not None: pBLogger.info(isstr.plotAuthor % self.authorPlotInfo["name"]) try: ymin = min( int(self.authorPlotInfo["allLi"][0][0].strftime("%Y")) - 2, int(self.authorPlotInfo["paLi"][0][0].strftime("%Y")) - 2, ) ymax = max( int(self.authorPlotInfo["allLi"][0][-1].strftime("%Y")) + 2, int(self.authorPlotInfo["paLi"][0][-1].strftime("%Y")) + 2, ) except: try: ymin = int( self.authorPlotInfo["paLi"][0][0].strftime("%Y")) - 2 ymax = int( self.authorPlotInfo["paLi"][0][-1].strftime("%Y")) + 2 except: pBLogger.warning(isstr.noPublications) return False figs = [] if len(self.authorPlotInfo["paLi"][0]) > 0: fig, ax = plt.subplots() plt.title(isstr.paperNumber) plt.plot( self.authorPlotInfo["paLi"][0], self.authorPlotInfo["paLi"][1], picker=True, pickradius=pickVal, ) fig.autofmt_xdate() if save: pdf = PdfPages( osp.join(path, self.authorPlotInfo["name"] + "_papers.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) if len(self.authorPlotInfo["paLi"][0]) > 0: fig, ax = plt.subplots() plt.title(isstr.paperYear) ax.hist( [ int(q.strftime("%Y")) for q in self.authorPlotInfo["paLi"][0] ], bins=range(ymin, ymax), picker=True, ) ax.get_xaxis().get_major_formatter().set_useOffset(False) plt.xlim([ymin, ymax]) if save: pdf = PdfPages( osp.join( path, self.authorPlotInfo["name"] + "_yearPapers.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) if len(self.authorPlotInfo["allLi"][0]) > 0: fig, ax = plt.subplots() plt.title(isstr.totalCitations) plt.plot( self.authorPlotInfo["allLi"][0], self.authorPlotInfo["allLi"][1], picker=True, pickradius=pickVal, ) fig.autofmt_xdate() if save: pdf = PdfPages( osp.join(path, self.authorPlotInfo["name"] + "_allCit.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) if len(self.authorPlotInfo["allLi"][0]) > 0: fig, ax = plt.subplots() plt.title(isstr.citationsYear) ax.hist( [ int(q.strftime("%Y")) for q in self.authorPlotInfo["allLi"][0] ], bins=range(ymin, ymax), picker=True, ) ax.get_xaxis().get_major_formatter().set_useOffset(False) plt.xlim([ymin, ymax]) if save: pdf = PdfPages( osp.join(path, self.authorPlotInfo["name"] + "_yearCit.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) if len(self.authorPlotInfo["meanLi"][0]) > 0: fig, ax = plt.subplots() plt.title(isstr.meanCitations) plt.plot( self.authorPlotInfo["meanLi"][0], self.authorPlotInfo["meanLi"][1], picker=True, pickradius=pickVal, ) fig.autofmt_xdate() if markPapers: for q in self.authorPlotInfo["paLi"][0]: plt.axvline( datetime.datetime( int(q.strftime("%Y")), int(q.strftime("%m")), int(q.strftime("%d")), ), color="k", ls="--", ) if save: pdf = PdfPages( osp.join(path, self.authorPlotInfo["name"] + "_meanCit.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) if len(self.authorPlotInfo["aI"].keys()) > 0: fig, ax = plt.subplots() plt.title(isstr.citationsPaper) for i, p in enumerate(self.authorPlotInfo["aI"].keys()): try: plt.plot( self.authorPlotInfo["aI"][p]["citingPapersList"] [0], self.authorPlotInfo["aI"][p]["citingPapersList"] [1], ) except: pBLogger.exception(isstr.errorPlotting) fig.autofmt_xdate() if save: pdf = PdfPages( osp.join(path, self.authorPlotInfo["name"] + "_paperCit.pdf")) pdf.savefig() pdf.close() if show: plt.show() plt.close() figs.append(fig) return figs else: pBLogger.info(isstr.noPlot) return False
def exportForTexFile( self, texFileName, outFileName, overwrite=False, autosave=True, updateExisting=False, removeUnused=False, reorder=False, newOperation=True, ): """Reads a .tex file looking for the \cite{} commands, collects the bibtex entries cited in the text and stores them in a bibtex file. The entries are taken from the database first, or from INSPIRE-HEP if possible. The downloaded entries are saved in the database. Parameters: texFileName: the name (or a list of names) of the considered .tex file(s) outFileName: the name of the output file, where the required entries will be added overwrite (boolean, default False): if True, the previous version of the file is replaced and no backup copy is created autosave (boolean, default True): if True, the changes to the database are automatically saved. updateExisting (boolean, default False): if True, remove duplicates and update entries that have been chenged in the DB removeUnused (boolean, default False): if True, remove bibtex entries that are no more cited in the tex files reorder (boolean, default False): if True, reorder (not update!) the bibtex entries in the bib files before adding the new ones newOperation (boolean, default True): reset the self.existingBibsList and read file .bib content. Time consuming! better to just keep it updated when using multiple texs... Output: True if successful, False if errors occurred """ db = bibtexparser.bibdatabase.BibDatabase() def printOutput( reqBibkeys, miss, retr, nFound, unexp, nKeys, warn, totalCites, full=False ): """Print information on the process""" pBLogger.info(exstr.resume) if totalCites is not None: pBLogger.info(exstr.keysFound % totalCites) pBLogger.info(exstr.newKeysFound % len(reqBibkeys)) j = ", " if full: pBLogger.info(j.join(reqBibkeys)) if len(miss) > 0: pBLogger.info(exstr.missingEntries % len(miss)) if full: pBLogger.info(j.join(miss)) if len(retr) > 0: pBLogger.info(exstr.retrievedEntries % len(retr)) pBLogger.info(j.join(retr)) if len(nFound) > 0: pBLogger.info(exstr.entriesNotFound % len(nFound)) pBLogger.info(j.join(nFound)) if len(unexp) > 0: pBLogger.info(exstr.unexpectedForEntries % len(unexp)) pBLogger.info(j.join(unexp)) if len(nKeys.keys()) > 0: pBLogger.info( exstr.nonMatchingEntries % len(nKeys.keys()) + "\n".join(["'%s' => '%s'" % (k, n) for k, n in nKeys.items()]) ) pBLogger.info(exstr.totalWarnings % warn) def saveEntryOutBib(a, m=None): """Remove unwanted fields and add the bibtex entry to the output file Parameters: a: the bibtex entry m: the ID (bibtex key) of the entry, if it is not the default one """ entry = ( bibtexparser.bparser.BibTexParser(common_strings=True) .parse(a) .entries[0] ) for u in self.unwantedFields: try: del entry[u] except KeyError: pass if m is not None: m = m.strip() if m != entry["ID"].strip(): entry["ID"] = m db.entries = [entry] bibf = pbWriter.write(db) try: with open(outFileName, "a") as o: o.write(bibf) pBLogger.info(exstr.entryInserted % m) except IOError: pBLogger.exception(exstr.errorWrite % outFileName) return False def removeUnusedBibtexs(existingBibsDict): """Functions that reads the list of bibtex entries in the existing .bib file and removes the ones that are not inside \cite commands """ newDict = {} notFound = [] for k, v in existingBibsDict.items(): if k in self.allCitations: newDict[k] = existingBibsDict[k] else: notFound.append(k) db.entries = [ newDict[k] for k in sorted( [e["ID"] for e in newDict.values()], key=lambda s: s.lower() ) ] bibf = pbWriter.write(db) try: with open(outFileName, "w") as o: o.write(exstr.byPhysbiblio + bibf) pBLogger.info(exstr.entriesRemoved % notFound) except IOError: pBLogger.exception(exstr.errorWrite % outFileName) self.exportForTexFlag = True pBLogger.info(exstr.startEFTF) pBLogger.info(exstr.readFrom % texFileName) pBLogger.info(exstr.saveTo % outFileName) if autosave: pBLogger.info(exstr.autoSave) missing = [] newKeys = {} notFound = [] requiredBibkeys = [] retrieved = [] unexpected = [] warnings = 0 totalCites = 0 # if overwrite, reset the output file if overwrite: updateExisting = False removeUnused = False reorder = False try: with open(outFileName, "w") as o: o.write(exstr.byPhysbiblio) except IOError: pBLogger.exception(exstr.cannotWrite) return False # read previous content of output file, if any try: with open(outFileName, "r") as f: existingBibText = f.readlines() except IOError: pBLogger.error(exstr.cannotRead % outFileName) try: open(outFileName, "w").close() except IOError: pBLogger.exception(exstr.cannotCreate % outFileName) return False existingBibText = "" # this is time consuming if there are many entries. # Do not load it every time for multiple texs! if newOperation: self.allCitations = set([]) if existingBibText != "": self.existingBibsList = pBDB.bibs.parseAllBibtexs( existingBibText, verbose=False ) else: self.existingBibsList = [] # work with dictionary, so that if there are repeated entries # (entries with same ID) they are automatically discarded existingBibsDict = CaseInsensitiveDict() for e in self.existingBibsList: existingBibsDict[e["ID"]] = e # if requested, do some cleaning if updateExisting or reorder: # update entry from DB if existing if updateExisting: for k, v in existingBibsDict.items(): e = pBDB.bibs.getByBibtex(k, saveQuery=False) if len(e) > 0 and e[0]["bibtexDict"] != v: existingBibsDict[k] = e[0]["bibtexDict"] if existingBibsDict[k]["ID"].lower() != k.lower(): existingBibsDict[k]["ID"] = k # write new (updated) bib content # (so also repeated entries are removed) db.entries = [ existingBibsDict[k] for k in sorted( [e["ID"] for e in existingBibsDict.values()], key=lambda s: s.lower(), ) ] bibf = pbWriter.write(db) try: with open(outFileName, "w") as o: o.write(exstr.byPhysbiblio + bibf) pBLogger.info(exstr.outputUpdated) except IOError: pBLogger.exception(exstr.errorWrite % outFileName) # if there is a list of tex files, run this function # for each of them...no updateExisting and removeUnused! if isinstance(texFileName, list): if len(texFileName) == 0: return False elif len(texFileName) == 1: texFileName = texFileName[0] else: for t in texFileName: req, m, ret, nF, un, nK, w, cits = self.exportForTexFile( t, outFileName, overwrite=False, autosave=autosave, updateExisting=False, removeUnused=False, reorder=False, newOperation=False, ) requiredBibkeys += req missing += m retrieved += ret notFound += nF unexpected += un for k, v in nK.items(): newKeys[k] = v warnings += w pBLogger.info(exstr.doneAllTexs) if removeUnused: removeUnusedBibtexs(existingBibsDict) printOutput( requiredBibkeys, missing, retrieved, notFound, unexpected, newKeys, warnings, len(self.allCitations), full=True, ) return ( requiredBibkeys, missing, retrieved, notFound, unexpected, newKeys, warnings, len(self.allCitations), ) # read the texFile keyscont = "" try: with open(texFileName) as r: keyscont += r.read() except IOError: pBLogger.exception(exstr.errorNoFile % texFileName) return False # extract \cite* commands matchKeys = "([0-9A-Za-z_\-':\+\.\&]+)" cite = re.compile( "\\\\(cite|citep|citet)\{([\n ]*" + matchKeys + "[,]?[\n ]*)*\}", re.MULTILINE, ) # find \cite{...} citeKeys = re.compile( matchKeys, re.MULTILINE ) # find the keys inside \cite{...} citaz = [m for m in cite.finditer(keyscont) if m != ""] pBLogger.info(exstr.citeFound % len(citaz)) # extract required keys from \cite* commands for c in citaz: try: for e in [l.group(1) for l in citeKeys.finditer(c.group())]: e = e.strip() if e == "" or e in ["cite", "citep", "citet"]: continue self.allCitations.add(e) if e not in requiredBibkeys: try: # this it's just to check if already present tmp = existingBibsDict[e] except KeyError: requiredBibkeys.append(e) except (IndexError, AttributeError, TypeError): pBLogger.warning(exstr.errorCitation % c.group()) a = [] pBLogger.info( exstr.newKeysTotal % (len(requiredBibkeys), len(self.allCitations)) ) # if True, remove unused bibtex entries if removeUnused: removeUnusedBibtexs(existingBibsDict) # check what is missing in the database and insert/import # what is needed: for m in requiredBibkeys: if m.strip() == "": continue entry = pBDB.bibs.getByBibtex(m) entryMissing = len(entry) == 0 if not self.exportForTexFlag: # if flag set, stop execution and # go to the end skipping everything continue elif not entryMissing: # if already in the database, just insert it as it is bibtex = entry[0]["bibtex"] bibtexDict = entry[0]["bibtexDict"] else: # if no entry is found, mark it as missing missing.append(m) # if not present, try INSPIRE import pBLogger.info(exstr.keyMissing % m) newWeb = pBDB.bibs.loadAndInsert(m, returnBibtex=True) newCheck = pBDB.bibs.getByBibtex(m, saveQuery=False) # if the import worked, insert the entry if len(newCheck) > 0: # if key is not matching, # just replace it in the exported bib and print a message if m.strip().lower() != newCheck[0]["bibkey"].lower(): warnings += 1 newKeys[m] = newCheck[0]["bibkey"] if newCheck[0]["bibkey"] not in retrieved: retrieved.append(newCheck[0]["bibkey"]) pBDB.catBib.insert( pbConfig.params["defaultCategories"], newCheck[0]["bibkey"] ) bibtex = newCheck[0]["bibtex"] bibtexDict = newCheck[0]["bibtexDict"] else: # if nothing found, add a warning for the end warnings += 1 notFound.append(m) continue pBLogger.info("\n") # save in output file try: bibtexDict["ID"] = m self.existingBibsList.append(bibtexDict) saveEntryOutBib(bibtex, m) except: unexpected.append(m) pBLogger.exception(exstr.unexpectedEntry % m) if autosave: pBDB.commit() printOutput( requiredBibkeys, missing, retrieved, notFound, unexpected, newKeys, warnings, len(self.allCitations), ) return ( requiredBibkeys, missing, retrieved, notFound, unexpected, newKeys, warnings, len(self.allCitations), )
def addButtons(self, profilesData=None, profileOrder=None, defaultProfile=None): """Read profiles configuration and add `QLineEdits` and buttons for the existing profiles, using previous form content if requested Parameters: profilesData (optional): a dictionary of dictionaries, containing the information of each profile. Each element has the profile name as key, and this structure: "n": profile name "d": description "f": name of the database file "r": True if the profile was marked as default in the form "x": True if the profile was selected for deletion If `None`, use `pbConfig.profiles` profileOrder (optional): the list containing the order of the profiles, by their name in the database. If `None`, use `pbConfig.profileOrder` defaultProfile (optional): the name of the default profile. If `None`, use `pbConfig.defaultProfileName` """ if profilesData is None: profilesData = pbConfig.profiles if profileOrder is None: profileOrder = pbConfig.profileOrder if defaultProfile is None: defaultProfile = pbConfig.defaultProfileName self.def_group = QButtonGroup(self.currGrid) self.elements = [] self.arrows = [] i = 0 j = 0 missing = [] for k in profileOrder: try: prof = profilesData[k] except KeyError: pBLogger.warning(pmstr.missingProfile % (k, sorted(list(profilesData)))) missing.append(k) continue for f in ["db", "d"]: if f not in list(prof): pBLogger.warning(pmstr.missingInfo % (f, sorted(list(prof)))) prof[f] = "" i += 1 tempEl = {} tempEl["r"] = QRadioButton("") self.def_group.addButton(tempEl["r"]) tempEl["r"].setChecked(False) self.currGrid.addWidget(tempEl["r"], i, 0) tempEl["n"] = QLineEdit(k) tempEl["f"] = QLineEdit(prof["db"].split(os.sep)[-1]) tempEl["f"].setReadOnly(True) tempEl["d"] = QLineEdit(prof["d"]) self.currGrid.addWidget(tempEl["n"], i, 1) self.currGrid.addWidget(tempEl["f"], i, 2) self.currGrid.addWidget(tempEl["d"], i, 3) if i > 1: self.arrows.append([ PBOrderPushButton(self, j, QIcon(":/images/arrow-down.png"), ""), PBOrderPushButton(self, j, QIcon(":/images/arrow-up.png"), ""), ]) self.currGrid.addWidget(self.arrows[j][0], i - 1, 5) self.currGrid.addWidget(self.arrows[j][1], i, 4) j += 1 tempEl["x"] = QCheckBox("", self) if "x" in prof.keys() and prof["x"]: tempEl["x"].setChecked(True) self.currGrid.addWidget(tempEl["x"], i, 6) self.elements.append(tempEl) # setChecked the radio of the default profile or # of the previously selected one profileOrder = [k for k in profileOrder if k not in missing] for i, k in enumerate(profileOrder): if defaultProfile == k: self.elements[i]["r"].setChecked(True) for i, k in enumerate(profileOrder): if "r" in profilesData[k].keys() and profilesData[k]["r"]: self.elements[i]["r"].setChecked(True)
def arxivDaily(self, category): """Read daily RSS feed for a given category Parameter: category: the selected category (see `self.categories) """ if "." in category: main, sub = category.split(".") else: main = category sub = "" url = self.urlRss if main not in self.categories.keys(): pBLogger.warning(self.mainCatNotFound % main) return False else: url += main if sub != "" and sub not in self.categories[main]: pBLogger.warning(self.subCatNotFound % sub) return False elif sub != "" and sub in self.categories[main]: url += "." + sub pBLogger.info(url) text = self.textFromUrl(url) if text is None: pBLogger.warning(self.emptyUrl) return False author = re.compile("(>|>)([^/]*)(</a>|</a>)") additionalInfo = re.compile( " \(arXiv:([0-9\.v]*) \[([\-\.a-zA-Z]*)\]([ A-Z]*)\)") if sys.version_info[0] < 3: text = text.decode("utf-8") try: data = feedparser.parse(parse_accents_str(text)) entries = [] for element in data.entries: tmp = {} tmp["eprint"] = element["id"].split("/")[-1] tmp["abstract"] = (element["summary"].replace( "\n", " ").replace("<p>", "").replace("</p>", "")) tmp["authors"] = [ m.group(2) for m in author.finditer(element["authors"][0]["name"]) if m != "" ] tmp["author"] = ( " and ".join(tmp["authors"]) if len(tmp["authors"]) < pbConfig.params["maxAuthorNames"] else " and ".join( tmp["authors"][0:pbConfig.params["maxAuthorNames"]] + ["others"])) tmp["replacement"] = "UPDATED" in element["title"] tmp["primaryclass"] = [ m.group(2) for m in additionalInfo.finditer(element["title"]) if m != "" ][0] tmp["cross"] = ("CROSS LISTED" in element["title"] or category.lower() not in tmp["primaryclass"].lower()) tmp["version"] = [ m.group(1) for m in additionalInfo.finditer(element["title"]) if m != "" ][0] parenthesis = [ m.group() for m in additionalInfo.finditer(element["title"]) if m != "" ][0] tmp["title"] = element["title"].replace(parenthesis, "") entries.append(tmp) return entries except Exception: pBLogger.error(self.cannotParseRSS % text, exc_info=True) return False
def createForm( self, profilesData=None, profileOrder=None, defaultProfile=None, newLine={ "r": False, "n": "", "db": "", "d": "", "c": "None" }, ): """Create the form for managing profiles, using previous form content if requested. Parameters: profilesData (optional): a dictionary of dictionaries, containing the information of each profile. Each element has the profile name as key, and this structure: "n": profile name "d": description "db": name of the database file "r": True if the profile was marked as default in the form "x": True if the profile was selected for deletion If `None`, use `pbConfig.profiles` profileOrder (optional): the list containing the order of the profiles, by their name in the database. If `None`, use `pbConfig.profileOrder` defaultProfile (optional): the name of the default profile. If `None`, use `pbConfig.defaultProfileName` newLine (optional): the content of the line corresponding to the potentially new profile. It is a dictionary with the following fields: "n": profile name "d": description "db": name of the database file "r": True if the profile was marked as default in the form "c": previous content of "Copy from:" """ if profilesData is None: profilesData = pbConfig.profiles if profileOrder is None: profileOrder = pbConfig.profileOrder if defaultProfile is None: defaultProfile = pbConfig.defaultProfileName self.setWindowTitle(pmstr.editProfile) labels = [ PBLabel(bastr.default), PBLabel(bastr.shortName), PBLabel(bastr.filename), PBLabel(bastr.description), ] for i, e in enumerate(labels): self.currGrid.addWidget(e, 0, i) self.currGrid.addWidget(PBLabel(bastr.order), 0, 4, 1, 2) self.currGrid.addWidget(PBLabel(bastr.deleteQ), 0, 6) self.addButtons(profilesData, profileOrder) for f in ["c", "db", "d", "n", "r"]: if f not in newLine.keys(): pBLogger.warning(pmstr.missingField % (f, sorted(list(newLine)))) newLine[f] = "" i = len(profilesData) + 3 self.currGrid.addWidget(PBLabel(""), i - 2, 0) tempEl = {} self.currGrid.addWidget(PBLabel(pmstr.addNew), i - 1, 0) tempEl["r"] = QRadioButton("") self.def_group.addButton(tempEl["r"]) if newLine["r"]: tempEl["r"].setChecked(True) else: tempEl["r"].setChecked(False) self.currGrid.addWidget(tempEl["r"], i, 0) tempEl["n"] = QLineEdit(newLine["n"]) self.currGrid.addWidget(tempEl["n"], i, 1) tempEl["f"] = QComboBox(self) tempEl["f"].setEditable(True) dbFiles = [ f.split(os.sep)[-1] for f in list(glob.iglob(os.path.join(pbConfig.dataPath, "*.db"))) ] registeredDb = sorted( [a["db"].split(os.sep)[-1] for a in profilesData.values()]) tempEl["f"].addItems([newLine["db"]] + [f for f in dbFiles if f not in registeredDb]) self.currGrid.addWidget(tempEl["f"], i, 2) tempEl["d"] = QLineEdit(newLine["d"]) self.currGrid.addWidget(tempEl["d"], i, 3) self.currGrid.addWidget(PBLabel(pmstr.copyFrom), i, 4, 1, 2) tempEl["c"] = QComboBox(self) copyElements = ["None"] + registeredDb tempEl["c"].addItems(copyElements) tempEl["c"].setCurrentIndex( copyElements.index(newLine["c"]) if newLine["c"] in copyElements else 0) self.currGrid.addWidget(tempEl["c"], i, 6) self.elements.append(tempEl) i += 1 self.currGrid.addWidget(PBLabel(""), i, 0) # OK button self.acceptButton = QPushButton(bastr.ok, self) self.acceptButton.clicked.connect(self.onOk) self.currGrid.addWidget(self.acceptButton, i + 1, 1) # cancel button self.cancelButton = QPushButton(bastr.cancel, self) self.cancelButton.clicked.connect(self.onCancel) self.cancelButton.setAutoDefault(True) self.currGrid.addWidget(self.cancelButton, i + 1, 2)