抓取 PyQt 中的任何异常

Grab any exception in PyQt

我在 PyQt 中创建了一个 GUI 应用程序,我想与很多人分享。有时我会遇到意想不到的异常并且我认为这是理所当然的 - 在每次异常之后我都会改进我的代码并且它会变得越来越好。

我使用一个记录器来记录这些异常和 PyQt 静默异常的特殊挂钩。我的代码如下所示:

记录器

def setLogger(level=logging.DEBUG,
              name="my_logger",
              file=join("src", "log.out")):

    logger = logging.getLogger(name)
    logger.setLevel(level)

    # console logger
    ch = logging.StreamHandler()
    console_lvl = logging.DEBUG
    ch.setLevel(console_lvl)
    formatter = logging.Formatter('%(message)s')
    ch.setFormatter(formatter)

    #file logger    
    fh = logging.FileHandler(file)
    fh.setLevel(level)
    formatter = logging.Formatter(
        '%(asctime)s :: %(name)s - %(message)s',
        datefmt='%m/%d/%Y %I:%M:%S %p')
    fh.setFormatter(formatter)
    logger.addHandler(ch)
    logger.addHandler(fh)
    return logger

2 个典型的 class GUI

class MainWindow(QtGui.QMainWindow):

    def __init__(self):
        self.logger = setLogger(name='main_window')
        [...]

class UploadDialog(QtGui.QDialog):

def __init__(self):
    self.logger = setLogger(name='upload_dialog')
    [...]

等等
PyQt 有其沉默的异常 - 异常发生但程序保持 运行。我针对这种情况使用了特殊的钩子(在某处看到过,这不是我的代码)

import sys
sys._excepthook = sys.excepthook

def exception_hook(exctype, value, traceback):
    sys._excepthook(exctype, value, traceback)
    sys.exit(1)

现在我想捕获任何异常,所以我的程序的用户在发生任何崩溃时只需将他们的 log.out 发送给我,我就会看到完整日志。

我是从这样的事情开始的。

try:
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
except Exception:
    logger.exception("MainWindow exception")

我工作得很好,直到 UploadDialog 内部出现异常。什么都没有 'recorded'。所以我只是做了:

#inside MainWindow class
def runDialog(self):
    try:
        dialog = UploadDialog()
        dialog.exec_()
    except Exception:
        self.logger.exception("Dialog exception")
        sys.exit(1)

再次,一切正常,直到 WorkThread 内部出现异常(继承自 QThread class 用于后台上传)。再一次。

#inside UploadDialog
def upload(self):
    # initialized as self.task = WorkThread()
    try:
        self.task.start()
    except Exception:
        self.logger.exception("Exception in WorkThread")

然后不是在 WorkThread 启动之后而是在初始化时引发了异常,所以

class UploadDialog(QtGui.QDialog):

    def __init__(self):
        try:
            self.task = WorkThread()
        except Exception:
            self.logger.exception("Exception in WorkThread")

在这里我只是抬起头对自己尖叫 - "STOP IT. YOU'RE DOING IT WRONG. It's not pythonic, it's dirty, it makes my eyes bleed"。

所以,我想问 - 是否有任何优雅和 pythonic 的方式来绝对捕获在 PyQt 应用程序中用一个 try...except 块引发的任何异常?

使用 excepthook 的目的是让您可以监视 所有 程序引发的异常,并集中处理它们。

所以你应该摆脱大部分 try/except 块,并在 excepthook 函数中记录异常。我说"most",因为你可能会受到bug 1230540, where sys.excepthook is not called correctly outside of the main thread. See the tracker thread for some workarounds for that, or this SO answer的影响。