恢复 Latex 编译错误 [英] Recovering Latex Compilation Errors

查看:29
本文介绍了恢复 Latex 编译错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I have a program to write a text and when I click on the 'compile' button, it compiles to latex, converts to pdf and displays it on my application. The problem is that when I have a compilation error, the application bugs and that's it. I'd like to know if it's possible to recover compilation errors without the application crashing. I tried with try/expect but it's not a python error so it doesn't work.

You will need PDF.js to view the pdf https://mozilla.github.io/pdf.js/getting_started/#download

Ui :

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(841, 481)
        self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.textEdit = QtWidgets.QTextEdit(Dialog)
        self.textEdit.setMinimumSize(QtCore.QSize(0, 200))
        self.textEdit.setObjectName("textEdit")
        self.gridLayout.addWidget(self.textEdit, 0, 0, 1, 1)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setOrientation(QtCore.Qt.Vertical)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.gridLayout.addWidget(self.buttonBox, 0, 1, 1, 1)
        #self.textEdit_2 = QtWidgets.QTextEdit(Dialog)
        #self.textEdit_2.setObjectName("textEdit_2")
        #self.gridLayout.addWidget(self.textEdit_2, 1, 0, 1, 1)
        self.horizontalLayout.addLayout(self.gridLayout)

        self.retranslateUi(Dialog)
        self.buttonBox.accepted.connect(Dialog.accept)
        self.buttonBox.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))

app:

import os
import sys
from PyQt5.QtWidgets import QDialog, QPushButton, QWidget, QApplication
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
from sympy import Symbol
import untitled

x=Symbol('x')
class Test(QDialog, untitled.Ui_Dialog):
    def __init__(self):
        super(Test, self).__init__()
        self.setupUi(self)

        self.bouton= QPushButton('compile',self)
        self.horizontalLayout.addWidget(self.bouton)
        self.bouton.clicked.connect(self.crertest)

        self.widget = QWidget(self)
        self.gridLayout.addWidget(self.widget, 1, 0, 1, 1)
        self.t = Window()
        lay = QtWidgets.QVBoxLayout(self.widget)
        lay.addWidget(self.t)

    def crertest(self):
        try :
            def preambule(*packages):
                p = ""
                for i in packages:
                    p = p + "\usepackage{" + i + "}
"
                return p
            start = "\documentclass[12pt,a4paper,french]{article}
\usepackage[utf8]{inputenc}
"
            start = start + preambule('amsmath','graphicx')
            start = start + "\begin{document}
"
            end = "\end{document}"
            body = self.textEdit.toPlainText()

            container = start + body + end
            file = "mypdf.tex"
            if os.path.exists(file):
                os.remove(file)
            fichier = open("mypdf.tex", "x")  #
            fichier.write(container)
            fichier.close()

            instructions = "pdflatex " + file
            os.system(instructions)
            readpdf = "START " + file[:-4] + ".pdf"
            self.t.loadd()
        except:
            print('Fail')

PDFJS = 'file:///C:/Users/pdf_js/web/viewer.html' #Path too viewer.htlm in your pddf_js folder
PDF = 'file:///C:/Users/mypdf.pdf' #Path to your pdf


class Window(QtWebEngineWidgets.QWebEngineView):
    def __init__(self):
        super(Window, self).__init__()
        self.loadd()
    try:
        def loadd(self):
            self.load(QtCore.QUrl.fromUserInput('%s?file=%s' % (PDFJS, PDF)))
    except:
        print ('Fail 2')
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Test()
    main.show()
    app.exec_()

I use the code taken from this post for the pdf display : How to render PDF using pdf.js viewer in PyQt?

Exactly like a latex editor like Texmaker does.

Edit.

I put the part of the program that compiles in latex and displays the pdf in another module.

I call the module on my main file, except that I have to compile the program twice to get an update of the display. Sometimes it's after compiling 3/4 times that the bug appeared. I need to add something to run it once ?

compile : test.py

import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets


CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
TMP_DIR = os.path.join(CURRENT_DIR, "tmp")
PDFJS = os.path.join(CURRENT_DIR, "3rdParty/pdfjs-2.2.228-dist/web/viewer.html")


def create_document(content, packages):
    lines = (
        r"documentclass[12pt,a4paper,french]{article}",
        r"usepackage[utf8]{inputenc}",
        *(r"usepackage {%s}" % (package,) for package in packages),
        r"egin{document}",
        content,
        r"end{document}",
    )
    return "
".join(lines)


class PdfViewer(QtWebEngineWidgets.QWebEngineView):
    def load_pdf(self, filename):
        url = QtCore.QUrl.fromUserInput(
            "%s?file=%s" % (QtCore.QUrl.fromLocalFile(PDFJS).toString(), filename)
        )
        self.load(url)


class Compile:
    def __init__(self, parent):
        super().__init__()
        self.process = QtCore.QProcess(parent)
        self.process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)
        self.process.finished.connect(self.on_finished)
        self.process.setProgram("pdflatex")

        self.basename = "mypdf"

    def compile(self,body):
        doc = create_document(body, ("amsmath", "graphicx"))
        QtCore.QDir().mkpath(TMP_DIR)
        self.qfile = QtCore.QFile(os.path.join(TMP_DIR, self.basename + ".tex"))
        if self.qfile.open(QtCore.QIODevice.WriteOnly):
            self.qfile.write(doc.encode())
            self.qfile.close()

        self.process.setArguments(
            [
                "-interaction=nonstopmode",
                "-jobname={}".format(self.basename),
                "-output-directory={}".format(TMP_DIR),
                self.qfile.fileName(),
            ]
        )
        self.process.start()

    def on_readyReadStandardOutput(self):
        print(self.process.readAllStandardOutput().data().decode(), end='')

    def on_finished(self):
        self.qfile.remove()

