class ConsoleWidget(QWidget): def __init__(self, exc_info, parent=None): QWidget.__init__(self, parent) self.compiler = code.CommandCompiler() # for console self.tb = exc_info[2] self.entries = traceback.extract_tb(self.tb) self.console = QLineEdit() self.console.setPlaceholderText(">>> Python Console") self.console.returnPressed.connect(self.exec_console) self.console.setFont(QFont("Courier")) self.console_out = QTextEdit() self.console_out.setReadOnly(True) self.console_out.setFont(QFont("Courier")) self.console_out.setVisible(False) # initially hidden self.console_outs = [''] * len(self.entries) self.frame_vars = [None] * len(self.entries) l = QVBoxLayout() l.addWidget(self.console_out) l.addWidget(self.console) l.setContentsMargins(0, 0, 0, 0) self.setLayout(l) def go_to_frame(self, index): self.console_out.setPlainText(self.console_outs[index]) self.current_frame_index = index def exec_console(self): index = self.current_frame_index if index < 0: return # cache frame variables (globals and locals) # because every time we ask for frame.f_locals, a new dict instance # is created - we keep our local cache that may contain some changes if self.frame_vars[index] is None: #print "init", index frame = frame_from_traceback(self.tb, index) self.frame_vars[index] = (dict(frame.f_globals), dict(frame.f_locals)) frame_vars = self.frame_vars[index] #print frame_vars[1] line = self.console.text() try: c = self.compiler(line, "<console>", "single") except (OverflowError, SyntaxError, ValueError) as e: QMessageBox.critical(self, "Error", str(e)) return if c is None: QMessageBox.critical(self, "Error", "Code not complete") return import io io = io.StringIO() if sys.version_info.major >= 3 else io.BytesIO() try: with stdout_redirected(io): exec(c, frame_vars[0], frame_vars[1]) except: etype, value, tb = sys.exc_info() QMessageBox.critical(self, "Error", etype.__name__ + "\n" + str(value)) return stuff = self.console_outs[index] stuff += ">>> " + line + "\n" stuff += io.getvalue() self.console_outs[index] = stuff self.console_out.setPlainText(stuff) self.console_out.setVisible(True) # make sure we are at the end c = self.console_out.textCursor() c.movePosition(QTextCursor.End) self.console_out.setTextCursor(c) self.console_out.ensureCursorVisible() self.console.setText('')