CrashHandler.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import sys
  2. import platform
  3. import traceback
  4. import webbrowser
  5. import faulthandler
  6. import tempfile
  7. import os
  8. import urllib
  9. from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QCoreApplication
  10. from PyQt5.QtGui import QPixmap
  11. from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QVBoxLayout, QLabel, QTextEdit
  12. from UM.Logger import Logger
  13. from UM.i18n import i18nCatalog
  14. catalog = i18nCatalog("cura")
  15. MYPY = False
  16. if MYPY:
  17. CuraDebugMode = False
  18. else:
  19. try:
  20. from cura.CuraVersion import CuraDebugMode
  21. except ImportError:
  22. CuraDebugMode = False # [CodeStyle: Reflecting imported value]
  23. # List of exceptions that should be considered "fatal" and abort the program.
  24. # These are primarily some exception types that we simply cannot really recover from
  25. # (MemoryError and SystemError) and exceptions that indicate grave errors in the
  26. # code that cause the Python interpreter to fail (SyntaxError, ImportError).
  27. fatal_exception_types = [
  28. MemoryError,
  29. SyntaxError,
  30. ImportError,
  31. SystemError,
  32. ]
  33. def show(exception_type, value, tb):
  34. Logger.log("c", "An uncaught exception has occurred!")
  35. for line in traceback.format_exception(exception_type, value, tb):
  36. for part in line.rstrip("\n").split("\n"):
  37. Logger.log("c", part)
  38. if not CuraDebugMode and exception_type not in fatal_exception_types:
  39. return
  40. application = QCoreApplication.instance()
  41. if not application:
  42. sys.exit(1)
  43. dialog = QDialog()
  44. dialog.setMinimumWidth(640)
  45. dialog.setMinimumHeight(640)
  46. dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
  47. layout = QVBoxLayout(dialog)
  48. #label = QLabel(dialog)
  49. #pixmap = QPixmap()
  50. #try:
  51. # data = urllib.request.urlopen("http://www.randomkittengenerator.com/cats/rotator.php").read()
  52. # pixmap.loadFromData(data)
  53. #except:
  54. # try:
  55. # from UM.Resources import Resources
  56. # path = Resources.getPath(Resources.Images, "kitten.jpg")
  57. # pixmap.load(path)
  58. # except:
  59. # pass
  60. #pixmap = pixmap.scaled(150, 150)
  61. #label.setPixmap(pixmap)
  62. #label.setAlignment(Qt.AlignCenter)
  63. #layout.addWidget(label)
  64. label = QLabel(dialog)
  65. layout.addWidget(label)
  66. #label.setScaledContents(True)
  67. label.setText(catalog.i18nc("@label", """<p>A fatal exception has occurred that we could not recover from!</p>
  68. <p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>
  69. """))
  70. textarea = QTextEdit(dialog)
  71. layout.addWidget(textarea)
  72. try:
  73. from UM.Application import Application
  74. version = Application.getInstance().getVersion()
  75. except:
  76. version = "Unknown"
  77. trace = "".join(traceback.format_exception(exception_type, value, tb))
  78. crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
  79. crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
  80. tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True)
  81. os.close(tmp_file_fd)
  82. with open(tmp_file_path, "w") as f:
  83. faulthandler.dump_traceback(f, all_threads=True)
  84. with open(tmp_file_path, "r") as f:
  85. data = f.read()
  86. msg = "-------------------------\n"
  87. msg += data
  88. crash_info += "\n\n" + msg
  89. textarea.setText(crash_info)
  90. buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)
  91. layout.addWidget(buttons)
  92. buttons.addButton(catalog.i18nc("@action:button", "Open Web Page"), QDialogButtonBox.HelpRole)
  93. buttons.rejected.connect(dialog.close)
  94. buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
  95. dialog.exec_()
  96. sys.exit(1)