from traceback import extract_tb, format_exception_only from PyQt5.QtWidgets import (QWidget, QTreeWidget, QTreeWidgetItem, QAction, QLabel) from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal from ..mixins import ComponentMixin from ..utils import layout class TracebackTree(QTreeWidget): name = 'Traceback Viewer' def __init__(self,parent): super(TracebackTree,self).__init__(parent) self.setHeaderHidden(False) self.setItemsExpandable(False) self.setRootIsDecorated(False) self.setContextMenuPolicy(Qt.ActionsContextMenu) self.setColumnCount(3) self.setHeaderLabels(['File','Line','Code']) self.root = self.invisibleRootItem() class TracebackPane(QWidget,ComponentMixin): sigHighlightLine = pyqtSignal(int) def __init__(self,parent): super(TracebackPane,self).__init__(parent) self.tree = TracebackTree(self) self.current_exception = QLabel(self) self.current_exception.setStyleSheet(\ "QLabel {color : red; }"); layout(self, (self.current_exception, self.tree), self) self.tree.currentItemChanged.connect(self.handleSelection) @pyqtSlot(object,str) def addTraceback(self,exc_info,code): self.tree.clear() if exc_info: t,exc,tb = exc_info root = self.tree.root code = code.splitlines() tb = [t for t in extract_tb(tb) if '' in t.filename] #ignore highest frames (debug, exec) for el in tb: #workaround of the traceback module if el.line == '': line = code[el.lineno-1].strip() else: line = el.line root.addChild(QTreeWidgetItem([el.filename, str(el.lineno), line])) exc_name = t.__name__ exc_msg = str(exc) exc_msg = exc_msg.replace('<', '<').replace('>', '>') #replace <> self.current_exception.\ setText('{}: {}'.format(exc_name,exc_msg)) # handle the special case of a SyntaxError if t is SyntaxError: root.addChild(QTreeWidgetItem( [exc.filename, str(exc.lineno), exc.text.strip() if exc.text else ''] )) else: self.current_exception.setText('') @pyqtSlot(QTreeWidgetItem,QTreeWidgetItem) def handleSelection(self,item,*args): if item: f,line = item.data(0,0),int(item.data(1,0)) if '' in f: self.sigHighlightLine.emit(line)