示例#1
0
    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
示例#2
0
    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))
示例#3
0
    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
示例#4
0
    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)
示例#5
0
 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
示例#6
0
 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 []
示例#7
0
    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
示例#8
0
    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
示例#9
0
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
示例#10
0
    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 ""
示例#11
0
    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]
示例#12
0
 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,
         )
示例#13
0
    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))
示例#14
0
    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)
示例#15
0
 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 != ""]
示例#16
0
    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
示例#17
0
    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),
        )
示例#18
0
    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)
示例#19
0
    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("(>|&gt;)([^/]*)(</a>|&lt;/a&gt;)")
        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
示例#20
0
    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)