Allow console to display any frame stack (even without an exception)

This commit is contained in:
Luke Campagnola 2017-09-13 20:50:31 -07:00
parent 8d730f07d9
commit 0517665473
4 changed files with 71 additions and 27 deletions

View File

@ -53,6 +53,7 @@ class ConsoleWidget(QtGui.QWidget):
self.editor = editor
self.multiline = None
self.inCmd = False
self.frames = [] # stack frames to access when an item in the stack list is selected
self.ui = template.Ui_Form()
self.ui.setupUi(self)
@ -133,14 +134,14 @@ class ConsoleWidget(QtGui.QWidget):
def globals(self):
frame = self.currentFrame()
if frame is not None and self.ui.runSelectedFrameCheck.isChecked():
return self.currentFrame().tb_frame.f_globals
return self.currentFrame().f_globals
else:
return self.localNamespace
def locals(self):
frame = self.currentFrame()
if frame is not None and self.ui.runSelectedFrameCheck.isChecked():
return self.currentFrame().tb_frame.f_locals
return self.currentFrame().f_locals
else:
return self.localNamespace
@ -149,10 +150,7 @@ class ConsoleWidget(QtGui.QWidget):
if self.currentTraceback is None:
return None
index = self.ui.exceptionStackList.currentRow()
tb = self.currentTraceback
for i in range(index):
tb = tb.tb_next
return tb
return self.frames[index]
def execSingle(self, cmd):
try:
@ -171,7 +169,6 @@ class ConsoleWidget(QtGui.QWidget):
except:
self.displayException()
def execMulti(self, nextLine):
#self.stdout.write(nextLine+"\n")
if nextLine.strip() != '':
@ -202,6 +199,10 @@ class ConsoleWidget(QtGui.QWidget):
self.multiline = None
def write(self, strn, html=False):
isGuiThread = QtCore.QThread.currentThread() == QtCore.QCoreApplication.instance().thread()
if not isGuiThread:
self.stdout.write(strn)
return
self.output.moveCursor(QtGui.QTextCursor.End)
if html:
self.output.textCursor().insertHtml(strn)
@ -293,14 +294,6 @@ class ConsoleWidget(QtGui.QWidget):
fileName = tb.tb_frame.f_code.co_filename
subprocess.Popen(self.editor.format(fileName=fileName, lineNum=lineNum), shell=True)
#def allExceptionsHandler(self, *args):
#self.exceptionHandler(*args)
#def nextExceptionHandler(self, *args):
#self.ui.catchNextExceptionBtn.setChecked(False)
#self.exceptionHandler(*args)
def updateSysTrace(self):
## Install or uninstall sys.settrace handler
@ -319,7 +312,7 @@ class ConsoleWidget(QtGui.QWidget):
else:
sys.settrace(self.systrace)
def exceptionHandler(self, excType, exc, tb):
def exceptionHandler(self, excType, exc, tb, systrace=False):
if self.ui.catchNextExceptionBtn.isChecked():
self.ui.catchNextExceptionBtn.setChecked(False)
elif not self.ui.catchAllExceptionsBtn.isChecked():
@ -330,13 +323,60 @@ class ConsoleWidget(QtGui.QWidget):
excMessage = ''.join(traceback.format_exception_only(excType, exc))
self.ui.exceptionInfoLabel.setText(excMessage)
if systrace:
# exceptions caught using systrace don't need the usual
# call stack + traceback handling
self.setStack(sys._getframe().f_back.f_back)
else:
self.setStack(frame=sys._getframe().f_back, tb=tb)
def setStack(self, frame=None, tb=None):
"""Display a call stack and exception traceback.
This allows the user to probe the contents of any frame in the given stack.
*frame* may either be a Frame instance or None, in which case the current
frame is retrieved from ``sys._getframe()``.
If *tb* is provided then the frames in the traceback will be appended to
the end of the stack list. If *tb* is None, then sys.exc_info() will
be checked instead.
"""
if frame is None:
frame = sys._getframe().f_back
if tb is None:
tb = sys.exc_info()[2]
self.ui.exceptionStackList.clear()
self.frames = []
# Build stack up to this point
for index, line in enumerate(traceback.extract_stack(frame)):
self.ui.exceptionStackList.addItem('File "%s", line %s, in %s()\n %s' % line)
while frame is not None:
self.frames.insert(0, frame)
frame = frame.f_back
if tb is None:
return
self.ui.exceptionStackList.addItem('-- exception caught here: --')
item = self.ui.exceptionStackList.item(self.ui.exceptionStackList.count()-1)
item.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
self.frames.append(None)
# And finish the rest of the stack up to the exception
for index, line in enumerate(traceback.extract_tb(tb)):
self.ui.exceptionStackList.addItem('File "%s", line %s, in %s()\n %s' % line)
while tb is not None:
self.frames.append(tb.tb_frame)
tb = tb.tb_next
def systrace(self, frame, event, arg):
if event == 'exception' and self.checkException(*arg):
self.exceptionHandler(*arg)
self.exceptionHandler(*arg, systrace=True)
return self.systrace
def checkException(self, excType, exc, tb):