call with :

import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
import test


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.input = QtWidgets.QTextEdit()
        self.input.setText('.')

        self.a = test.Compile(self)
        self.a.compile('.')
        self.b = test.PdfViewer()
        self.b.load_pdf(your PDF path)

        compile_button = QtWidgets.QPushButton(self.tr("Compile"))

        lay = QtWidgets.QGridLayout(self)
        lay.addWidget(compile_button, 0, 0, 1, 2)
        lay.addWidget(self.input, 1, 0)
        lay.addWidget(self.b, 1, 1)
        lay.setColumnStretch(0, 1)
        lay.setColumnStretch(1, 1)

        compile_button.clicked.connect(self.call)

    def call(self):
        self.a.compile(self.input.toPlainText())
        self.b.load_pdf(your PDF path)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.showMaximized()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

解决方案

It is difficult to know the error of your problem since there can be many causes so I have created my example from scratch. To do this you must have the following file structure: At the side of the script there must be a folder called 3rdParty where you must unzip the file downloaded from PDF.js.

├── 3rdParty
│   └── pdfjs-2.2.228-dist
│       ├── build
│       │   ├── pdf.js
│       │   ├── pdf.js.map
│       │   ├── pdf.worker.js
│       │   └── pdf.worker.js.map
│       ├── LICENSE
│       └── web
│           ├── cmaps
│           ├── compressed.tracemonkey-pldi-09.pdf
│           ├── debugger.js
│           ├── images
│           ├── locale
│           ├── viewer.css
│           ├── viewer.html
│           ├── viewer.js
│           └── viewer.js.map
├── main.py
└── tmp

Instead of using os.system () it is better to use a method that gives feedback on the state of the conversion, in this case use QProcess, in addition to adding more options such as "-interaction=nonstopmode", "-jobname=FILENAME" and "-output-directory=DIR" that allow that there is no interactive mode, point to the folder Output and name of pdf:

import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
TMP_DIR = os.path.join(CURRENT_DIR, "tmp")
PDFJS = os.path.join(CURRENT_DIR, "3rdParty/pdfjs-2.2.228-dist/web/viewer.html")


def create_document(content, packages):
    lines = (
        r"documentclass[12pt,a4paper,french]{article}",
        r"usepackage[utf8]{inputenc}",
        *(r"usepackage {%s}" % (package,) for package in packages),
        r"egin{document}",
        content,
        r"end{document}",
    )
    return "
".join(lines)


class PdfViewer(QtWebEngineWidgets.QWebEngineView):
    def load_pdf(self, filename):
        url = QtCore.QUrl.fromUserInput(
            "%s?file=%s" % (QtCore.QUrl.fromLocalFile(PDFJS).toString(), filename)
        )
        self.load(url)


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.input = QtWidgets.QTextEdit()
        self.output = PdfViewer()

        compile_button = QtWidgets.QPushButton(self.tr("Compile"))

        lay = QtWidgets.QGridLayout(self)
        lay.addWidget(compile_button, 0, 0, 1, 2)
        lay.addWidget(self.input, 1, 0)
        lay.addWidget(self.output, 1, 1)
        lay.setColumnStretch(0, 1)
        lay.setColumnStretch(1, 1)

        compile_button.clicked.connect(self.compile)

        self.process = QtCore.QProcess(self)
        self.process.readyReadStandardError.connect(self.on_readyReadStandardError)
        self.process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)
        self.process.finished.connect(self.on_finished)
        self.process.setProgram("pdflatex")

        self.basename = "mypdf"

    def compile(self):
        doc = create_document(self.input.toPlainText(), ("amsmath", "graphicx"))
        QtCore.QDir().mkpath(TMP_DIR)
        self.qfile = QtCore.QFile(os.path.join(TMP_DIR, self.basename + ".tex"))
        if self.qfile.open(QtCore.QIODevice.WriteOnly):
            self.qfile.write(doc.encode())
            self.qfile.close()

        self.process.setArguments(
            [
                "-interaction=nonstopmode",
                "-jobname={}".format(self.basename),
                "-output-directory={}".format(TMP_DIR),
                self.qfile.fileName(),
            ]
        )
        self.process.start()

    def on_readyReadStandardError(self):
        print(self.process.readAllStandardError().data().decode(), end='')

    def on_readyReadStandardOutput(self):
        print(self.process.readAllStandardOutput().data().decode(), end='')

    def on_finished(self):
        self.qfile.remove()
        pdf_filename = os.path.join(TMP_DIR, self.basename + ".pdf")
        self.output.load_pdf(pdf_filename)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.showMaximized()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

Note: try-except only handles the exceptions (not errors) thrown by the python code, not by other programs such as pdflatex. In the case of QProcess the readyReadStandardOutput and readyReadStandardError signal notifies if there is stdout and stderr information from the program(in this case pdflatex), respectively and can be retrieved using the readAllStandardOutput() and readAllStandardError() methods, respectively. That information is printed on the console

这篇关于恢复 Latex 编译错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