summaryrefslogtreecommitdiff
path: root/raphodo/excepthook.py
blob: 8c75839d7c745dc531c5290d916186d7bce72038 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# Copyright (C) 2016 Damon Lynch <damonlynch@gmail.com>

# This file is part of Rapid Photo Downloader.
#
# Rapid Photo Downloader is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Rapid Photo Downloader is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Rapid Photo Downloader. If not,
# see <http://www.gnu.org/licenses/>.

import logging
import traceback
import io
import os
from urllib.request import pathname2url
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QApplication
from PyQt5.QtGui import QPixmap
try:
    from easygui import codebox
    have_easygui = True
except:
    # if import failed for any reason, ignore it
    have_easygui = False

from gettext import gettext as _
import raphodo.qrc_resources as qrc_resources

from raphodo.iplogging import full_log_file_path

message_box_displayed = False
exceptions_notified = set()


def excepthook(exception_type, exception_value, traceback_object) -> None:
    """
    Global function to catch unhandled exceptions.

    Inspired by function of the same name in the Eric project.
    """

    if traceback_object is not None:
        frame = traceback_object.tb_frame
        filename = frame.f_code.co_filename
        lineno = traceback_object.tb_lineno
    else:
        lineno = -1
        filename = 'unknown'
    key = '{}{}'.format(filename, lineno)

    global message_box_displayed

    tb_file = io.StringIO()
    traceback.print_exception(exception_type, exception_value, traceback_object,
                              limit=None, file=tb_file)
    tb_file.seek(0)
    traceback_info = tb_file.read()

    logging.error("An unhandled exception occurred")
    logging.error(traceback_info)

    if not message_box_displayed and key not in exceptions_notified:
        message_box_displayed = True
        exceptions_notified.add(key)

        log_path, log_file = os.path.split(full_log_file_path())
        log_uri = pathname2url(log_path)

        title = _("Problem in Rapid Photo Downloader")

        if QApplication.instance():

            message = _(r"""<b>A problem occurred in Rapid Photo Downloader</b><br><br>
    Please report the problem at <a href="{website}">{website}</a>.<br><br>
    Attach the log file <i>{log_file}</i> to your bug report (click
    <a href="{log_path}">here</a> to open the log directory).<br><br>If the same problem occurs
    again before the program exits, this is the only notification about it.
    """).format(website='https://bugs.launchpad.net/rapid', log_path=log_uri, log_file=log_file)

            icon = QPixmap(':/rapid-photo-downloader.svg')

            errorbox = QMessageBox()
            errorbox.setTextFormat(Qt.RichText)
            errorbox.setIconPixmap(icon)
            errorbox.setWindowTitle(title)
            errorbox.setText(message)
            errorbox.setDetailedText(traceback_info)
            errorbox.exec_()
        elif have_easygui:
            message = _('A problem occurred in Rapid Photo Downloader\n')
            prefix = _("""Please report the problem at {website}\n
    Attach the log file to your bug report, found at {log_path}\n\n""").format(
                website='https://bugs.launchpad.net/rapid', log_path=full_log_file_path())
            text = prefix + traceback_info
            codebox(msg=message, title=title, text=text)
        message_box_displayed = False