View File

@ -86,7 +86,10 @@
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<property name="horizontalSpacing">
<number>2</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="6">
@ -95,7 +98,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>Clear Exception</string>
<string>Clear Stack</string>
</property>
</widget>
</item>
@ -149,7 +152,7 @@
<item row="1" column="0" colspan="7">
<widget class="QLabel" name="exceptionInfoLabel">
<property name="text">
<string>Exception Info</string>
<string>Stack Trace</string>
</property>
</widget>
</item>

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'template.ui'
#
# Created: Fri May 02 18:55:28 2014
# Created: Wed Apr 08 16:28:53 2015
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@ -68,8 +68,9 @@ class Ui_Form(object):
self.exceptionGroup = QtGui.QGroupBox(self.splitter)
self.exceptionGroup.setObjectName(_fromUtf8("exceptionGroup"))
self.gridLayout_2 = QtGui.QGridLayout(self.exceptionGroup)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setContentsMargins(-1, 0, -1, 0)
self.gridLayout_2.setHorizontalSpacing(2)
self.gridLayout_2.setVerticalSpacing(0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.clearExceptionBtn = QtGui.QPushButton(self.exceptionGroup)
self.clearExceptionBtn.setEnabled(False)
@ -116,12 +117,12 @@ class Ui_Form(object):
self.historyBtn.setText(_translate("Form", "History..", None))
self.exceptionBtn.setText(_translate("Form", "Exceptions..", None))
self.exceptionGroup.setTitle(_translate("Form", "Exception Handling", None))
self.clearExceptionBtn.setText(_translate("Form", "Clear Exception", None))
self.clearExceptionBtn.setText(_translate("Form", "Clear Stack", None))
self.catchAllExceptionsBtn.setText(_translate("Form", "Show All Exceptions", None))
self.catchNextExceptionBtn.setText(_translate("Form", "Show Next Exception", None))
self.onlyUncaughtCheck.setText(_translate("Form", "Only Uncaught Exceptions", None))
self.runSelectedFrameCheck.setText(_translate("Form", "Run commands in selected stack frame", None))
self.exceptionInfoLabel.setText(_translate("Form", "Exception Info", None))
self.exceptionInfoLabel.setText(_translate("Form", "Stack Trace", None))
self.label.setText(_translate("Form", "Filter (regex):", None))
from .CmdInput import CmdInput

View File

@ -100,7 +100,7 @@ class Ui_Form(object):
self.catchNextExceptionBtn.setText(QtGui.QApplication.translate("Form", "Show Next Exception", None, QtGui.QApplication.UnicodeUTF8))
self.onlyUncaughtCheck.setText(QtGui.QApplication.translate("Form", "Only Uncaught Exceptions", None, QtGui.QApplication.UnicodeUTF8))
self.runSelectedFrameCheck.setText(QtGui.QApplication.translate("Form", "Run commands in selected stack frame", None, QtGui.QApplication.UnicodeUTF8))
self.exceptionInfoLabel.setText(QtGui.QApplication.translate("Form", "Exception Info", None, QtGui.QApplication.UnicodeUTF8))
self.clearExceptionBtn.setText(QtGui.QApplication.translate("Form", "Clear Exception", None, QtGui.QApplication.UnicodeUTF8))
self.exceptionInfoLabel.setText(QtGui.QApplication.translate("Form", "Stack Trace", None, QtGui.QApplication.UnicodeUTF8))
self.clearExceptionBtn.setText(QtGui.QApplication.translate("Form", "Clear Stack", None, QtGui.QApplication.UnicodeUTF8))
from .CmdInput import CmdInput