class PyConsoleTextEdit(ConsoleTextEdit): _color_stdin = Qt.darkGreen _multi_line_char = ':' _multi_line_indent = ' ' _prompt = ('>>> ', '... ') # prompt for single and multi line exit = Signal() def __init__(self, parent=None): super(PyConsoleTextEdit, self).__init__(parent) self._interpreter_locals = {} self._interpreter = InteractiveInterpreter(self._interpreter_locals) self._comment_writer.write( 'Python %s on %s\n' % (sys.version.replace('\n', ''), sys.platform)) self._comment_writer.write('Qt bindings: %s version %s\n' % (QT_BINDING, QT_BINDING_VERSION)) self._add_prompt() def update_interpreter_locals(self, newLocals): self._interpreter_locals.update(newLocals) def _exec_code(self, code): try: self._interpreter.runsource(code) except SystemExit: # catch sys.exit() calls, so they don't close the whole gui self.exit.emit()
class PyConsoleTextEdit(ConsoleTextEdit): _color_stdin = Qt.darkGreen _multi_line_char = ':' _multi_line_indent = ' ' _prompt = ('>>> ', '... ') # prompt for single and multi line exit = Signal() def __init__(self, parent=None): super(PyConsoleTextEdit, self).__init__(parent) self._interpreter_locals = {} self._interpreter = InteractiveInterpreter(self._interpreter_locals) self._comment_writer.write('Python %s on %s\n' % (sys.version.replace('\n', ''), sys.platform)) self._comment_writer.write('Qt bindings: %s version %s\n' % (QT_BINDING, QT_BINDING_VERSION)) self._add_prompt() def update_interpreter_locals(self, newLocals): self._interpreter_locals.update(newLocals) def _exec_code(self, code): try: self._interpreter.runsource(code) except SystemExit: # catch sys.exit() calls, so they don't close the whole gui self.exit.emit()
class MyWindow(QtGui.QWidget): def __init__(self, parent=None): super(MyWindow, self).__init__(parent=parent) self.newshell = True self.stmt = True self.construct = False self.initUI() self.index = 0 self.interpreter = InteractiveInterpreter() def initUI(self): self.sh = QtGui.QTextEdit( ''' Python 2.7.6 on linux2 ** DO NOT DELETE SHELL PROMPT! ** >>> ''', self) self.sh.textChanged.connect(self.shellop) self.sh.setReadOnly(True) self.sh.setReadOnly(False) def shellop(self): self.index += 1 if self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[ self.index - 1] == ":": self.stmt = False self.construct = True elif self.sh.toPlainText()[self.index] == "\n" and not self.construct: self.stmt = not self.stmt class stdoutProxy: def write(self, s): self.sh.insertPlainText(s) stdout = sys.stdout sys.stdout = stdoutProxy() self.interpreter.runsource(self.sh.toPlainText()) self.sh.insertPlainText("\n") self.index += 1 while self.interpreter.showtraceback(): print self.interpreter.showtraceback() sys.stdout = stdout if self.sh.toPlainText()[ self.index] == "\n" and not self.construct and not self.stmt: self.stmt = not self.stmt self.sh.insertPlainText(">>> ") self.index += 4 if self.construct and self.sh.toPlainText( )[self.index] == "\n" and self.sh.toPlainText()[self.index - 1] == " ": self.construct = False self.sh.insertPlainText(">>> ") self.index += 4 if self.construct: self.sh.insertPlainText("... ") index += 4
class MyWindow(QtGui.QWidget): def __init__(self, parent=None): super(MyWindow, self).__init__(parent=parent) self.newshell = True self.stmt = True self.construct = False self.initUI() self.index = 0 self.interpreter = InteractiveInterpreter() def initUI(self): self.sh = QtGui.QTextEdit(''' Python 2.7.6 on linux2 ** DO NOT DELETE SHELL PROMPT! ** >>> ''', self) self.sh.textChanged.connect(self.shellop) self.sh.setReadOnly(True) self.sh.setReadOnly(False) def shellop(self): self.index += 1 if self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[self.index-1] == ":": self.stmt = False self.construct = True elif self.sh.toPlainText()[self.index] == "\n" and not self.construct: self.stmt = not self.stmt class stdoutProxy: def write(self, s): self.sh.insertPlainText(s) stdout = sys.stdout sys.stdout = stdoutProxy() self.interpreter.runsource(self.sh.toPlainText()) self.sh.insertPlainText("\n") self.index += 1 while self.interpreter.showtraceback(): print self.interpreter.showtraceback() sys.stdout = stdout if self.sh.toPlainText()[self.index] == "\n" and not self.construct and not self.stmt: self.stmt = not self.stmt self.sh.insertPlainText(">>> ") self.index += 4 if self.construct and self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[self.index-1] == " ": self.construct = False self.sh.insertPlainText(">>> ") self.index += 4 if self.construct: self.sh.insertPlainText("... ") index += 4
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr # more = InteractiveInterpreter.runsource(self, source) # this was a cute idea, but didn't work... #more = self.runcode(compile(source,'', # ('exec' if self.useExecMode else 'single'))) more = False if not self.socket: if not source.startswith("connect"): print("Type \"connect(ip, port)\" to connect the game client") else: more = InteractiveInterpreter.runsource(self, source) else: more = self.rmt_run(source) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin else: self.stdin = sys.stdin if sys.stdout == self.stdout: sys.stdout = stdout else: self.stdout = sys.stdout if sys.stderr == self.stderr: sys.stderr = stderr else: self.stderr = sys.stderr return more
def Interpreter_runsource(self, source): from code import InteractiveInterpreter # Horrible hack - if there are newlines # in the source, compile it as 'exec', # otherwise compile it as 'single' if source.find('\n') > -1: symbol = 'exec' else: symbol = 'single' stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr more = InteractiveInterpreter.runsource(self, source, symbol=symbol) # this was a cute idea, but didn't work... # more = self.runcode(compile(source,'', # ('exec' if self.useExecMode else 'single'))) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin else: self.stdin = sys.stdin if sys.stdout == self.stdout: sys.stdout = stdout else: self.stdout = sys.stdout if sys.stderr == self.stderr: sys.stderr = stderr else: self.stderr = sys.stderr return more
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr # more = InteractiveInterpreter.runsource(self, source) # this was a cute idea, but didn't work... #more = self.runcode(compile(source,'', # ('exec' if self.useExecMode else 'single'))) more = False if not self.socket: if not source.startswith("connect"): print("Type \"connect(ip, port)\" to connect the game client") else: more = InteractiveInterpreter.runsource(self, source) else: more = self.rmt_run(source) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin else: self.stdin = sys.stdin if sys.stdout == self.stdout: sys.stdout = stdout else: self.stdout = sys.stdout if sys.stderr == self.stderr: sys.stderr = stderr else: self.stderr = sys.stderr return more
def push(self, line, filename='<input>'): ''' Execute a command string in the child shell. Returns STDOUT/STDERR tuple. ''' # Redirect STDOUT/STDERR to our custom cache. sys.stdout = self.stdout_cache sys.stderr = self.stderr_cache # Filter input here (if required). # Execute line. r = InteractiveInterpreter.runsource(self, line, filename) # Custom cache will have taken all STDOUT/STDERR so now put it back to # allow other stuff to use STDOUT/STDERR. sys.stdout = self.stdout sys.stderr = self.stderr # Take all the output snarffed from STDOUT/STDERR. output = self.stdout_cache.flush() error = self.stderr_cache.flush() # Filter output here (if required). return output, error
def runsource(self,source): self.get_output() more = InteractiveInterpreter.runsource(self,source) self.return_output() output = self.out_cache.flush() errors = self.err_cache.flush() return more,errors,output
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr more = InteractiveInterpreter.runsource(self, source) # this was a cute idea, but didn't work... #more = self.runcode(compile(source,'', # ('exec' if self.useExecMode else 'single'))) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin else: self.stdin = sys.stdin if sys.stdout == self.stdout: sys.stdout = stdout else: self.stdout = sys.stdout if sys.stderr == self.stderr: sys.stderr = stderr else: self.stderr = sys.stderr return more
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr more = InteractiveInterpreter.runsource(self, source) # this was a cute idea, but didn't work... #more = self.runcode(compile(source,'', # ('exec' if self.useExecMode else 'single'))) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin else: self.stdin = sys.stdin if sys.stdout == self.stdout: sys.stdout = stdout else: self.stdout = sys.stdout if sys.stderr == self.stderr: sys.stderr = stderr else: self.stderr = sys.stderr return more
def runsource(self, source): # Extend base class to stuff the source in the line cache filename = "<pyshell#%d>" % self.gid self.gid = self.gid + 1 lines = string.split(source, "\n") linecache.cache[filename] = len(source)+1, 0, lines, filename self.more = 0 return InteractiveInterpreter.runsource(self, source, filename)
def runsource(self, source): stdout, stderr = sys.stdout, sys.stderr sys.stdout = FauxFile(self, _stdout_style) sys.stderr = FauxFile(self, _stderr_style) more = InteractiveInterpreter.runsource(self, source) sys.stdout, sys.stderr = stdout, stderr return more
def runsource(self, source): # Extend base class to stuff the source in the line cache first filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) try: return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
def main(): """ Print lines of input along with output. """ source_lines = (line.rstrip() for line in sys.stdin) console = InteractiveInterpreter() source = '' try: while True: source = source_lines.next() print '>>>', source more = console.runsource(source) while more: next_line = source_lines.next() print '...', next_line source += '\n' + next_line more = console.runsource(source) except StopIteration: if more: print '... ' more = console.runsource(source + '\n')
def runsource(self, source): # Extend base class to stuff the source in the line cache first filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) try: return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
def main(): """ Print lines of input along with output. """ source_lines = (line.rstrip() for line in sys.stdin) console = InteractiveInterpreter() console.runsource("import turicreate") source = "" try: while True: source = source_lines.next() more = console.runsource(source) while more: next_line = source_lines.next() print "...", next_line source += "\n" + next_line more = console.runsource(source) except StopIteration: if more: print "... " more = console.runsource(source + "\n")
def main(): """ Print lines of input along with output. """ source_lines = (line.rstrip() for line in sys.stdin) console = InteractiveInterpreter() console.runsource('import graphlab') source = '' try: while True: source = source_lines.next() more = console.runsource(source) while more: next_line = source_lines.next() print '...', next_line source += '\n' + next_line more = console.runsource(source) except StopIteration: if more: print '... ' more = console.runsource(source + '\n')
def main(): """ Print lines of input along with output. """ source_lines = (line.rstrip() for line in sys.stdin) console = InteractiveInterpreter() source = '' try: while True: source = next(source_lines) print('>>>', source) more = console.runsource(source) while more: next_line = next(source_lines) print('...', next_line) source += '\n' + next_line more = console.runsource(source) except StopIteration: if more: print('... ') more = console.runsource(source + '\n')
def runsource(self, source): """Extend base class method: Stuff the source in the line cache first""" filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action='error', category=SyntaxWarning) assert isinstance(source, str) try: return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
class DebugInterpreter: def __init__(self, shell_locals: List[ShellVariable]): self._shell_locals = shell_locals self._interpreter = InteractiveInterpreter() def eval(self, msg): old_stdout = sys.stdout old_stderr = sys.stderr sys.stdout = StringIO() sys.stderr = StringIO() if msg.endswith(";"): msg = msg.replace(";", "\n") handler = logging.StreamHandler(sys.stdout) logging.getLogger().addHandler(handler) self._interpreter.runsource(msg) logging.getLogger().removeHandler(handler) sys.stdout.seek(0) out = sys.stdout.read() sys.stderr.seek(0) err = sys.stderr.read() sys.stdout = old_stdout sys.stderr = old_stderr return out.strip("\n"), err.strip("\n") def set_locals(self): initial_code = [] variables_description = [] for shellLocal in self._shell_locals: initial_code.extend(shellLocal.get_evaluation_command()) result = shellLocal.name, shellLocal.description variables_description.append(result) for line in initial_code: self.eval(line) return variables_description
def runsource(self, source, symbol="single"): "Extend base class method: encode the source" filename = '<diyrpc shell>' if isinstance(source, types.UnicodeType): from idlelib import IOBinding try: source = source.encode(IOBinding.encoding) except UnicodeError: self.write("Unsupported characters in input\n") return try: return InteractiveInterpreter.runsource(self, source, filename, symbol) finally: pass
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = self.stdin, self.stdout, self.stderr more = InteractiveInterpreter.runsource(self, source) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin if sys.stdout == self.stdout: sys.stdout = stdout if sys.stderr == self.stderr: sys.stderr = stderr return more
def runsource(self, source): """Compile and run source code in the interpreter.""" stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr sys.stdin, sys.stdout, sys.stderr = \ self.stdin, self.stdout, self.stderr more = InteractiveInterpreter.runsource(self, source) # If sys.std* is still what we set it to, then restore it. # But, if the executed source changed sys.std*, assume it was # meant to be changed and leave it. Power to the people. if sys.stdin == self.stdin: sys.stdin = stdin if sys.stdout == self.stdout: sys.stdout = stdout if sys.stderr == self.stderr: sys.stderr = stderr return more
def runsource(self, source): "Extend base class method: Stuff the source in the line cache first" filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) if isinstance(source, types.UnicodeType): import IOBinding try: source = source.encode(IOBinding.encoding) except UnicodeError: self.tkconsole.resetoutput() self.write("Unsupported characters in input") return try: return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
def runsource(self, source): "Extend base class method: Stuff the source in the line cache first" filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) if isinstance(source, types.UnicodeType): import IOBinding try: source = source.encode(IOBinding.encoding) except UnicodeError: self.tkconsole.resetoutput() self.write("Unsupported characters in input") return try: return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
def runsource(self, source): "Extend base class method: Stuff the source in the line cache first" filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) # at the moment, InteractiveInterpreter expects str assert isinstance(source, str) #if isinstance(source, str): # from idlelib import IOBinding # try: # source = source.encode(IOBinding.encoding) # except UnicodeError: # self.tkconsole.resetoutput() # self.write("Unsupported characters in input\n") # return try: # InteractiveInterpreter.runsource() calls its runcode() method, # which is overridden (see below) return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
def runsource(self, source): "Extend base class method: Stuff the source in the line cache first" filename = self.stuffsource(source) self.more = 0 self.save_warnings_filters = warnings.filters[:] warnings.filterwarnings(action="error", category=SyntaxWarning) # at the moment, InteractiveInterpreter expects str assert isinstance(source, str) #if isinstance(source, str): # from idlelib import IOBinding # try: # source = source.encode(IOBinding.encoding) # except UnicodeError: # self.tkconsole.resetoutput() # self.write("Unsupported characters in input\n") # return try: # InteractiveInterpreter.runsource() calls its runcode() method, # which is overridden (see below) return InteractiveInterpreter.runsource(self, source, filename) finally: if self.save_warnings_filters is not None: warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None
class PyCute(QMultiLineEdit): """ PyCute is a Python shell for PyQt. Creating, displaying and controlling PyQt widgets from the Python command line interpreter is very hard, if not, impossible. PyCute solves this problem by interfacing the Python interpreter to a PyQt widget. My use is interpreter driven plotting to QwtPlot instances. Why? Other popular scientific software packages like SciPy, SciLab, Octave, Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting. It is well adapted to quick & dirty exploration. Of course, PyQt's debugger -- eric -- gives you similar facilities, but PyCute is smaller and easier to integrate in applications. Eric requires Qt-3.x PyCute is based on ideas and code from: - Python*/Tools/idle/PyShell.py (Python Software Foundation License) - PyQt*/eric/Shell.py (Gnu Public License) """ def __init__(self, locals=None, log='', parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QMultiLineEdit.__init__(self, parent) self.interpreter = Interpreter(locals) # session log self.log = log or '' # to exit the main interpreter by a Ctrl-D if PyCute has no parent if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self # last line + last incomplete lines self.line = QString() self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.xLast = 0 self.yLast = 0 # user interface setup # no word wrapping simplifies cursor <-> numLines() mapping self.setWordWrap(QMultiLineEdit.NoWrap) self.setCaption('PyCute -- a Python Shell for PyQt --' 'http://gerard.vermeulen.free.fr') # font if os.name == 'posix': font = QFont("Fixed", 12) elif os.name == 'nt' or os.name == 'dos': font = QFont("Courier New", 8) else: raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'" font.setFixedPitch(1) self.setFont(font) # geometry height = 40 * QFontMetrics(font).lineSpacing() request = QSize(600, height) if parent is not None: request = request.boundedTo(parent.size()) self.resize(request) # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " # interpreter banner self.write('The PyCute shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.write(sys.ps1) def flush(self): """ Simulate stdin, stdout, and stderr. """ pass def isatty(self): """ Simulate stdin, stdout, and stderr. """ return 1 def readline(self): """ Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() self.__moveCursorToEnd() while self.reading: qApp.processOneEvent() if self.line.length() == 0: return '\n' else: return str(self.line) def write(self, text): """ Simulate stdin, stdout, and stderr. """ # The output of self.append(text) contains to many newline characters, # so work around QTextEdit's policy for handling newline characters. hack = self.text() hack.append(text) self.setText(hack) #self.setText(self.text().append(text)) # segmentation fault self.yLast, self.xLast = self.__moveCursorToEnd() def writelines(self, text): """ Simulate stdin, stdout, and stderr. """ map(self.write, text) print "DO WE EVER GET HERE? IF YES, OPTIMIZATION POSSIBLE" def fakeUser(self, lines): """ Simulate a user: lines is a sequence of strings (Python statements). """ for line in lines: self.line = QString(line.rstrip()) self.write(self.line) self.write('\n') self.__run() def __run(self): """ Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ self.pointer = 0 self.history.append(QString(self.line)) self.lines.append(str(self.line)) source = '\n'.join(self.lines) self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() def __clearLine(self): """ Clear input line buffer """ self.line.truncate(0) self.point = 0 def __insertText(self, text): """ Insert text at the current cursor position. """ y, x = self.getCursorPosition() self.insertAt(text, y, x) self.line.insert(self.point, text) self.point += text.length() self.setCursorPosition(y, x + text.length()) def __moveCursorToEnd(self): y = self.numLines() - 1 x = self.lineLength(y) self.setCursorPosition(y, x) return y, x def keyPressEvent(self, e): """ Handle user input a key at a time. """ text = e.text() key = e.key() ascii = e.ascii() if text.length() and ascii >= 32 and ascii < 127: self.__insertText(text) return if e.state() & Qt.ControlButton and key == self.eofKey: try: file = open(self.log, "w") file.write(str(self.text())) file.close() except: pass sys.exit() return if e.state() & Qt.ControlButton or e.state() & Qt.ShiftButton: e.ignore() return if key == Qt.Key_Backspace: if self.point: self.backspace() self.point -= 1 self.line.remove(self.point, 1) elif key == Qt.Key_Delete: self.delChar() self.line.remove(self.point, 1) elif key == Qt.Key_Return or key == Qt.Key_Enter: self.write('\n') if self.reading: self.reading = 0 else: self.__run() elif key == Qt.Key_Tab: self.__insertText(text) elif key == Qt.Key_Left: if self.point: self.cursorLeft() self.point -= 1 elif key == Qt.Key_Right: if self.point < self.line.length(): self.cursorRight() self.point += 1 elif key == Qt.Key_Home: self.setCursorPosition(self.yLast, self.xLast) self.point = 0 elif key == Qt.Key_End: self.end() self.point = self.line.length() elif key == Qt.Key_Up: if len(self.history): if self.pointer == 0: self.pointer = len(self.history) self.pointer -= 1 self.__recall() elif key == Qt.Key_Down: if len(self.history): self.pointer += 1 if self.pointer == len(self.history): self.pointer = 0 self.__recall() else: e.ignore() def __recall(self): """ Display the current item from the command history. """ self.setCursorPosition(self.yLast, self.xLast) self.killLine() # QMultiLineEdit self.__clearLine() # self.line self.__insertText(self.history[self.pointer]) def focusNextPrevChild(self, next): """ Suppress tabbing to the next window in multi-line commands. """ if next and self.more: return 0 return QMultiLineEdit.focusNextPrevChild(self, next) def mousePressEvent(self, e): """ Keep the cursor after the last prompt. """ if e.button() == Qt.LeftButton: self.__moveCursorToEnd() return def contentsContextMenuEvent(self, ev): """ Suppress the right button context menu. """ return
class DigitalWatchStatechart(StateMachine): # Constants for this model StateNum = 4 EventNames = ["__INTERNAL_0_TIME_0", "start", "stop", "topRightPressed"] StateNames = ["New", "Running", "Setup", "Stopped"] ParentTable = [ -1, # New -- parent (None) -1, # Running -- parent (None) -1, # Setup -- parent (None) -1 # Stopped -- parent (None) ] HistoryStateTable = [0, 0, 0, 0] LeafStateTable = ["New", "Running", "Setup", "Stopped"] OrthogonalInBetween = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] OrthogonalTable = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] IntervalTable = ["3", None, None, None] RescheduleTable = [1, -1, -1, -1] Hierarchy = [ [0, 0, 0, 0], # substates of state New [0, 0, 0, 0], # substates of state Running [0, 0, 0, 0], # substates of state Setup [0, 0, 0, 0] # substates of state Stopped ] CommonStateTable = [[-1, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1]] Description = None Lock = thread.allocate_lock() CurrentModel = None def __init__(self, Interpreter=None, Parent=None, OldInstance=None): # Variables self.Parent = Parent self.HistoryCount = 0 self.state = None self.BackState = None if OldInstance != None: self.Submodels = OldInstance.Submodels else: self.Submodels = [] for i in range(DigitalWatchStatechart.StateNum): self.Submodels.append(None) self.history = [] for i in range(DigitalWatchStatechart.StateNum): self.history.append(None) # Constructor for i in range(DigitalWatchStatechart.StateNum): self.history[i] = History() self.history[i].States = [] self.history[i].Times = [] for j in range(DigitalWatchStatechart.StateNum): self.history[i].States.append(-1) self.history[i].Times.append(-1) self.TimedTransitions = [] # used only when --ext is set for i in range(DigitalWatchStatechart.StateNum): self.TimedTransitions.append(None) self.clearEnteredStates() self.HasInteractor = 0 # Interpreter of action code if self.Parent == None: # Top-level model if Interpreter: self.DefaultInterpreter = Interpreter else: self.DefaultInterpreter = InteractiveInterpreter() self.setupInterpreter() self.EventsCond = threading.Condition() self.SchedulerCond = threading.Condition() self.Schedules = [] self.PendingEvents = None self.PendingEventsTail = None else: self.DefaultInterpreter = Interpreter self.Started = 0 self.Stopped = 0 self.description = DigitalWatchStatechart.Description # Methods def isParent(self, sp, sc): return sc >= 0 and (sp < 0 or DigitalWatchStatechart.Hierarchy[sp][sc]) def isInState(self, s, check_substate=1, use_backup=1): if isinstance(s, int): if use_backup: st = self.BackState else: st = self.state while st != None: if st.StateID == s or (check_substate and self.isParent(s, st.StateID)): return 1 else: st = st.Next return 0 elif isinstance(s, str): i = 0 while i < DigitalWatchStatechart.StateNum: if s == DigitalWatchStatechart.StateNames[i]: return self.isInState(i, check_substate, use_backup) i = i + 1 i = 0 while i < DigitalWatchStatechart.StateNum: stname = DigitalWatchStatechart.StateNames[i] if self.Submodels[i] != None and startsWith(s, stname + "."): pos = len(stname) + 1 SubmodelState = s[pos:] return self.isInState( i, 0, use_backup) and self.Submodels[i].isInState( SubmodelState, check_substate, use_backup) i = i + 1 return 0 else: return 0 class main_callable: def __call__(self, argv): model = DigitalWatchStatechart() cmd = "" model.initModel() if model.HasInteractor: model.runInteractor() else: cond = thread.allocate_lock() while cmd != "exit": sys.__stdout__.write(model.getCurrentState() + " > ") cmd = string.strip(sys.__stdin__.readline()) if cmd == "exit": break if not model.Stopped: cond.acquire() model.event(cmd, [], cond) cond.acquire() cond.release() model.runFinalizer() main = main_callable() def initModel(self, run_initializer=1, run_enter_actions=1): self.clearEnteredStates() if self.Parent == None and DigitalWatchStatechart.Description != None: sys.__stdout__.write(DigitalWatchStatechart.Description + "\n") self.addInState(2) # init state "Setup" self.recordEnteredState(2) if run_initializer: self.runInitializer() if not self.HasInteractor: self.start(None, run_enter_actions) def applyMask(self, mask, dest): i = 0 while i < DigitalWatchStatechart.StateNum: dest[i] = dest[i] and mask[i] i = i + 1 def handleEvent(self, se, params=[], cond=None, scheduler=None): if not self.Started: if cond: cond.release() return 0 self.params = params handled = 0 table = [] i = 0 while i < DigitalWatchStatechart.StateNum: table.append(1) i = i + 1 if self.state: self.BackState = self.state.copy() else: self.BackState = None e = self.eventStr2Int(se) if e == 0: # event "__INTERNAL_0_TIME_0" if table[1] and self.isInState(1) and self.testCondition(0): if (scheduler == self or scheduler == None) and table[1]: self.runActionCode(2) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(1, 1) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(DigitalWatchStatechart.OrthogonalTable[1], table) handled = 1 elif e == 1: # event "start" if table[2] and self.isInState(2) and self.testCondition(1): if (scheduler == self or scheduler == None) and table[2]: self.runActionCode(3) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(2, 1) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(DigitalWatchStatechart.OrthogonalTable[2], table) handled = 1 elif e == 2: # event "stop" if table[0] and self.isInState(0) and self.testCondition(2): if (scheduler == self or scheduler == None) and table[0]: self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(0, 3) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(DigitalWatchStatechart.OrthogonalTable[0], table) handled = 1 elif e == 3: # event "topRightPressed" if table[1] and self.isInState(1) and self.testCondition(3): if (scheduler == self or scheduler == None) and table[1]: self.runActionCode(4) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(1, 0) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(DigitalWatchStatechart.OrthogonalTable[1], table) handled = 1 if table[0] and self.isInState(0) and self.testCondition(4): if (scheduler == self or scheduler == None) and table[0]: self.runActionCode(5) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(0, 0) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(DigitalWatchStatechart.OrthogonalTable[0], table) handled = 1 if cond and self.Parent == None: # Top-level model cond.release() if not handled and e >= 0 and ( scheduler == self or scheduler == None) and DigitalWatchStatechart.RescheduleTable[e] >= 0: self.addSchedule(DigitalWatchStatechart.RescheduleTable[e], DigitalWatchStatechart.IntervalTable[e], DigitalWatchStatechart.EventNames[e], scheduler) return handled def forceIntoState(self, s): changed = 0 s2 = self.state while s2 != None: HasCommonParent = 0 for i in range(DigitalWatchStatechart.StateNum): if self.isParent(i, s2.StateID) and self.isParent(i, s): HasCommonParent = 1 if not self.hasOrthogonalStateInBetween(i, s2.StateID): self.changeState(s2.StateID, s) changed = 1 if not HasCommonParent: self.changeState(s2.StateID, s) changed = 1 s2 = s2.Next if not changed: self.addInState(s) def changeState(self, s1, s2, check_history=0, top_level=0): # t1=common(s1, s2) t1 = DigitalWatchStatechart.CommonStateTable[s1][s2] self.recordHistory(t1) if t1 >= 0: self.removeOutStates(t1) else: self.state = None # t2=history(s2) t2 = DigitalWatchStatechart.HistoryStateTable[s2] if t2 == 0: # no history self.generateStates(t1, s2) elif t2 == 1: # normal history if not check_history: self.generateStates(t1, s2) elif self.hasHistoryRecorded(s2) and self.Submodels[s2] == None: self.generateStates(t1, self.history[s2].States[s2]) else: self.generateStates(t1, s2, 1) elif t2 == 2: # deep history if check_history and self.hasHistoryRecorded(s2): if self.Submodels[s2]: self.recordEnteredState(s2, 1, 1, t1) self.addInState(s2) else: for i in range(DigitalWatchStatechart.StateNum): hs = self.history[s2].States[i] if hs >= 0 and self.isLeafState(hs): self.recordEnteredState(hs, 1, 1, t1) self.addInState(hs) else: self.generateStates(t1, s2) def addInState(self, s): if not self.isInState(s, 1, 0): st = State() st.StateID = s st.Next = self.state self.state = st return 1 else: return 0 def generateStates(self, common, dest, history_type=0): if common == -1: if dest == 0: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(0): self.recordEnteredState(0) self.addInState(0) # move into leaf state "New" elif dest == 1: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(1): self.recordEnteredState(1) self.addInState(1) # move into leaf state "Running" elif dest == 2: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(2): self.recordEnteredState(2) self.addInState(2) # move into leaf state "Setup" elif dest == 3: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(3): self.recordEnteredState(3) self.addInState(3) # move into leaf state "Stopped" elif common == 0: if dest == 0: if history_type != 2 or self.check_history(0): self.addInState(0) # move into leaf state "New" elif common == 1: if dest == 1: if history_type != 2 or self.check_history(1): self.addInState(1) # move into leaf state "Running" elif common == 2: if dest == 2: if history_type != 2 or self.check_history(2): self.addInState(2) # move into leaf state "Setup" elif common == 3: if dest == 3: if history_type != 2 or self.check_history(3): self.addInState(3) # move into leaf state "Stopped" def removeOutStates(self, common_state): s = self.state prev = None while s != None: if self.isParent(common_state, s.StateID): if prev == None: self.state = self.state.Next else: prev.Next = s.Next else: prev = s s = s.Next def eventStr2Int(self, event): for i in range(4): if event == DigitalWatchStatechart.EventNames[i]: return i return -1 def stateInt2Str(self, state): if state == -1: return "" else: return DigitalWatchStatechart.StateNames[state] def getCurrentStateList(self): sl = StringList() slend = sl s = self.state while s != None: sm = self.Submodels[s.StateID] curstate = self.stateInt2Str(s.StateID) if sm != None: slend.Next = sm.getCurrentStateList() while slend.Next != None: slend.Next.str = curstate + "." + slend.Next.str slend = slend.Next else: slend.Next = StringList(curstate) slend = slend.Next s = s.Next return sl.Next def getCurrentState(self, states=None): if states == None: states = self.getCurrentStateList() if states != None: states = states.sort() strst = "['%s'%s]" % (states.str, self.getCurrentState(states)) else: strst = "[]" else: if states.Next: strst = ", '%s'%s" % (states.Next.str, self.getCurrentState(states.Next)) else: strst = "" return strst def getParentState(self, state): return DigitalWatchStatechart.ParentTable[state] def getSubstates(self, state): substates = None if state == -1: # substates of "" # add substate "New" st = IntList() st.int = 0 st.Next = substates substates = st # add substate "Running" st = IntList() st.int = 1 st.Next = substates substates = st # add substate "Setup" st = IntList() st.int = 2 st.Next = substates substates = st # add substate "Stopped" st = IntList() st.int = 3 st.Next = substates substates = st elif state == 0: # substates of "New" pass elif state == 1: # substates of "Running" pass elif state == 2: # substates of "Setup" pass elif state == 3: # substates of "Stopped" pass return substates def isHistoryState(self, state): return DigitalWatchStatechart.HistoryStateTable[state] > 0 def isLeafState(self, state): if isinstance(state, int): return DigitalWatchStatechart.LeafStateTable[state] != None elif isinstance(state, str): for i in range(DigitalWatchStatechart.StateNum): if DigitalWatchStatechart.LeafStateTable[i] == None: continue if state == DigitalWatchStatechart.LeafStateTable[ i] and self.Submodels[i] == None: return 1 elif startsWith(state, DigitalWatchStatechart.LeafStateTable[i] + ".") and self.Submodels[i] != None: SubmodelState = state[DigitalWatchStatechart. LeafStateTable[i].length() + 1:] return self.Submodels[i].isLeafState(SubmodelState) return 0 def isHistoryUp2Date(self, state, time): for i in range(DigitalWatchStatechart.StateNum): if self.history[state].Times[i] >= time: return 1 return 0 def mergeHistory(self, state, states, times): max = -1 for i in range(DigitalWatchStatechart.StateNum): if times[i] > max: max = times[i] if self.isHistoryUp2Date(state, max): for i in range(DigitalWatchStatechart.StateNum): if times[i] > self.history[state].Times[i]: self.history[state].States[i] = states[i] self.history[state].Times[i] = times[i] else: self.history[state].States = copy.copy(states) self.history[state].Times = copy.copy(times) def recordHistory(self, top_state): curtime = self.HistoryCount self.HistoryCount = self.HistoryCount + 1 s = self.state while s != None: child = s.StateID states = [] times = [] for i in range(DigitalWatchStatechart.StateNum): states.append(-1) times.append(-1) states[child] = child times[child] = curtime if top_state < 0 or self.isParent(top_state, child): parent = self.getParentState(child) if self.isHistoryState(child): self.history[child].Submodel = self.Submodels[child] while parent >= 0 and times[parent] != curtime: states[parent] = child times[parent] = curtime if self.isHistoryState(parent): self.mergeHistory(parent, states, times) if parent == top_state: break child = parent parent = self.getParentState(child) s = s.Next def hasHistoryRecorded(self, state): for i in range(DigitalWatchStatechart.StateNum): if self.history[state].States[i] != -1: return 1 if self.Submodels[state] != None: return 1 return 0 def hasOrthogonalStateInBetween(self, parent, leaf): return DigitalWatchStatechart.OrthogonalInBetween[parent + 1][leaf] def check_history(self, dest): s = self.state while s != None: if self.isParent( dest, s.StateID) and not self.hasOrthogonalStateInBetween( dest, s.StateID): return 0 s = s.Next return 1 def getEnabledEvents(self): events = EventList() if self.isInState(1): events.Append("__INTERNAL_0_TIME_0") if self.isInState(2): events.Append("start") if self.isInState(0): events.Append("stop") if self.isInState(1): events.Append("topRightPressed") if self.isInState(0): events.Append("topRightPressed") return events.Next def getHierarchy(self, start_level, state_prefix): h = Hierarchy() lasth = h # Generate state "New" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "New" if state_prefix == None: lasth.Next.PathName = "New" else: lasth.Next.PathName = state_prefix + ".New" lasth.Next.StateNum = 0 lasth.Next.Level = start_level + 0 lasth = lasth.Next # Generate state "Running" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Running" if state_prefix == None: lasth.Next.PathName = "Running" else: lasth.Next.PathName = state_prefix + ".Running" lasth.Next.StateNum = 1 lasth.Next.Level = start_level + 0 lasth = lasth.Next # Generate state "Setup" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Setup" if state_prefix == None: lasth.Next.PathName = "Setup" else: lasth.Next.PathName = state_prefix + ".Setup" lasth.Next.StateNum = 2 lasth.Next.Level = start_level + 0 lasth = lasth.Next # Generate state "Stopped" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Stopped" if state_prefix == None: lasth.Next.PathName = "Stopped" else: lasth.Next.PathName = state_prefix + ".Stopped" lasth.Next.StateNum = 3 lasth.Next.Level = start_level + 0 lasth = lasth.Next return h.Next def topLevelHistory(self): s = self.state.StateID t = self.getParentState(s) while t != -1: s = t t = self.getParentState(s) self.changeState(s, s) def runActionCode(self, code_num): if code_num == 0: # model finalizer pass elif code_num == 1: # model initializer pass elif code_num == 2: # output action(s) of a transition self.runCode("dump_message(\"transition after 3 seconds\")") # repeated timed transition self.addSchedule(1, DigitalWatchStatechart.IntervalTable[0], DigitalWatchStatechart.EventNames[0], self) elif code_num == 3: # output action(s) of a transition self.runCode("dump_message(\"Starting the Digital Watch\")") self.runCode("controller=eventhandler.get_event_params()") elif code_num == 4: # output action(s) of a transition self.runCode("controller.refreshTimeDisplay()") self.runCode("dump_message(\"refreshing time display\")") elif code_num == 5: # output action(s) of a transition self.runCode("controller.refreshTimeDisplay()") self.runCode("dump_message(\"refreshing time display\")") elif code_num == 6: # enter actions for state "Running" # a timed transition self.addSchedule(1, DigitalWatchStatechart.IntervalTable[0], DigitalWatchStatechart.EventNames[0], self) elif code_num == 7: # enter actions for state "Stopped" # run finalizer for a final state self.runFinalizer() elif code_num == 8: # exit actions for state "Running" # clean up timed transitions self.removeSchedule(1, self) def testCondition(self, cond_num): if cond_num==0 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==1 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==2 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==3 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==4 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 return 0 def runEnterActions(self, state): if state == 1: # enter action(s) for state "Running" self.runActionCode(6) elif state == 3: # enter action(s) for state "Stopped" self.runActionCode(7) def runExitActions(self, state): if state == 1: # exit action(s) for state "Running" self.runActionCode(8) def compareSchedule(self, sched_a, sched_b): return cmp(sched_a[1], sched_b[1]) def addSchedule(self, id, interval, event, scheduler): if self.Parent != None: # Non-top-level model self.Parent.addSchedule(id, interval, event, scheduler) return f = eval(interval, self.DefaultInterpreter.locals) self.SchedulerCond.acquire() t = time.time() + f s = [id, t, interval, event, scheduler] self.Schedules.append(s) self.Schedules.sort(self.compareSchedule) self.SchedulerCond.notify() self.SchedulerCond.release() def removeSchedule(self, id, scheduler): if self.Parent != None: # Non-top-level model self.Parent.removeSchedule(id, scheduler) return self.SchedulerCond.acquire() i = 0 while i < len(self.Schedules): if self.Schedules[i][0] == id and self.Schedules[i][4] == scheduler: del self.Schedules[i] else: i = i + 1 self.SchedulerCond.release() def scheduler(self): self.SchedulerCond.acquire() wait_cond = thread.allocate_lock() while 1: while not self.Schedules: self.SchedulerCond.wait() if self.Stopped: self.SchedulerCond.release() return while self.Schedules and self.Schedules[0][1] <= time.time(): this_sched = self.Schedules[0] del self.Schedules[0] self.SchedulerCond.release() wait_cond.acquire() self.event(this_sched[3], [], wait_cond, this_sched[4]) wait_cond.acquire() wait_cond.release() self.SchedulerCond.acquire() if self.Schedules: t = self.Schedules[0][1] - time.time() if t > 0: self.SchedulerCond.wait(t) if self.Stopped: self.SchedulerCond.release() return def recordAllEnteredStates(self): st = self.state while st != None: self.recordEnteredState(st.StateID, 1, 1) st = st.Next def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1): # test if s is already recorded se = self.StatesEntered found = 0 while se != None: if se.int == s: found = 1 break se = se.Next if not found: if superstates: parent = self.getParentState(s) if parent >= 0 and parent != commonstate: self.recordEnteredState(parent, 1, 0, commonstate) st = IntList() st.Next = self.StatesEntered st.int = s self.StatesEntered = st if submodel and self.Submodels[s]: self.Submodels[s].recordAllEnteredStates() def runAllEnterActions(self): self.runEnterActionsForStates(self.StatesEntered, 1) def runEnterActionsForStates(self, states, recursive=0): if states: self.runEnterActionsForStates(states.Next, 0) self.runEnterActions(states.int) if recursive: for s in self.Submodels: if s: s.runAllEnterActions() def runExitActionsForStates(self, common_state): substates = self.getSubstates(common_state) if substates == None: s = self.state while s != None and s.StateID != common_state: s = s.Next if s != None and self.Submodels[s.StateID]: self.Submodels[s.StateID].runExitActionsForStates(-1) return s != None else: has_current_substate = 0 while substates != None: res = self.runExitActionsForStates(substates.int) has_current_substate = has_current_substate or res if res: self.runExitActions(substates.int) substates = substates.Next return has_current_substate def runInitializer(self): self.runActionCode(1) for s in self.Submodels: if s: s.runInitializer() def runFinalizer(self): if self.Started: self.Started = 0 for s in self.Submodels: if s: s.runFinalizer() self.runActionCode(0) if self.Parent == None: # Top-level model self.EventsCond.acquire() self.SchedulerCond.acquire() self.Stopped = 1 self.EventsCond.notify() self.SchedulerCond.notify() self.SchedulerCond.release() self.EventsCond.release() else: self.Stopped = 1 def clearEnteredStates(self): self.StatesEntered = None for s in self.Submodels: if s: s.clearEnteredStates() def get_current_state(self): return self.getCurrentState() def runCode(self, c): self.DefaultInterpreter.runsource(c + "\n", "<input>", "exec") def setupInterpreter(self): self.DefaultInterpreter.locals["eventhandler"] = self self.DefaultInterpreter.locals["dump_message"] = self.dump_message def get_event_params(self): return self.params def dump_message(self, msg): print msg def is_in_state(self, s, check_substate=1): return self.isInState(s, check_substate) def start(self, lock=None, run_enter_actions=1): if self.Parent == None: # Top-level model if run_enter_actions: self.runEnterActionsForStates(self.StatesEntered, 1) self.Started = 1 thread.start_new_thread(self.handleEvent_wrapper, ()) thread.start_new_thread(self.scheduler, ()) if lock: lock.release() else: self.Started = 1 for submodel in self.Submodels: if submodel != None: submodel.start() def shutdown(self): pass def handleEvent_wrapper(self): self.EventsCond.acquire() while 1: if self.PendingEvents == None: self.EventsCond.wait() if self.Stopped: self.EventsCond.release() return event = self.PendingEvents self.PendingEvents = self.PendingEvents.Next if self.PendingEvents == None: self.PendingEventsTail = None event.next = None self.EventsCond.release() self.handleEvent(event.Event[0], event.Event[1], event.Event[2], event.Event[3]) self.EventsCond.acquire() if self.Stopped: self.EventsCond.release() return def event(self, e, params=[], cond=None, scheduler=None): self.EventsCond.acquire() ev = EventList() ev.Event = [e, params, cond, scheduler] if self.PendingEventsTail != None: self.PendingEventsTail.Next = ev else: self.PendingEvents = ev self.PendingEventsTail = ev self.EventsCond.notify() self.EventsCond.release()
#! /usr/bin/env python
class QShell(QtGui.QTextEdit): """This class embeds a python interperter in a QTextEdit Widget It is based on PyCute developed by Gerard Vermeulen. """ def __init__(self, locals=None, parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QtGui.QTextEdit.__init__(self, parent) self.setReadOnly(False) self.setWindowTitle("Console") # to exit the main interpreter by a Ctrl-D if QShell has no parent if parent is None: self.eofKey = QtCore.Qt.Key_D else: self.eofKey = None # flag for knowing when selecting text self.selectMode = False self.interpreter = None self.controller = None # storing current state #this is not working on mac #self.prev_stdout = sys.stdout #self.prev_stdin = sys.stdin #self.prev_stderr = sys.stderr # capture all interactive input/output #sys.stdout = self #sys.stderr = self #sys.stdin = self # user interface setup self.setAcceptRichText(False) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) conf = get_vistrails_configuration() shell_conf = conf.shell # font font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size) font.setFixedPitch(1) self.setFont(font) self.reset(locals) def load_package(self, pkg_name): reg = core.modules.module_registry.get_module_registry() package = reg.get_package_by_name(pkg_name) def create_dict(modules, ns, m, mdesc): md = {} if len(ns) == 0: d = { '_module_desc': mdesc, '_package': pkg, } modules[m] = type('module', (vistrails_module, ), d) else: if ns[0] in modules: md = create_dict(modules[ns[0]], ns[1:], m, mdesc) else: md = create_dict(md, ns[1:], m, mdesc) modules[ns[0]] = md return modules def create_namespace_path(root, modules): for k, v in modules.iteritems(): if type(v) == type({}): d = create_namespace_path(k, v) modules[k] = d if root is not None: modules['_package'] = pkg return type(root, (object, ), modules)() else: return modules def get_module_init(module_desc): def init(self, *args, **kwargs): self.__dict__['module'] = \ api.add_module_from_descriptor(module_desc) return init def get_module(package): def getter(self, attr_name): desc_tuple = (attr_name, '') if desc_tuple in package.descriptors: module_desc = package.descriptors[desc_tuple] d = { '_module_desc': module_desc, '_package': self, } return type('module', (vistrails_module, ), d) else: raise AttributeError("type object '%s' has no attribute " "'%s'" % (self.__class__.__name__, attr_name)) return getter d = { '__getattr__': get_module(package), } pkg = type(package.name, (object, ), d)() modules = {} for (m, ns) in package.descriptors: module_desc = package.descriptors[(m, ns)] modules = create_dict(modules, ns.split('|'), m, module_desc) modules = create_namespace_path(None, modules) for (k, v) in modules.iteritems(): setattr(pkg, k, v) return pkg def selected_modules(self): shell_modules = [] modules = api.get_selected_modules() for module in modules: d = {'_module': module} shell_modules.append(type('module', (vistrails_module, ), d)()) return shell_modules def reset(self, locals): """reset(locals) -> None Reset shell preparing it for a new session. """ locals['load_package'] = self.load_package locals['selected_modules'] = self.selected_modules if self.interpreter: del self.interpreter self.interpreter = InteractiveInterpreter(locals) # last line + last incomplete lines self.line = QtCore.QString() self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.last = 0 # interpreter prompt. if hasattr(sys, "ps1"): sys.ps1 else: sys.ps1 = ">>> " if hasattr(sys, "ps2"): sys.ps2 else: sys.ps2 = "... " # interpreter banner self.write('VisTrails shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.write(sys.ps1) def flush(self): """flush() -> None. Simulate stdin, stdout, and stderr. """ pass def isatty(self): """isatty() -> int Simulate stdin, stdout, and stderr. """ return 1 def readline(self): """readline() -> str Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) app = QtGui.QApplication.instance() while self.reading: app.processOneEvent() if self.line.length() == 0: return '\n' else: return str(self.line) def write(self, text): """write(text: str) -> None Simulate stdin, stdout, and stderr. """ cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.insertPlainText(text) cursor = self.textCursor() self.last = cursor.position() def write_input(self, text): cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.__insertText(text) def write_and_exec(self, commandlist): for command in commandlist: self.write_input(command) self.__run() def insertFromMimeData(self, source): if source.hasText(): cmds = source.text().split(QtCore.QString('\n')) self.write_and_exec(cmds) def scroll_bar_at_bottom(self): """Returns true if vertical bar exists and is at bottom, or if vertical bar does not exist.""" bar = self.verticalScrollBar() if not bar: return True return bar.value() == bar.maximum() def __run(self): """__run() -> None Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) # self.set_controller() should_scroll = self.scroll_bar_at_bottom() self.pointer = 0 self.history.append(QtCore.QString(self.line)) self.lines.append(str(self.line)) source = '\n'.join(self.lines) self.write('\n') self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() if should_scroll: bar = self.verticalScrollBar() if bar: bar.setValue(bar.maximum()) def __clearLine(self): """__clearLine() -> None Clear input line buffer. """ self.line.truncate(0) self.point = 0 def __insertText(self, text): """__insertText(text) -> None Insert text at the current cursor position. """ self.insertPlainText(text) self.line.insert(self.point, text) self.point += text.length() # def add_pipeline(self, p): # """ # add_pipeline(p) -> None # Set the active pipeline in the command shell. This replaces the modules # variable with the list of current active modules of the selected pipeline. # """ # if self.controller: # self.interpreter.active_pipeline = self.controller.current_pipeline # else: # self.interpreter.active_pipeline = p # cmd = 'active_pipeline = self.shell.interpreter.active_pipeline' # self.interpreter.runcode(cmd) # cmd = 'modules = self.vistrails_interpreter.find_persistent_entities(active_pipeline)[0]' # self.interpreter.runcode(cmd) def set_controller(self, controller=None): """set_controller(controller: VistrailController) -> None Set the current VistrailController on the shell. """ self.controller = controller if controller and self.controller.current_pipeline: self.interpreter.active_pipeline = self.controller.current_pipeline cmd = 'run_pipeline = self.shell.run_pipeline' self.interpreter.runcode(cmd) cmd = 'active_pipeline = self.shell.interpreter.active_pipeline' self.interpreter.runcode(cmd) cmd = 'modules = self.vistrails_interpreter.' \ 'find_persistent_entities(active_pipeline)[0]' self.interpreter.runcode(cmd) # def set_pipeline(self): # """set_active_pipeline() -> None # Makes sure that the pipeline being displayed is present in the shell for # direct inspection and manipulation # """ # self.add_pipeline(None) def run_pipeline(self): if self.controller: if self.interpreter.active_pipeline: self.controller.execute_current_workflow() def keyPressEvent(self, e): """keyPressEvent(e) -> None Handle user input a key at a time. Notice that text might come more than one keypress at a time if user is a fast enough typist! """ text = e.text() key = e.key() # NB: Sometimes len(str(text)) > 1! if text.length() and all( ord(x) >= 32 and ord(x) < 127 for x in str(text)): # exit select mode and jump to end of text cursor = self.textCursor() if self.selectMode or cursor.hasSelection(): self.selectMode = False cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.__insertText(text) return if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey: self.parent().closeSession() if e.modifiers() & QtCore.Qt.ControlModifier: if key == QtCore.Qt.Key_C or key == QtCore.Qt.Key_Insert: self.copy() elif key == QtCore.Qt.Key_V: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.paste() elif key == QtCore.Qt.Key_A: self.selectAll() self.selectMode = True else: e.ignore() return if e.modifiers() & QtCore.Qt.ShiftModifier: if key == QtCore.Qt.Key_Insert: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.paste() else: e.ignore() return # exit select mode and jump to end of text cursor = self.textCursor() if self.selectMode or cursor.hasSelection(): self.selectMode = False cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) if key == QtCore.Qt.Key_Backspace: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 self.line.remove(self.point, 1) elif key == QtCore.Qt.Key_Delete: QtGui.QTextEdit.keyPressEvent(self, e) self.line.remove(self.point, 1) elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter: if self.reading: self.reading = 0 else: self.__run() elif key == QtCore.Qt.Key_Tab: self.__insertText(text) elif key == QtCore.Qt.Key_Left: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 elif key == QtCore.Qt.Key_Right: if self.point < self.line.length(): QtGui.QTextEdit.keyPressEvent(self, e) self.point += 1 elif key == QtCore.Qt.Key_Home: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.StartOfLine) cursor.setPosition(cursor.position() + 4) self.setTextCursor(cursor) self.point = 0 elif key == QtCore.Qt.Key_End: QtGui.QTextEdit.keyPressEvent(self, e) self.point = self.line.length() elif key == QtCore.Qt.Key_Up: if len(self.history): if self.pointer == 0: self.pointer = len(self.history) self.pointer -= 1 self.__recall() elif key == QtCore.Qt.Key_Down: if len(self.history): self.pointer += 1 if self.pointer == len(self.history): self.pointer = 0 self.__recall() else: e.ignore() def __recall(self): """__recall() -> None Display the current item from the command history. """ cursor = self.textCursor() cursor.setPosition(self.last) cursor.select(QtGui.QTextCursor.LineUnderCursor) cursor.removeSelectedText() self.setTextCursor(cursor) self.insertPlainText(sys.ps1) self.__clearLine() self.__insertText(self.history[self.pointer]) def focusNextPrevChild(self, next): """focusNextPrevChild(next) -> None Suppress tabbing to the next window in multi-line commands. """ if next and self.more: return 0 return QtGui.QTextEdit.focusNextPrevChild(self, next) def mousePressEvent(self, e): """mousePressEvent(e) -> None Keep the cursor after the last prompt. """ if e.button() == QtCore.Qt.LeftButton: self.selectMode = True QtGui.QTextEdit.mousePressEvent(self, e) # cursor = self.textCursor() # cursor.movePosition(QtGui.QTextCursor.End) # self.setTextCursor(cursor) return def hide(self): """suspend() -> None Called when hiding the parent window in order to recover the previous state. """ #recovering the state sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ sys.stdin = sys.__stdin__ def show(self): """show() -> None Store previous state and starts capturing all interactive input and output. """ # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self self.setFocus() def saveSession(self, fileName): """saveSession(fileName: str) -> None Write its contents to a file """ output = open(str(fileName), 'w') output.write(self.toPlainText()) output.close() def restart(self, locals=None): """restart(locals=None) -> None Restart a new session """ self.clear() self.reset(locals) def contentsContextMenuEvent(self, ev): """ contentsContextMenuEvent(ev) -> None Suppress the right button context menu. """ return
class ButtonBehaviour_MDL(StateMachine): # Constants for this model StateNum = 3 EventNames = [ "(create)*", "<Any-ButtonRelease-1>", "<ButtonPress-1>", "[Done]" ] StateNames = ["Activate Button*", "Default", "Idle"] ParentTable = [ -1, # Activate Button* -- parent (None) -1, # Default -- parent (None) -1 # Idle -- parent (None) ] HistoryStateTable = [0, 0, 0] LeafStateTable = ["Activate Button*", "Default", "Idle"] OrthogonalInBetween = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] OrthogonalTable = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] IntervalTable = [None, None, None, None] RescheduleTable = [-1, -1, -1, -1] Hierarchy = [ [0, 0, 0], # substates of state Activate Button* [0, 0, 0], # substates of state Default [0, 0, 0] # substates of state Idle ] CommonStateTable = [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]] Description = None ##Lock=thread.allocate_lock() CurrentModel = None def __init__(self, Interpreter=None, Parent=None, OldInstance=None): # Variables self.Parent = Parent self.HistoryCount = 0 self.state = None self.BackState = None if OldInstance != None: self.Submodels = OldInstance.Submodels else: self.Submodels = [] for i in range(ButtonBehaviour_MDL.StateNum): self.Submodels.append(None) self.history = [] for i in range(ButtonBehaviour_MDL.StateNum): self.history.append(None) # Constructor for i in range(ButtonBehaviour_MDL.StateNum): self.history[i] = History() self.history[i].States = [] self.history[i].Times = [] for j in range(ButtonBehaviour_MDL.StateNum): self.history[i].States.append(-1) self.history[i].Times.append(-1) self.TimedTransitions = [] # used only when --ext is set for i in range(ButtonBehaviour_MDL.StateNum): self.TimedTransitions.append(None) self.clearEnteredStates() self.HasInteractor = 0 # Interpreter of action code if self.Parent == None: # Top-level model if Interpreter: self.DefaultInterpreter = Interpreter else: self.DefaultInterpreter = InteractiveInterpreter() self.setupInterpreter() ##self.EventsCond=threading.Condition() ##self.SchedulerCond=threading.Condition() self.Schedules = [] self.PendingEvents = None self.PendingEventsTail = None else: self.DefaultInterpreter = Interpreter self.Started = 0 self.Stopped = 0 self.description = ButtonBehaviour_MDL.Description # Methods def isParent(self, sp, sc): return sc >= 0 and (sp < 0 or ButtonBehaviour_MDL.Hierarchy[sp][sc]) def isInState(self, s, check_substate=1, use_backup=1): if isinstance(s, int): if use_backup: st = self.BackState else: st = self.state while st != None: if st.StateID == s or (check_substate and self.isParent(s, st.StateID)): return 1 else: st = st.Next return 0 elif isinstance(s, str): i = 0 while i < ButtonBehaviour_MDL.StateNum: if s == ButtonBehaviour_MDL.StateNames[i]: return self.isInState(i, check_substate, use_backup) i = i + 1 i = 0 while i < ButtonBehaviour_MDL.StateNum: stname = ButtonBehaviour_MDL.StateNames[i] if self.Submodels[i] != None and startsWith(s, stname + "."): pos = len(stname) + 1 SubmodelState = s[pos:] return self.isInState( i, 0, use_backup) and self.Submodels[i].isInState( SubmodelState, check_substate, use_backup) i = i + 1 return 0 else: return 0 class main_callable: def __call__(self, argv): model = ButtonBehaviour_MDL() cmd = "" model.initModel() if model.HasInteractor: model.runInteractor() else: ##cond=thread.allocate_lock() while cmd != "exit": sys.__stdout__.write(model.getCurrentState() + " > ") cmd = string.strip(sys.__stdin__.readline()) if cmd == "exit": break if not model.Stopped: ##cond.acquire() ##model.event(cmd, [], cond) model.event(cmd, []) ##cond.acquire() ##cond.release() model.runFinalizer() main = main_callable() def initModel(self, run_initializer=1, run_enter_actions=1, TkInstance=None): self.clearEnteredStates() if self.Parent == None and ButtonBehaviour_MDL.Description != None: sys.__stdout__.write(ButtonBehaviour_MDL.Description + "\n") self.addInState(1) # init state "Default" self.recordEnteredState(1) if run_initializer: self.runInitializer() if not self.HasInteractor: self.start(None, run_enter_actions, TkInstance) def applyMask(self, mask, dest): i = 0 while i < ButtonBehaviour_MDL.StateNum: dest[i] = dest[i] and mask[i] i = i + 1 def handleEvent(self, se, params=[], cond=None, scheduler=None): if not self.Started: if cond: cond.release() return 0 self.params = params handled = 0 table = [] i = 0 while i < ButtonBehaviour_MDL.StateNum: table.append(1) i = i + 1 if self.state: self.BackState = self.state.copy() else: self.BackState = None e = self.eventStr2Int(se) if e == 0: # event "(create)*" if table[1] and self.isInState(1) and self.testCondition(0): if (scheduler == self or scheduler == None) and table[1]: self.runActionCode(2) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(1, 2) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[1], table) handled = 1 elif e == 1: # event "<Any-ButtonRelease-1>" if table[2] and self.isInState(2) and self.testCondition(1): if (scheduler == self or scheduler == None) and table[2]: self.runActionCode(3) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(2, 0) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[2], table) handled = 1 elif e == 2: # event "<ButtonPress-1>" if table[2] and self.isInState(2) and self.testCondition(2): if (scheduler == self or scheduler == None) and table[2]: self.runActionCode(4) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(2, 2) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[2], table) handled = 1 elif e == 3: # event "[Done]" if table[0] and self.isInState(0) and self.testCondition(3): if (scheduler == self or scheduler == None) and table[0]: self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(0, 2) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[0], table) handled = 1 if cond and self.Parent == None: # Top-level model cond.release() if not handled and e >= 0 and ( scheduler == self or scheduler == None) and ButtonBehaviour_MDL.RescheduleTable[e] >= 0: self.addSchedule(ButtonBehaviour_MDL.RescheduleTable[e], ButtonBehaviour_MDL.IntervalTable[e], ButtonBehaviour_MDL.EventNames[e], scheduler) return handled def forceIntoState(self, s): changed = 0 s2 = self.state while s2 != None: HasCommonParent = 0 for i in range(ButtonBehaviour_MDL.StateNum): if self.isParent(i, s2.StateID) and self.isParent(i, s): HasCommonParent = 1 if not self.hasOrthogonalStateInBetween(i, s2.StateID): self.changeState(s2.StateID, s) changed = 1 if not HasCommonParent: self.changeState(s2.StateID, s) changed = 1 s2 = s2.Next if not changed: self.addInState(s) def changeState(self, s1, s2, check_history=0, top_level=0): # t1=common(s1, s2) t1 = ButtonBehaviour_MDL.CommonStateTable[s1][s2] self.recordHistory(t1) if t1 >= 0: self.removeOutStates(t1) else: self.state = None # t2=history(s2) t2 = ButtonBehaviour_MDL.HistoryStateTable[s2] if t2 == 0: # no history self.generateStates(t1, s2) elif t2 == 1: # normal history if not check_history: self.generateStates(t1, s2) elif self.hasHistoryRecorded(s2) and self.Submodels[s2] == None: self.generateStates(t1, self.history[s2].States[s2]) else: self.generateStates(t1, s2, 1) elif t2 == 2: # deep history if check_history and self.hasHistoryRecorded(s2): if self.Submodels[s2]: self.recordEnteredState(s2, 1, 1, t1) self.addInState(s2) else: for i in range(ButtonBehaviour_MDL.StateNum): hs = self.history[s2].States[i] if hs >= 0 and self.isLeafState(hs): self.recordEnteredState(hs, 1, 1, t1) self.addInState(hs) else: self.generateStates(t1, s2) def addInState(self, s): if not self.isInState(s, 1, 0): st = State() st.StateID = s st.Next = self.state self.state = st return 1 else: return 0 def generateStates(self, common, dest, history_type=0): if common == -1: if dest == 0: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(0): self.recordEnteredState(0) self.addInState( 0) # move into leaf state "Activate Button*" elif dest == 1: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(1): self.recordEnteredState(1) self.addInState(1) # move into leaf state "Default" elif dest == 2: if history_type != 2 or self.check_history(-1): if history_type != 2 or self.check_history(2): self.recordEnteredState(2) self.addInState(2) # move into leaf state "Idle" elif common == 0: if dest == 0: if history_type != 2 or self.check_history(0): self.addInState( 0) # move into leaf state "Activate Button*" elif common == 1: if dest == 1: if history_type != 2 or self.check_history(1): self.addInState(1) # move into leaf state "Default" elif common == 2: if dest == 2: if history_type != 2 or self.check_history(2): self.addInState(2) # move into leaf state "Idle" def removeOutStates(self, common_state): s = self.state prev = None while s != None: if self.isParent(common_state, s.StateID): if prev == None: self.state = self.state.Next else: prev.Next = s.Next else: prev = s s = s.Next def eventStr2Int(self, event): for i in range(4): if event == ButtonBehaviour_MDL.EventNames[i]: return i return -1 def stateInt2Str(self, state): if state == -1: return "" else: return ButtonBehaviour_MDL.StateNames[state] def getCurrentStateList(self): sl = StringList() slend = sl s = self.state while s != None: sm = self.Submodels[s.StateID] curstate = self.stateInt2Str(s.StateID) if sm != None: slend.Next = sm.getCurrentStateList() while slend.Next != None: slend.Next.str = curstate + "." + slend.Next.str slend = slend.Next else: slend.Next = StringList(curstate) slend = slend.Next s = s.Next return sl.Next def getCurrentState(self, states=None): if states == None: states = self.getCurrentStateList() if states != None: states = states.sort() strst = "['%s'%s]" % (states.str, self.getCurrentState(states)) else: strst = "[]" else: if states.Next: strst = ", '%s'%s" % (states.Next.str, self.getCurrentState(states.Next)) else: strst = "" return strst def getParentState(self, state): return ButtonBehaviour_MDL.ParentTable[state] def getSubstates(self, state): substates = None if state == -1: # substates of "" # add substate "Activate Button*" st = IntList() st.int = 0 st.Next = substates substates = st # add substate "Default" st = IntList() st.int = 1 st.Next = substates substates = st # add substate "Idle" st = IntList() st.int = 2 st.Next = substates substates = st elif state == 0: # substates of "Activate Button*" pass elif state == 1: # substates of "Default" pass elif state == 2: # substates of "Idle" pass return substates def isHistoryState(self, state): return ButtonBehaviour_MDL.HistoryStateTable[state] > 0 def isLeafState(self, state): if isinstance(state, int): return ButtonBehaviour_MDL.LeafStateTable[state] != None elif isinstance(state, str): for i in range(ButtonBehaviour_MDL.StateNum): if ButtonBehaviour_MDL.LeafStateTable[i] == None: continue if state == ButtonBehaviour_MDL.LeafStateTable[ i] and self.Submodels[i] == None: return 1 elif startsWith(state, ButtonBehaviour_MDL.LeafStateTable[i] + ".") and self.Submodels[i] != None: SubmodelState = state[ButtonBehaviour_MDL. LeafStateTable[i].length() + 1:] return self.Submodels[i].isLeafState(SubmodelState) return 0 def isHistoryUp2Date(self, state, time): for i in range(ButtonBehaviour_MDL.StateNum): if self.history[state].Times[i] >= time: return 1 return 0 def mergeHistory(self, state, states, times): max = -1 for i in range(ButtonBehaviour_MDL.StateNum): if times[i] > max: max = times[i] if self.isHistoryUp2Date(state, max): for i in range(ButtonBehaviour_MDL.StateNum): if times[i] > self.history[state].Times[i]: self.history[state].States[i] = states[i] self.history[state].Times[i] = times[i] else: self.history[state].States = copy.copy(states) self.history[state].Times = copy.copy(times) def recordHistory(self, top_state): curtime = self.HistoryCount self.HistoryCount = self.HistoryCount + 1 s = self.state while s != None: child = s.StateID states = [] times = [] for i in range(ButtonBehaviour_MDL.StateNum): states.append(-1) times.append(-1) states[child] = child times[child] = curtime if top_state < 0 or self.isParent(top_state, child): parent = self.getParentState(child) if self.isHistoryState(child): self.history[child].Submodel = self.Submodels[child] while parent >= 0 and times[parent] != curtime: states[parent] = child times[parent] = curtime if self.isHistoryState(parent): self.mergeHistory(parent, states, times) if parent == top_state: break child = parent parent = self.getParentState(child) s = s.Next def hasHistoryRecorded(self, state): for i in range(ButtonBehaviour_MDL.StateNum): if self.history[state].States[i] != -1: return 1 if self.Submodels[state] != None: return 1 return 0 def hasOrthogonalStateInBetween(self, parent, leaf): return ButtonBehaviour_MDL.OrthogonalInBetween[parent + 1][leaf] def check_history(self, dest): s = self.state while s != None: if self.isParent( dest, s.StateID) and not self.hasOrthogonalStateInBetween( dest, s.StateID): return 0 s = s.Next return 1 def getEnabledEvents(self): events = EventList() if self.isInState(1): events.Append("(create)*") if self.isInState(2): events.Append("<Any-ButtonRelease-1>") if self.isInState(2): events.Append("<ButtonPress-1>") if self.isInState(0): events.Append("[Done]") return events.Next def getHierarchy(self, start_level, state_prefix): h = Hierarchy() lasth = h # Generate state "Activate Button*" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Activate Button*" if state_prefix == None: lasth.Next.PathName = "Activate Button*" else: lasth.Next.PathName = state_prefix + ".Activate Button*" lasth.Next.StateNum = 0 lasth.Next.Level = start_level + 0 lasth = lasth.Next # Generate state "Default" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Default" if state_prefix == None: lasth.Next.PathName = "Default" else: lasth.Next.PathName = state_prefix + ".Default" lasth.Next.StateNum = 1 lasth.Next.Level = start_level + 0 lasth = lasth.Next # Generate state "Idle" in the hierarchy table lasth.Next = Hierarchy() lasth.Next.StateName = "Idle" if state_prefix == None: lasth.Next.PathName = "Idle" else: lasth.Next.PathName = state_prefix + ".Idle" lasth.Next.StateNum = 2 lasth.Next.Level = start_level + 0 lasth = lasth.Next return h.Next def topLevelHistory(self): s = self.state.StateID t = self.getParentState(s) while t != -1: s = t t = self.getParentState(s) self.changeState(s, s) def runActionCode(self, code_num): if code_num == 0: # model finalizer pass elif code_num == 1: # model initializer pass elif code_num == 2: # output action(s) of a transition self.runCode("self = eventhandler.get_event_params()") self.runCode("atom3i = self.parent") self.runCode("cb = atom3i.cb") elif code_num == 3: # output action(s) of a transition self.runCode("event = eventhandler.get_event_params()") self.runCode("event._isHandled = True") elif code_num == 4: # output action(s) of a transition self.runCode("event = eventhandler.get_event_params()") self.runCode("event._isHandled = True") elif code_num == 5: # enter actions for state "Activate Button*" self.runCode("event = eventhandler.get_event_params()") self.runCode("from FSB_Code.Constructor import buttonActivation") self.runCode("buttonActivation(self)") self.runCode("eventhandler.event(\'[Done]\')") def testCondition(self, cond_num): if cond_num==0 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==1 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==2 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==3 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 return 0 def runEnterActions(self, state): if state == 0: # enter action(s) for state "Activate Button*" self.runActionCode(5) def runExitActions(self, state): pass def compareSchedule(self, sched_a, sched_b): return cmp(sched_a[1], sched_b[1]) def addSchedule(self, id, interval, event, scheduler): if self.Parent != None: # Non-top-level model self.Parent.addSchedule(id, interval, event, scheduler) return f = eval(interval, self.DefaultInterpreter.locals) ##self.SchedulerCond.acquire() t = time.time() + f s = [id, t, interval, event, scheduler] self.Schedules.append(s) self.Schedules.sort(self.compareSchedule) ##self.SchedulerCond.notify() ##self.SchedulerCond.release() def removeSchedule(self, id, scheduler): if self.Parent != None: # Non-top-level model self.Parent.removeSchedule(id, scheduler) return ##self.SchedulerCond.acquire() i = 0 while i < len(self.Schedules): if self.Schedules[i][0] == id and self.Schedules[i][4] == scheduler: del self.Schedules[i] else: i = i + 1 ##self.SchedulerCond.release() def scheduler(self): if (not self.Schedules): return while (self.Schedules and self.Schedules[0][1] <= time.time()): this_sched = self.Schedules[0] del self.Schedules[0] self.event(this_sched[3], [], None, this_sched[4]) if self.Schedules: t = self.Schedules[0][1] - time.time() def recordAllEnteredStates(self): st = self.state while st != None: self.recordEnteredState(st.StateID, 1, 1) st = st.Next def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1): # test if s is already recorded se = self.StatesEntered found = 0 while se != None: if se.int == s: found = 1 break se = se.Next if not found: if superstates: parent = self.getParentState(s) if parent >= 0 and parent != commonstate: self.recordEnteredState(parent, 1, 0, commonstate) st = IntList() st.Next = self.StatesEntered st.int = s self.StatesEntered = st if submodel and self.Submodels[s]: self.Submodels[s].recordAllEnteredStates() def runAllEnterActions(self): self.runEnterActionsForStates(self.StatesEntered, 1) def runEnterActionsForStates(self, states, recursive=0): if states: self.runEnterActionsForStates(states.Next, 0) self.runEnterActions(states.int) if recursive: for s in self.Submodels: if s: s.runAllEnterActions() def runExitActionsForStates(self, common_state): substates = self.getSubstates(common_state) if substates == None: s = self.state while s != None and s.StateID != common_state: s = s.Next if s != None and self.Submodels[s.StateID]: self.Submodels[s.StateID].runExitActionsForStates(-1) return s != None else: has_current_substate = 0 while substates != None: res = self.runExitActionsForStates(substates.int) has_current_substate = has_current_substate or res if res: self.runExitActions(substates.int) substates = substates.Next return has_current_substate def runInitializer(self): self.runActionCode(1) for s in self.Submodels: if s: s.runInitializer() def runFinalizer(self): if self.Started: self.Started = 0 for s in self.Submodels: if s: s.runFinalizer() self.runActionCode(0) if self.Parent == None: # Top-level model ##self.EventsCond.acquire() ##self.SchedulerCond.acquire() self.Stopped = 1 ##self.EventsCond.notify() ##self.SchedulerCond.notify() ##self.SchedulerCond.release() ##self.EventsCond.release() else: self.Stopped = 1 def clearEnteredStates(self): self.StatesEntered = None for s in self.Submodels: if s: s.clearEnteredStates() def get_current_state(self): return self.getCurrentState() def runCode(self, c): self.DefaultInterpreter.runsource(c + "\n", "<input>", "exec") def setupInterpreter(self): self.DefaultInterpreter.locals["eventhandler"] = self self.DefaultInterpreter.locals["dump_message"] = self.dump_message def get_event_params(self): return self.params def dump_message(self, msg): print msg def is_in_state(self, s, check_substate=1): return self.isInState(s, check_substate) def start(self, lock=None, run_enter_actions=1, TkInstance=None): if self.Parent == None: # Top-level model if run_enter_actions: self.runEnterActionsForStates(self.StatesEntered, 1) self.Started = 1 if (TkInstance): self.sleepMethod = TkInstance.after startTkMainloop = False else: import Tkinter TkInstance = Tkinter.Tk() self.sleepMethod = TkInstance.after startTkMainloop = True self.pollingStation() ##thread.start_new_thread(self.handleEvent_wrapper, ()) ##thread.start_new_thread(self.scheduler, ()) ## if lock: ## lock.release() else: self.Started = 1 for submodel in self.Submodels: if submodel != None: submodel.start() if (self.Parent == None and startTkMainloop == None): TkInstance.mainloop() def pollingStation(self): self.sleepMethod(100, self.pollingStation) if self.Stopped: return #self.handleEvent_wrapper() self.scheduler() #todo: pollingStation\, def shutdown(self): pass def handleEvent_wrapper(self): if (self.PendingEvents == None): return event = self.PendingEvents self.PendingEvents = self.PendingEvents.Next if self.PendingEvents == None: self.PendingEventsTail = None event.next = None self.handleEvent(event.Event[0], event.Event[1], event.Event[2], event.Event[3]) self.handleEvent_wrapper() def event(self, e, params=[], cond=None, scheduler=None): ev = EventList() ev.Event = [e, params, cond, scheduler] if self.PendingEventsTail != None: self.PendingEventsTail.Next = ev else: self.PendingEvents = ev self.PendingEventsTail = ev self.handleEvent_wrapper()
statinfo = os.stat(PyAnswers) if not stat.S_ISFIFO(statinfo.st_mode): os.unlink(PyAnswers) os.mkfifo(PyAnswers) try: OUTPUT = open(PyAnswers, 'w') except IOError: print "Can't open " + PyAnswers else: # for simplicity, we redirect # anything the script outputs sError = sys.stderr sOutput = sys.stdout sys.stderr = OUTPUT sys.stdout = OUTPUT # execute command line(s) if PyShell.runsource(str(commandLine)) : # the command is not complete print "... " commandLine += "\n" else: # the command was complete print ">>> " commandLine = '' OUTPUT.close() # restore the streams sys.stdout, sys.stderr = sOutput, sError
def runsource(self, source): # Extend base class to stuff the source in the line cache first filename = self.stuffsource(source) self.more = 0 return InteractiveInterpreter.runsource(self, source, filename)
class PyCute(QMultiLineEdit): """ PyCute is a Python shell for PyQt. Creating, displaying and controlling PyQt widgets from the Python command line interpreter is very hard, if not, impossible. PyCute solves this problem by interfacing the Python interpreter to a PyQt widget. My use is interpreter driven plotting to QwtPlot instances. Why? Other popular scientific software packages like SciPy, SciLab, Octave, Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting. It is well adapted to quick & dirty exploration. Of course, PyQt's debugger -- eric -- gives you similar facilities, but PyCute is smaller and easier to integrate in applications. Eric requires Qt-3.x PyCute is based on ideas and code from: - Python*/Tools/idle/PyShell.py (Python Software Foundation License) - PyQt*/eric/Shell.py (Gnu Public License) """ def __init__(self, locals=None, log='', parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QMultiLineEdit.__init__(self, parent) self.interpreter = Interpreter(locals) # session log self.log = log or '' # to exit the main interpreter by a Ctrl-D if PyCute has no parent if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self # last line + last incomplete lines self.line = QString() self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.xLast = 0 self.yLast = 0 # user interface setup # no word wrapping simplifies cursor <-> numLines() mapping self.setWordWrap(QMultiLineEdit.NoWrap) self.setCaption('PyCute -- a Python Shell for PyQt --' 'http://gerard.vermeulen.free.fr') # font if os.name == 'posix': font = QFont("Fixed", 12) elif os.name == 'nt' or os.name == 'dos': font = QFont("Courier New", 8) else: raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'" font.setFixedPitch(1) self.setFont(font) # geometry height = 40*QFontMetrics(font).lineSpacing() request = QSize(600, height) if parent is not None: request = request.boundedTo(parent.size()) self.resize(request) # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " # interpreter banner self.write('The PyCute shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.write(sys.ps1) def flush(self): """ Simulate stdin, stdout, and stderr. """ pass def isatty(self): """ Simulate stdin, stdout, and stderr. """ return 1 def readline(self): """ Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() self.__moveCursorToEnd() while self.reading: qApp.processOneEvent() if self.line.length() == 0: return '\n' else: return str(self.line) def write(self, text): """ Simulate stdin, stdout, and stderr. """ # The output of self.append(text) contains to many newline characters, # so work around QTextEdit's policy for handling newline characters. hack = self.text() hack.append(text) self.setText(hack) #self.setText(self.text().append(text)) # segmentation fault self.yLast, self.xLast = self.__moveCursorToEnd() def writelines(self, text): """ Simulate stdin, stdout, and stderr. """ map(self.write, text) print "DO WE EVER GET HERE? IF YES, OPTIMIZATION POSSIBLE" def fakeUser(self, lines): """ Simulate a user: lines is a sequence of strings (Python statements). """ for line in lines: self.line = QString(line.rstrip()) self.write(self.line) self.write('\n') self.__run() def __run(self): """ Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ self.pointer = 0 self.history.append(QString(self.line)) self.lines.append(str(self.line)) source = '\n'.join(self.lines) self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() def __clearLine(self): """ Clear input line buffer """ self.line.truncate(0) self.point = 0 def __insertText(self, text): """ Insert text at the current cursor position. """ y, x = self.getCursorPosition() self.insertAt(text, y, x) self.line.insert(self.point, text) self.point += text.length() self.setCursorPosition(y, x + text.length()) def __moveCursorToEnd(self): y = self.numLines()-1 x = self.lineLength(y) self.setCursorPosition(y, x) return y, x def keyPressEvent(self, e): """ Handle user input a key at a time. """ text = e.text() key = e.key() ascii = e.ascii() if text.length() and ascii>=32 and ascii<127: self.__insertText(text) return if e.state() & Qt.ControlButton and key == self.eofKey: try: file = open(self.log, "w") file.write(str(self.text())) file.close() except: pass sys.exit() return if e.state() & Qt.ControlButton or e.state() & Qt.ShiftButton: e.ignore() return if key == Qt.Key_Backspace: if self.point: self.backspace() self.point -= 1 self.line.remove(self.point, 1) elif key == Qt.Key_Delete: self.delChar() self.line.remove(self.point, 1) elif key == Qt.Key_Return or key == Qt.Key_Enter: self.write('\n') if self.reading: self.reading = 0 else: self.__run() elif key == Qt.Key_Tab: self.__insertText(text) elif key == Qt.Key_Left: if self.point: self.cursorLeft() self.point -= 1 elif key == Qt.Key_Right: if self.point < self.line.length(): self.cursorRight() self.point += 1 elif key == Qt.Key_Home: self.setCursorPosition(self.yLast, self.xLast) self.point = 0 elif key == Qt.Key_End: self.end() self.point = self.line.length() elif key == Qt.Key_Up: if len(self.history): if self.pointer == 0: self.pointer = len(self.history) self.pointer -= 1 self.__recall() elif key == Qt.Key_Down: if len(self.history): self.pointer += 1 if self.pointer == len(self.history): self.pointer = 0 self.__recall() else: e.ignore() def __recall(self): """ Display the current item from the command history. """ self.setCursorPosition(self.yLast, self.xLast) self.killLine() # QMultiLineEdit self.__clearLine() # self.line self.__insertText(self.history[self.pointer]) def focusNextPrevChild(self, next): """ Suppress tabbing to the next window in multi-line commands. """ if next and self.more: return 0 return QMultiLineEdit.focusNextPrevChild(self, next) def mousePressEvent(self, e): """ Keep the cursor after the last prompt. """ if e.button() == Qt.LeftButton: self.__moveCursorToEnd() return def contentsContextMenuEvent(self,ev): """ Suppress the right button context menu. """ return
def runStartupCommands(self, locals): interp = InteractiveInterpreter(locals) """Execute the startup commands that import default modules""" interp.runsource("import os") interp.runsource("import sys") interp.runsource("import wx") interp.runsource("import vtk") interp.runsource("import numpy") interp.runsource("np = numpy") interp.runsource("import coda") interp.runsource("import harp") interp.runsource("import visan") interp.runsource("import visan.math") interp.runsource("from visan.commands import *") self.version = interp.locals['visan'].VERSION self.component_versions = [ "Python %d.%d.%d" % (sys.version_info[0], sys.version_info[1], sys.version_info[2]), "wxPython %s" % interp.locals['wx'].VERSION_STRING, "VTK %s" % interp.locals['vtk'].VTK_VERSION, "NumPy %s" % interp.locals['numpy'].__version__, "CODA %s" % interp.locals['coda'].version(), "HARP %s" % interp.locals['harp'].version(), ]
class QPyShell(QWidget): """QPyShell - a Qt based python command shell based on code.InteractiveInterpreter. Because it catches stdout and stderr there can be only one active instance of this class. Make sure initInterpreter() and exitInterpreter() is called! """ activeInstance = None def __init__(self, parent=None): QWidget.__init__(self, parent) if parent: self.standalone = False else: self.standalone = True self.setWindowTitle(QCoreApplication.translate("QPyShell", "QPyShell - a simple python shell widget for Qt")) self.mainLayout = QVBoxLayout(self) self.outputBrowser = QTextEdit(self) self.outputBrowser.setMinimumSize(QSize(100,100)) self.outputBrowser.setReadOnly(True) self.mainLayout.addWidget(self.outputBrowser) self.clLayout = QHBoxLayout() self.mainLayout.addLayout(self.clLayout) self.promptLabel = QLabel() self.promptLabel.setText(">>>") self.clLayout.addWidget(self.promptLabel) self.lineInput = QLineEdit() self.lineInput.setToolTip(QCoreApplication.translate('QPyShell', 'The python commandline: enter code her')) self.clLayout.addWidget(self.lineInput) self.enterButton = QToolButton(self) self.enterButton.setText(QCoreApplication.translate("QPyShell", "Enter")) self.enterButton.setToolTip(QCoreApplication.translate('QPyShell', 'This button or [Enter] executes the command')) self.enterButton.setIcon(QIcon(QPixmap(enterXPM))) self.clLayout.addWidget(self.enterButton) self.clLayout.addSpacing(8) self.clearButton = QToolButton(self) self.clearButton.setText(QCoreApplication.translate("QPyShell", "Clear")) self.clearButton.setToolTip(QCoreApplication.translate('QPyShell', 'Clear the output window')) self.clearButton.setIcon(QIcon(QPixmap(clearXPM))) self.clLayout.addWidget(self.clearButton) self.saveButton = QToolButton(self) self.saveButton.setText(QCoreApplication.translate("QPyShell", "Save ...")) self.saveButton.setToolTip(QCoreApplication.translate('QPyShell', 'Save the contents of the output window')) self.saveButton.setIcon(QIcon(QPixmap(saveXPM))) self.clLayout.addWidget(self.saveButton) self.printButton = QToolButton(self) self.printButton.setText(QCoreApplication.translate("QPyShell", "Print")) self.printButton.setToolTip(QCoreApplication.translate('QPyShell', 'Print the contents of the output window')) self.printButton.setIcon(QIcon(QPixmap(printXPM))) self.clLayout.addWidget(self.printButton) self.history = [] self.historyFile = None self.history_i = -1 self.cmdBuffer = [] self.showCompletionLimit = 100 self.interpreter = None self.old_displayhook = None self.cursor = QTextCursor(self.outputBrowser.document()) self.outputBrowser.setTextCursor(self.cursor) self.outputBrowser.append(greeting) self.setTabOrder(self.lineInput, self.outputBrowser) self.setTabOrder(self.outputBrowser, self.enterButton) self.setTabOrder(self.enterButton, self.saveButton) self.setTabOrder(self.saveButton, self.clearButton) self.connect(self.enterButton, SIGNAL("pressed()"), self.run) self.connect(self.saveButton, SIGNAL("pressed()"), self.saveContents) self.connect(self.printButton, SIGNAL("pressed()"), self.printContents) self.connect(self.clearButton, SIGNAL("pressed()"), self.outputBrowser.clear) def initInterpreter(self, loc=None, greet=greeting, historyFile=None): if QPyShell.activeInstance: raise Exception(QCoreApplication.translate("QPyShell", "QPyShell: There can be only one highlander... sorry, I mean one active QPyShell widget!")) QPyShell.activeInstance = self self.loadHistoryFile(historyFile) self.interpreter = InteractiveInterpreter(loc) self.completer = Completer(loc) self.old_stdout = sys.stdout self.old_stderr = sys.stderr sys.stdout = DummyFileW(self.write) sys.stderr = sys.stdout # there's a strange problem with gettext and interactive interpreters # gettext's "_"" will be overwritten by the standard sys.displayhook... self.old_displayhook = sys.displayhook sys.displayhook = mydisplayhook def loadHistoryFile(self, historyFile): self.historyFile = historyFile if historyFile and os.path.exists(historyFile): lines = open(historyFile, 'r').read().split(os.linesep) self.history = [l for l in lines if not l.startswith('#')] def saveHistoryFile(self): if self.historyFile: h = self.history if len(h) > 100: h = h[:100] h.insert(0, unicode(QCoreApplication.translate('QPyShell', '# this is the command history of the QPyShell'))) open(self.historyFile, 'w').write(os.linesep.join(h)) def exitInterpreter(self, loc=None): sys.stdout = self.old_stdout sys.stderr = self.old_stderr self.saveHistoryFile() del self.interpreter self.interpreter = None sys.displayhook = self.old_displayhook QPyShell.ativeInstance = None def run(self): if not self.interpreter: raise Exception(QCoreApplication.translate("QPyShell", "No interpreter found! You need to call QPyShell.initInterpreter() first!")) line = unicode(self.lineInput.text()) self.lineInput.clear() if line: if (not self.history) or line != self.history[0]: # no consecutive identical entries self.history.insert(0, line) self.history_i = -1 self.cursor.movePosition(QTextCursor.End) if not self.cmdBuffer: self.cursor.insertHtml('<br><b>|>>> %s</b><br>' % formatPyLine(line)) else: self.cursor.insertHtml('<br><b>|. . . %s</b><br>' % formatPyLine(line)) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() self.cmdBuffer.append(line) more = self.interpreter.runsource('\n'.join(self.cmdBuffer)) if more: self.promptLabel.setText('...') else: self.cmdBuffer = [] self.promptLabel.setText('>>>') def appendHtml(self, txt): self.cursor.movePosition(QTextCursor.End) self.cursor.insertHtml(txt) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() def appendText(self, txt): self.cursor.movePosition(QTextCursor.End) self.outputBrowser.insertPlainText(txt) self.cursor.movePosition(QTextCursor.End) self.outputBrowser.ensureCursorVisible() write = appendText def keyPressEvent(self, event): key = event.key() mod = event.modifiers() if key == Qt.Key_Up and self.history: self.history_i = min(self.history_i+1, len(self.history)-1) self.lineInput.setText(self.history[self.history_i]) elif key == Qt.Key_Down and self.history: self.history_i = max(self.history_i-1, -1) if self.history_i >= 0: self.lineInput.setText(self.history[self.history_i]) else: self.lineInput.setText('') elif key == Qt.Key_Enter or key == Qt.Key_Return: if mod & Qt.ShiftModifier: self.complete() else: self.run() elif key == Qt.Key_Escape: txt, r = QInputDialog.getItem(self, QCoreApplication.translate("QPyShell", "Command line history"), QCoreApplication.translate("QPyShell", "Please select a history item:"), self.history, 0, False) if r and txt: self.lineInput.setText(txt) elif self.standalone and key == Qt.Key_Print: self.printContents() elif self.standalone and key == Qt.Key_Q and (mod & Qt.ControlModifier): self.close() else: QWidget.keyPressEvent(self, event) def closeEvent(self, event): if self.standalone: self.exitInterpreter() QWidget.closeEvent(self, event) def printContents(self, printer=None): if not printer: printer = QPrinter() dialog = QPrintDialog(printer, self) dialog.setWindowTitle(QCoreApplication.translate("QPyShell", "Print Document")) if dialog.exec_() != QDialog.Accepted: return self.outputBrowser.document().print_(printer) def saveContents(self, fileName=None): if not fileName: fileTypes = {'Text':('txt',), 'HTML':('htm', 'html')} filters = ';;'.join(['%s (%s)' % (k, ' '.join(['*.'+e for e in v])) for k, v in fileTypes.items()]) dlg = QFileDialog(self, QCoreApplication.translate('QPyShell', 'Select name of file to save'), os.getcwd(), filters) dlg.setFileMode(QFileDialog.AnyFile) dlg.setAcceptMode(QFileDialog.AcceptSave) if dlg.exec_() != QDialog.Accepted: return tmp = unicode(dlg.selectedFilter()) fileType = tmp[:tmp.find('(')-1] dlg.setDefaultSuffix(fileTypes[fileType][0]) files = dlg.selectedFiles() if not files: return fileName = unicode(files[0]) if fileType == 'Text': txt = self.outputBrowser.toPlainText() elif fileType == 'HTML': txt = self.outputBrowser.toHtml() else: raise IOError('Unknown FileType: %s' % fileType) try: open(fileName, 'w').write(txt) except IOError: QMessageBox.critical(self, QCoreApplication.translate('QPyShell', 'Could not save file!'), QCoreApplication.translate('QPyShell', 'Writing failed! Make sure you have write permissions!')) def complete(self): """ a very simple, quick and dirty completion of identifiers in the namespace """ # FIXME: fertig machen! txt = unicode(self.lineInput.text()) cur = self.lineInput.cursorPosition() s = cur while s>0 and txt[s-1] in identChars: s -= 1 try: completions = self.completer.matches(txt[s:cur]) except: return if not completions: return n_comp = len(completions) if n_comp == 1: comp = completions.pop() self.lineInput.insert(comp[cur-s:]) elif n_comp < self.showCompletionLimit: tmp = list(completions) tmp.sort() self.appendHtml('<font color="#0000ff">[%s]</font>' % ', '.join(tmp)) # get common prefix ... stolen from the python cookbook pref = tmp[0][:([min([x[0]==elem for elem in x]) for x in zip(*tmp)]+[0]).index(0)] if len(pref) > (cur-s): self.lineInput.insert(pref[cur-s:]) else: self.appendHtml(unicode(QCoreApplication.translate("QPyShell", '<font color="#0000ff">[Too many completions: %d]</font>')) % n_comp)
class Module(MgrModule): """ This module is for testing the ceph-mgr python interface from within a running ceph-mgr daemon. It implements a sychronous self-test command for calling the functions in the MgrModule interface one by one, and a background "workload" command for causing the module to perform some thrashing-type activities in its serve() thread. """ # The test code in qa/ relies on these options existing -- they # are of course not really used for anything in the module MODULE_OPTIONS = [ Option(name='testkey'), Option(name='testlkey'), Option(name='testnewline'), Option(name='roption1'), Option(name='roption2', type='str', default='xyz'), Option(name='rwoption1'), Option(name='rwoption2', type='int'), Option(name='rwoption3', type='float'), Option(name='rwoption4', type='str'), Option(name='rwoption5', type='bool'), Option(name='rwoption6', type='bool', default=True), Option(name='rwoption7', type='int', min=1, max=42), ] def __init__(self, *args: Any, **kwargs: Any) -> None: super(Module, self).__init__(*args, **kwargs) self._event = threading.Event() self._workload: Optional[Workload] = None self._health: Dict[str, Dict[str, Any]] = {} self._repl = InteractiveInterpreter(dict(mgr=self)) @CLICommand('mgr self-test python-version', perm='r') def python_version(self) -> Tuple[int, str, str]: ''' Query the version of the embedded Python runtime ''' major = sys.version_info.major minor = sys.version_info.minor micro = sys.version_info.micro return 0, f'{major}.{minor}.{micro}', '' @CLICommand('mgr self-test run') def run(self) -> Tuple[int, str, str]: ''' Run mgr python interface tests ''' self._self_test() return 0, '', 'Self-test succeeded' @CLICommand('mgr self-test background start') def backgroun_start(self, workload: Workload) -> Tuple[int, str, str]: ''' Activate a background workload (one of command_spam, throw_exception) ''' self._workload = workload self._event.set() return 0, '', 'Running `{0}` in background'.format(self._workload) @CLICommand('mgr self-test background stop') def background_stop(self) -> Tuple[int, str, str]: ''' Stop background workload if any is running ''' if self._workload: was_running = self._workload self._workload = None self._event.set() return 0, '', 'Stopping background workload `{0}`'.format( was_running) else: return 0, '', 'No background workload was running' @CLICommand('mgr self-test config get') def config_get(self, key: str) -> Tuple[int, str, str]: ''' Peek at a configuration value ''' return 0, str(self.get_module_option(key)), '' @CLICommand('mgr self-test config get_localized') def config_get_localized(self, key: str) -> Tuple[int, str, str]: ''' Peek at a configuration value (localized variant) ''' return 0, str(self.get_localized_module_option(key)), '' @CLICommand('mgr self-test remote') def test_remote(self) -> Tuple[int, str, str]: ''' Test inter-module calls ''' self._test_remote_calls() return 0, '', 'Successfully called' @CLICommand('mgr self-test module') def module(self, module: str) -> Tuple[int, str, str]: ''' Run another module's self_test() method ''' try: r = self.remote(module, "self_test") except RuntimeError as e: return -1, '', "Test failed: {0}".format(e) else: return 0, str(r), "Self-test OK" @CLICommand('mgr self-test cluster-log') def do_cluster_log(self, channel: str, priority: str, message: str) -> Tuple[int, str, str]: ''' Create an audit log record. ''' priority_map = { 'info': self.ClusterLogPrio.INFO, 'security': self.ClusterLogPrio.SEC, 'warning': self.ClusterLogPrio.WARN, 'error': self.ClusterLogPrio.ERROR } self.cluster_log(channel, priority_map[priority], message) return 0, '', 'Successfully called' @CLICommand('mgr self-test health set') def health_set(self, checks: str) -> Tuple[int, str, str]: ''' Set a health check from a JSON-formatted description. ''' try: health_check = json.loads(checks) except Exception as e: return -1, "", "Failed to decode JSON input: {}".format(e) try: for check, info in health_check.items(): self._health[check] = { "severity": str(info["severity"]), "summary": str(info["summary"]), "count": 123, "detail": [str(m) for m in info["detail"]] } except Exception as e: return -1, "", "Invalid health check format: {}".format(e) self.set_health_checks(self._health) return 0, "", "" @CLICommand('mgr self-test health clear') def health_clear(self, checks: Optional[List[str]] = None) -> Tuple[int, str, str]: ''' Clear health checks by name. If no names provided, clear all. ''' if checks is not None: for check in checks: if check in self._health: del self._health[check] else: self._health = dict() self.set_health_checks(self._health) return 0, "", "" @CLICommand('mgr self-test insights_set_now_offset') def insights_set_now_offset(self, hours: int) -> Tuple[int, str, str]: ''' Set the now time for the insights module. ''' self.remote("insights", "testing_set_now_time_offset", hours) return 0, "", "" def _self_test(self) -> None: self.log.info("Running self-test procedure...") self._self_test_osdmap() self._self_test_getters() self._self_test_config() self._self_test_store() self._self_test_misc() self._self_test_perf_counters() def _self_test_getters(self) -> None: self.version self.get_context() self.get_mgr_id() # In this function, we will assume that the system is in a steady # state, i.e. if a server/service appears in one call, it will # not have gone by the time we call another function referring to it objects = [ "fs_map", "osdmap_crush_map_text", "osd_map", "config", "mon_map", "service_map", "osd_metadata", "pg_summary", "pg_status", "pg_dump", "pg_ready", "df", "pg_stats", "pool_stats", "osd_stats", "osd_ping_times", "health", "mon_status", "mgr_map" ] for obj in objects: assert self.get(obj) is not None assert self.get("__OBJ_DNE__") is None servers = self.list_servers() for server in servers: self.get_server(server['hostname']) # type: ignore osdmap = self.get('osd_map') for o in osdmap['osds']: osd_id = o['osd'] self.get_metadata("osd", str(osd_id)) self.get_daemon_status("osd", "0") def _self_test_config(self) -> None: # This is not a strong test (can't tell if values really # persisted), it's just for the python interface bit. self.set_module_option("testkey", "testvalue") assert self.get_module_option("testkey") == "testvalue" self.set_localized_module_option("testkey", "foo") assert self.get_localized_module_option("testkey") == "foo" # Must return the default value defined in MODULE_OPTIONS. value = self.get_localized_module_option("rwoption6") assert isinstance(value, bool) assert value is True # Use default value. assert self.get_module_option("roption1") is None assert self.get_module_option("roption1", "foobar") == "foobar" assert self.get_module_option("roption2") == "xyz" assert self.get_module_option("roption2", "foobar") == "xyz" # Option type is not defined => return as string. self.set_module_option("rwoption1", 8080) value = self.get_module_option("rwoption1") assert isinstance(value, str) assert value == "8080" # Option type is defined => return as integer. self.set_module_option("rwoption2", 10) value = self.get_module_option("rwoption2") assert isinstance(value, int) assert value == 10 # Option type is defined => return as float. self.set_module_option("rwoption3", 1.5) value = self.get_module_option("rwoption3") assert isinstance(value, float) assert value == 1.5 # Option type is defined => return as string. self.set_module_option("rwoption4", "foo") value = self.get_module_option("rwoption4") assert isinstance(value, str) assert value == "foo" # Option type is defined => return as bool. self.set_module_option("rwoption5", False) value = self.get_module_option("rwoption5") assert isinstance(value, bool) assert value is False # Option value range is specified try: self.set_module_option("rwoption7", 43) except Exception as e: assert isinstance(e, ValueError) else: message = "should raise if value is not in specified range" assert False, message # Specified module does not exist => return None. assert self.get_module_option_ex("foo", "bar") is None # Specified key does not exist => return None. assert self.get_module_option_ex("dashboard", "bar") is None self.set_module_option_ex("telemetry", "contact", "*****@*****.**") assert self.get_module_option_ex("telemetry", "contact") == "*****@*****.**" # No option default value, so use the specified one. assert self.get_module_option_ex("dashboard", "password") is None assert self.get_module_option_ex("dashboard", "password", "foobar") == "foobar" # Option type is not defined => return as string. self.set_module_option_ex("selftest", "rwoption1", 1234) value = self.get_module_option_ex("selftest", "rwoption1") assert isinstance(value, str) assert value == "1234" # Option type is defined => return as integer. self.set_module_option_ex("telemetry", "interval", 60) value = self.get_module_option_ex("telemetry", "interval") assert isinstance(value, int) assert value == 60 # Option type is defined => return as bool. self.set_module_option_ex("telemetry", "leaderboard", True) value = self.get_module_option_ex("telemetry", "leaderboard") assert isinstance(value, bool) assert value is True def _self_test_store(self) -> None: existing_keys = set(self.get_store_prefix("test").keys()) self.set_store("testkey", "testvalue") assert self.get_store("testkey") == "testvalue" assert (set(self.get_store_prefix("test").keys()) == {"testkey"} | existing_keys) def _self_test_perf_counters(self) -> None: self.get_perf_schema("osd", "0") self.get_counter("osd", "0", "osd.op") # get_counter # get_all_perf_coutners def _self_test_misc(self) -> None: self.set_uri("http://this.is.a.test.com") self.set_health_checks({}) def _self_test_osdmap(self) -> None: osdmap = self.get_osdmap() osdmap.get_epoch() osdmap.get_crush_version() osdmap.dump() inc = osdmap.new_incremental() osdmap.apply_incremental(inc) inc.get_epoch() inc.dump() crush = osdmap.get_crush() crush.dump() crush.get_item_name(-1) crush.get_item_weight(-1) crush.find_takes() crush.get_take_weight_osd_map(-1) # osdmap.get_pools_by_take() # osdmap.calc_pg_upmaps() # osdmap.map_pools_pgs_up() # inc.set_osd_reweights # inc.set_crush_compat_weight_set_weights self.log.info("Finished self-test procedure.") def _test_remote_calls(self) -> None: # Test making valid call self.remote("influx", "self_test") # Test calling module that exists but isn't enabled # (arbitrarily pick a non-always-on module to use) disabled_module = "telegraf" mgr_map = self.get("mgr_map") assert disabled_module not in mgr_map['modules'] # (This works until the Z release in about 2027) latest_release = sorted(mgr_map['always_on_modules'].keys())[-1] assert disabled_module not in mgr_map['always_on_modules'][latest_release] try: self.remote(disabled_module, "handle_command", {"prefix": "influx self-test"}) except ImportError: pass else: raise RuntimeError("ImportError not raised for disabled module") # Test calling module that doesn't exist try: self.remote("idontexist", "self_test") except ImportError: pass else: raise RuntimeError("ImportError not raised for nonexistent module") # Test calling method that doesn't exist try: self.remote("influx", "idontexist") except NameError: pass else: raise RuntimeError("KeyError not raised") def remote_from_orchestrator_cli_self_test(self, what: str) -> Any: import orchestrator if what == 'OrchestratorError': return orchestrator.OrchResult(result=None, exception=orchestrator.OrchestratorError('hello, world')) elif what == "ZeroDivisionError": return orchestrator.OrchResult(result=None, exception=ZeroDivisionError('hello, world')) assert False, repr(what) def shutdown(self) -> None: self._workload = Workload.SHUTDOWN self._event.set() def _command_spam(self) -> None: self.log.info("Starting command_spam workload...") while not self._event.is_set(): osdmap = self.get_osdmap() dump = osdmap.dump() count = len(dump['osds']) i = int(random.random() * count) w = random.random() result = CommandResult('') self.send_command(result, 'mon', '', json.dumps({ 'prefix': 'osd reweight', 'id': i, 'weight': w}), '') _ = osdmap.get_crush().dump() r, outb, outs = result.wait() self._event.clear() self.log.info("Ended command_spam workload...") @CLICommand('mgr self-test eval') def eval(self, s: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: ''' eval given source ''' source = s or inbuf if source is None: return HandleCommandResult(-1, '', 'source is not specified') err = StringIO() out = StringIO() with redirect_stderr(err), redirect_stdout(out): needs_more = self._repl.runsource(source) if needs_more: retval = 2 stdout = '' stderr = '' else: retval = 0 stdout = out.getvalue() stderr = err.getvalue() return HandleCommandResult(retval, stdout, stderr) def serve(self) -> None: while True: if self._workload == Workload.COMMAND_SPAM: self._command_spam() elif self._workload == Workload.SHUTDOWN: self.log.info("Shutting down...") break elif self._workload == Workload.THROW_EXCEPTION: raise RuntimeError("Synthetic exception in serve") else: self.log.info("Waiting for workload request...") self._event.wait() self._event.clear()
class PyCute(QMultiLineEdit): """ PyCute is a Python shell for PyQt. Creating, displaying and controlling PyQt widgets from the Python command line interpreter is very hard, if not, impossible. PyCute solves this problem by interfacing the Python interpreter to a PyQt widget. My use is interpreter driven plotting to QwtPlot instances. Why? Other popular scientific software packages like SciPy, SciLab, Octave, Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting. It is well adapted to quick & dirty exploration. Of course, PyQt's debugger -- eric -- gives you similar facilities, but PyCute is smaller and easier to integrate in applications. Eric requires Qt-3.x. """ reading = 0 history = [] pointer = 0 def __init__(self, locals=None, log='', parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QMultiLineEdit.__init__(self, parent) self.interpreter = Interpreter(locals) self.connect(self, SIGNAL("returnPressed()"), self.onReturnPressed) # session log self.log = log or 'PyCute.log' # to exit the main interpreter by a Ctrl-D if PyCute has no parent if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None # capture all interactive input/output #sys.stdout = self sys.stderr = self sys.stdin = self # user interface setup # no word wrapping simplifies cursor <-> numLines() mapping self.setWordWrap(QMultiLineEdit.WidgetWidth) self.setCaption('PyCute -- a Python Shell for PyQt --' 'http://gerard.vermeulen.free.fr') # font if os.name == 'posix': font = QFont("Fixed", 12) elif os.name == 'nt' or os.name == 'dos': font = QFont("Courier New", 8) else: raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'" font.setFixedPitch(1) self.setFont(font) # geometry height = 40*QFontMetrics(font).lineSpacing() request = QSize(600, height) if parent is not None: request = request.boundedTo(parent.size()) self.resize(request) # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " # interpreter banner self.write('The PyCute shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.ps1() # __init__() def write(self, line): self.append(line.rstrip('\r\n')) self.moveCursorToEnd() # write() def ps1(self): self.append(sys.ps1) self.mark = self.moveCursorToEnd() # ps1() def ps2(self): self.append(sys.ps2) self.moveCursorToEnd() # ps2() def tab(self): self.insert(' ') self.moveCursorMoveToEnd() # tab() def getLines(self): #print self.mark, 'pipo' position = self.getCursorPosition() apply(self.setCursorPosition, self.mark + (1,)) lines = self.markedText() apply(self.setCursorPosition, position) return str(lines) # getLines() def readline(self): """ Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() self.__moveCursorToEnd() while self.reading: qApp.processOneEvent() if self.line.length() == 0: return '\n' else: return str(self.line) def fakeUser(self, lines): """ Simulate a user: lines is a sequence of strings (Python statements). """ for line in lines: self.line = QString(line.rstrip()) self.write(self.line) self.write('\n') self.__run() def __run(self): """ Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ if self.gnu: self.pointer = 0 self.history.append(QString(self.line)) self.lines.append(str(self.line)) source = '\n'.join(self.lines) self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() def __clearLine(self): """ Clear input line buffer """ self.line.truncate(0) self.point = 0 def moveCursorToEnd(self): y = self.numLines()-1 x = self.lineLength(y) self.setCursorPosition(y, x) return y, x def push(self): lines = self.getLines() if not self.interpreter.runsource(lines.replace(sys.ps2, '')): self.history.insert(0, (self.mark, lines)) self.ps1() else: self.ps2() # push() def onReturnPressed(self): if self.reading: self.reading = 0 else: self.push() # onReturnPressed() def keyPressEvent(self, e): ascii = e.ascii() key = e.key() state = e.state() text = e.text() if state & Qt.ControlButton and key == self.eofKey: try: file = open(self.log, "w") file.write(str(self.text())) file.close() except: pass sys.exit() return if state & Qt.ControlButton and key == Qt.Key_I: self.tab() return if key == Qt.Key_Tab: # completion return if key == Qt.Key_Return and not self.reading: position = self.getCursorPosition() if self.mark > position: for mark, lines in self.history: if mark < position: apply(self.setCursorPosition, self.mark) self.insert(lines) return else: return QMultiLineEdit.keyPressEvent(self, e)
class PythonWidget(HistoryConsoleWidget): """ A basic in-process Python interpreter. """ # Emitted when a command has been executed in the interpeter. executed = QtCore.Signal() #-------------------------------------------------------------------------- # 'object' interface #-------------------------------------------------------------------------- def __init__(self, parent=None): super(PythonWidget, self).__init__(parent) # PythonWidget attributes. self.locals = dict(__name__='__console__', __doc__=None) self.interpreter = InteractiveInterpreter(self.locals) # PythonWidget protected attributes. self._buffer = StringIO() self._bracket_matcher = BracketMatcher(self._control) self._call_tip_widget = CallTipWidget(self._control) self._completion_lexer = CompletionLexer(PythonLexer()) self._hidden = False self._highlighter = PythonWidgetHighlighter(self) self._last_refresh_time = 0 # file-like object attributes. self.encoding = sys.stdin.encoding # Configure the ConsoleWidget. self.tab_width = 4 self._set_continuation_prompt('... ') # Configure the CallTipWidget. self._call_tip_widget.setFont(self.font) self.font_changed.connect(self._call_tip_widget.setFont) # Connect signal handlers. document = self._control.document() document.contentsChange.connect(self._document_contents_change) # Display the banner and initial prompt. self.reset() #-------------------------------------------------------------------------- # file-like object interface #-------------------------------------------------------------------------- def flush(self): """ Flush the buffer by writing its contents to the screen. """ self._buffer.seek(0) text = self._buffer.getvalue() self._buffer.close() self._buffer = StringIO() self._append_plain_text(text) self._control.moveCursor(QtGui.QTextCursor.End) def readline(self, prompt=None): """ Read and return one line of input from the user. """ return self._readline(prompt) def write(self, text, refresh=True): """ Write text to the buffer, possibly flushing it if 'refresh' is set. """ if not self._hidden: self._buffer.write(text) if refresh: current_time = time() if current_time - self._last_refresh_time > 0.05: self.flush() self._last_refresh_time = current_time def writelines(self, lines, refresh=True): """ Write a list of lines to the buffer. """ for line in lines: self.write(line, refresh=refresh) #--------------------------------------------------------------------------- # 'ConsoleWidget' abstract interface #--------------------------------------------------------------------------- def _is_complete(self, source, interactive): """ Returns whether 'source' can be completely processed and a new prompt created. When triggered by an Enter/Return key press, 'interactive' is True; otherwise, it is False. """ if interactive: lines = source.splitlines() if len(lines) == 1: try: return compile_command(source) is not None except: # We'll let the interpeter handle the error. return True else: return lines[-1].strip() == '' else: return True def _execute(self, source, hidden): """ Execute 'source'. If 'hidden', do not show any output. See parent class :meth:`execute` docstring for full details. """ # Save the current std* and point them here old_stdin = sys.stdin old_stdout = sys.stdout old_stderr = sys.stderr sys.stdin = sys.stdout = sys.stderr = self # Run the source code in the interpeter self._hidden = hidden try: more = self.interpreter.runsource(source) finally: self._hidden = False # Restore std* unless the executed changed them if sys.stdin is self: sys.stdin = old_stdin if sys.stdout is self: sys.stdout = old_stdout if sys.stderr is self: sys.stderr = old_stderr self.executed.emit() self._show_interpreter_prompt() def _prompt_started_hook(self): """ Called immediately after a new prompt is displayed. """ if not self._reading: self._highlighter.highlighting_on = True def _prompt_finished_hook(self): """ Called immediately after a prompt is finished, i.e. when some input will be processed and a new prompt displayed. """ if not self._reading: self._highlighter.highlighting_on = False def _tab_pressed(self): """ Called when the tab key is pressed. Returns whether to continue processing the event. """ # Perform tab completion if: # 1) The cursor is in the input buffer. # 2) There is a non-whitespace character before the cursor. text = self._get_input_buffer_cursor_line() if text is None: return False complete = bool(text[:self._get_input_buffer_cursor_column()].strip()) if complete: self._complete() return not complete #--------------------------------------------------------------------------- # 'ConsoleWidget' protected interface #--------------------------------------------------------------------------- def _event_filter_console_keypress(self, event): """ Reimplemented for smart backspace. """ if event.key() == QtCore.Qt.Key_Backspace and \ not event.modifiers() & QtCore.Qt.AltModifier: # Smart backspace: remove four characters in one backspace if: # 1) everything left of the cursor is whitespace # 2) the four characters immediately left of the cursor are spaces col = self._get_input_buffer_cursor_column() cursor = self._control.textCursor() if col > 3 and not cursor.hasSelection(): text = self._get_input_buffer_cursor_line()[:col] if text.endswith(' ') and not text.strip(): cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor, 4) cursor.removeSelectedText() return True return super(PythonWidget, self)._event_filter_console_keypress(event) def _insert_continuation_prompt(self, cursor): """ Reimplemented for auto-indentation. """ super(PythonWidget, self)._insert_continuation_prompt(cursor) source = self.input_buffer space = 0 for c in source.splitlines()[-1]: if c == '\t': space += 4 elif c == ' ': space += 1 else: break if source.rstrip().endswith(':'): space += 4 cursor.insertText(' ' * space) #--------------------------------------------------------------------------- # 'PythonWidget' public interface #--------------------------------------------------------------------------- def execute_file(self, path, hidden=False): """ Attempts to execute file with 'path'. If 'hidden', no output is shown. """ self.execute("exec(open(%s).read())" % repr(path), hidden=hidden) def reset(self): """ Resets the widget to its initial state. Similar to ``clear``, but also re-writes the banner. """ self._reading = False self._highlighter.highlighting_on = False self._control.clear() self._append_plain_text(self._get_banner()) self._show_interpreter_prompt() #--------------------------------------------------------------------------- # 'PythonWidget' protected interface #--------------------------------------------------------------------------- def _call_tip(self): """ Shows a call tip, if appropriate, at the current cursor location. """ # Decide if it makes sense to show a call tip cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.Left) if cursor.document().characterAt(cursor.position()) != '(': return False context = self._get_context(cursor) if not context: return False # Look up the context and show a tip for it symbol, leftover = self._get_symbol_from_context(context) doc = getattr(symbol, '__doc__', None) if doc is not None and not leftover: self._call_tip_widget.show_call_info(doc=doc) return True return False def _complete(self): """ Performs completion at the current cursor location. """ context = self._get_context() if context: symbol, leftover = self._get_symbol_from_context(context) if len(leftover) == 1: leftover = leftover[0] if symbol is None: names = self.interpreter.locals.keys() names += __builtin__.__dict__.keys() else: names = dir(symbol) completions = [ n for n in names if n.startswith(leftover) ] if completions: cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.Left, n=len(context[-1])) self._complete_with_items(cursor, completions) def _get_banner(self): """ Gets a banner to display at the beginning of a session. """ banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \ '"license" for more information.' return banner % (sys.version, sys.platform) def _get_context(self, cursor=None): """ Gets the context for the specified cursor (or the current cursor if none is specified). """ if cursor is None: cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.StartOfBlock, QtGui.QTextCursor.KeepAnchor) text = cursor.selection().toPlainText() return self._completion_lexer.get_context(text) def _get_symbol_from_context(self, context): """ Find a python object in the interpeter namespace from a context (a list of names). """ context = map(str, context) if len(context) == 0: return None, context base_symbol_string = context[0] symbol = self.interpreter.locals.get(base_symbol_string, None) if symbol is None: symbol = __builtin__.__dict__.get(base_symbol_string, None) if symbol is None: return None, context context = context[1:] for i, name in enumerate(context): new_symbol = getattr(symbol, name, None) if new_symbol is None: return symbol, context[i:] else: symbol = new_symbol return symbol, [] def _show_interpreter_prompt(self): """ Shows a prompt for the interpreter. """ self.flush() self._show_prompt('>>> ') #------ Signal handlers ---------------------------------------------------- def _document_contents_change(self, position, removed, added): """ Called whenever the document's content changes. Display a call tip if appropriate. """ # Calculate where the cursor should be *after* the change: position += added document = self._control.document() if position == self._get_cursor().position(): self._call_tip()
class PyConsole(QtGui.QWidget): def __init__(self,parent=None,locals=None, log='', fontSize=10, commandWidget=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_Form() self.ui.setupUi(self) # Setup TextBrowser self.ui.tb_view.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.ui.tb_view.keyPressEvent = self.tb_out_keypress # Setup Command if not commandWidget: try: import scintilla_cmd commandWidget = scintilla_cmd.cmd_widget() except: commandWidget = None if commandWidget: # Scintilla Commandline self.ui.le_cmd = commandWidget else: # Line Edit self.ui.le_cmd = QtGui.QLineEdit() self.ui.le_cmd.widgetObject = QtGui.QLineEdit self.ui.le_cmd.type = 'qlineedit' self.ui.frame.layout().addWidget(self.ui.le_cmd,0,2,1,1) self.ui.le_cmd.keyPressEvent = self.cmdKeyPress # font if os.name == 'posix': font = QtGui.QFont("Monospace", fontSize) elif os.name == 'nt' or os.name == 'dos': font = QtGui.QFont("Courier New", fontSize) else: print(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'") ## raise Exception(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'") font.setFixedPitch(1) ## self.setFont(font) self.ui.tb_view.setFont(font) self.ui.le_cmd.setFont(font) self.ui.l_prompt.setFont(font) # geometry height = 40*QtGui.QFontMetrics(font).lineSpacing() self.ui.tb_view.setTabStopWidth(QtGui.QFontMetrics(font).width(' ')-1) # Setup Interpreter if locals==None: locals={'self':self,'scope':parent} self.interpreter = Interpreter(locals) # Exit with Ctrl+D if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None ## self.viewers = [] class SplitStdErr: def __init__(self,default_stderr,console_stderr): ## self._targets=targets self.default_stderr = default_stderr self.console_stderr = console_stderr def write(self,line): self.default_stderr.write(line) self.console_stderr.write(line,mode=2) ## for target in self._targets: ## target.write(line) # capture all interactive input/output sys.stdout = self sys.stderr = SplitStdErr(sys.stderr,self) sys.stdin = self # last line + last incomplete lines self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.indent = '' self.prompt = '>>>' self.writecount = 0 # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " self.write('# Python '+'('+str(sys.version_info.major)+'.'+str(sys.version_info.minor)+'.'+str(sys.version_info.micro)+')\n',mode=1) self.write('\n') # Focus to command prompt self.ui.le_cmd.setFocus() def cmdSizeHint(self): print 'size hint' return QtCore.QSize(20,20) def enter(self): line = unicode(self.ui.le_cmd.text()) if line.strip(): self.history.append(line) self.pointer = len(self.history) ## self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ') else: line = '' # Clear if 2 blank lines in a row cmd_reset = 0 if len(self.lines) > 0: if self.lines[-1].rstrip() =='' and line.rstrip()=='': self.lines = [] cmd_reset = 1 if not cmd_reset: self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ') self.lines.append(line) if line == 'clear': # Clear Text self.prompt = '>>>' self.ui.tb_view.setText('') self.ui.le_cmd.setText('') self.lines = [] else: source = '\n'.join(self.lines) self.more = self.interpreter.runsource(source) self.indent='' if self.more: self.prompt = sys.ps2 self.indent = line[0:len(line)-len(line.lstrip())] if line.rstrip(): if line.rstrip()[-1]==':': self.indent+=' ' else: self.prompt = sys.ps1 self.lines = [] self.setCommandText(self.indent) self.ui.l_prompt.setText(self.prompt) def write(self, text,mode=0,prefix=None): # modes # 0 = output # 1 = input # 2 = error ## hack = self.ui.tb_view.toPlainText() ## hack.append(text+'\n') ## self.ui.tb_view.setText(hack) ## print len(text),len(text.rstrip()) self.writecount += 1 ## if text.rstrip() or 1: self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0) if mode == 2: # Error txt = '<font style="color:rgb(255,112,99);">' + str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','<').replace('>','>').replace(' ',' ').replace('\n','<br>')+"</font>" txt = re_file.sub(r"<a style=""color:rgb(121,213,255);"" href='\g<2>'>\g<2></a>",txt) self.ui.tb_view.insertHtml(txt) elif mode == 1: # Input txt = '<div style="color:rgb(89,197,254);">' if prefix: txt += '<span style="color:rgb(38,90,150);">'+prefix.replace('>','>')+'</span>' txt +=str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','<').replace('>','>').replace(' ',' ').replace('\n','<br>')+"</div>" self.ui.tb_view.insertHtml(txt) else: # Write txt = '<div style="color:rgb(255,255,255);">'+str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','<').replace('>','>').replace(' ',' ').replace('\n','<br>')+"</div>" self.ui.tb_view.insertHtml(txt) self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0) def cmdKeyPress(self,e): key = e.key() handled = 0 if key == Qt.Key_Up: # Up if len(self.history): if self.pointer > 0: self.pointer -= 1 self.setCommandText(self.history[self.pointer]) handled = 1 elif key == Qt.Key_Down: # Down if len(self.history) and self.pointer<len(self.history): if self.pointer == len(self.history)-1: self.setCommandText('') self.pointer += 1 handled = 1 else: self.pointer += 1 self.setCommandText(self.history[self.pointer]) handled = 1 elif key == Qt.Key_Enter or key == Qt.Key_Return: # Enter if self.reading: self.reading = 0 else: self.enter() handled = 1 elif key == Qt.Key_Tab: self.ui.le_cmd.insert(' ') handled=1 # Ctrl if e.modifiers() & QtCore.Qt.ControlModifier: if key == QtCore.Qt.Key_V: # paste # V ## txt = QtGui.QApplication.clipboard().text('plain').split(QtCore.QRegExp("[\r\n]"),QtCore.QString.SkipEmptyParts) txt = str(QtGui.QApplication.clipboard().text('plain').toUtf8()).decode('utf-8').splitlines() if len(txt) > 0: self.ui.le_cmd.insert(txt[0]) if len(txt) > 1: self.enter() for t in txt[1:-1]: self.setCommandText(t) self.enter() self.setCommandText(txt[-1]) handled = 1 elif key == QtCore.Qt.Key_L: # launch # L from subprocess import Popen try: if os.name =='nt': Popen(["pythonw",os.path.abspath(__file__)]) else: Popen(["python",os.path.abspath(__file__)]) except: QtGui.QMessageBox.warning(self,'Error','The Python Shell could not open with your default Python install. Please make sure you have Python 2.7 (or 2.6) installed and the Python executable is in your system path') if not handled: ## QtGui.QLineEdit.keyPressEvent(self.ui.le_cmd,e) self.ui.le_cmd.widgetObject.keyPressEvent(self.ui.le_cmd,e) def setCommandText(self,text): self.ui.le_cmd.setText(text) if self.ui.le_cmd.type == 'qscintilla': self.ui.le_cmd.setCursorPosition(0,len(text)) def readline(self): """ Simulate stdin, stdout, and stderr. """ self.reading = 1 self.ui.le_cmd.setText('') self.ui.l_prompt.setText('?') ## self.moveCursor(QtGui.QTextCursor.End, 0) while self.reading: QtGui.QApplication.processEvents() line = self.ui.le_cmd.text() if len(line) == 0: return_line = '\n' else: return_line = str(line) self.write('\n') return return_line def writelines(self, text): """ Simulate stdin, stdout, and stderr. """ map(self.write, text) def flush(self): """ Simulate stdin, stdout, and stderr. """ pass def isatty(self): """ Simulate stdin, stdout, and stderr. """ return 1 #---Output Overrides def tb_out_keypress(self,e): key = e.key() handled = 0 # Copy ahead of disable if e.modifiers() & QtCore.Qt.ControlModifier: # Copy if key == Qt.Key_C: txt = str(self.ui.tb_view.textCursor().selectedText().toUtf8()).replace('\xc2\xa0',' ').decode('utf-8') ## QtGui.QApplication.clipboard().clear() ntxt = [] for ln in txt.splitlines(): t = ln if ln.startswith('>>> ') or ln.startswith('... '): t = ln[4:] ntxt.append(t) txt = '\n'.join(ntxt) QtGui.QApplication.clipboard().setText(txt) handled = 1 if not handled: QtGui.QTextEdit.keyPressEvent(self.ui.tb_view,e)
class PyConsole(QtGui.QWidget): def __init__(self, parent=None, locals=None, log='', fontSize=10, commandWidget=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_Form() self.ui.setupUi(self) # Setup TextBrowser self.ui.tb_view.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.ui.tb_view.keyPressEvent = self.tb_out_keypress # Setup Command if not commandWidget: try: import scintilla_cmd commandWidget = scintilla_cmd.cmd_widget() except: commandWidget = None if commandWidget: # Scintilla Commandline self.ui.le_cmd = commandWidget else: # Line Edit self.ui.le_cmd = QtGui.QLineEdit() self.ui.le_cmd.widgetObject = QtGui.QLineEdit self.ui.le_cmd.type = 'qlineedit' self.ui.frame.layout().addWidget(self.ui.le_cmd, 0, 2, 1, 1) self.ui.le_cmd.keyPressEvent = self.cmdKeyPress # font if os.name == 'posix': font = QtGui.QFont("Monospace", fontSize) elif os.name == 'nt' or os.name == 'dos': font = QtGui.QFont("Courier New", fontSize) else: print(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'") ## raise Exception(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'") font.setFixedPitch(1) ## self.setFont(font) self.ui.tb_view.setFont(font) self.ui.le_cmd.setFont(font) self.ui.l_prompt.setFont(font) # geometry height = 40 * QtGui.QFontMetrics(font).lineSpacing() self.ui.tb_view.setTabStopWidth( QtGui.QFontMetrics(font).width(' ') - 1) # Setup Interpreter if locals == None: locals = {'self': self, 'scope': parent} self.interpreter = Interpreter(locals) # Exit with Ctrl+D if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None ## self.viewers = [] class SplitStdErr: def __init__(self, default_stderr, console_stderr): ## self._targets=targets self.default_stderr = default_stderr self.console_stderr = console_stderr def write(self, line): self.default_stderr.write(line) self.console_stderr.write(line, mode=2) ## for target in self._targets: ## target.write(line) # capture all interactive input/output sys.stdout = self sys.stderr = SplitStdErr(sys.stderr, self) sys.stdin = self # last line + last incomplete lines self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.indent = '' self.prompt = '>>>' self.writecount = 0 # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " self.write('# Python ' + '(' + str(sys.version_info.major) + '.' + str(sys.version_info.minor) + '.' + str(sys.version_info.micro) + ')\n', mode=1) self.write('\n') # Focus to command prompt self.ui.le_cmd.setFocus() def cmdSizeHint(self): print 'size hint' return QtCore.QSize(20, 20) def enter(self): line = unicode(self.ui.le_cmd.text()) if line.strip(): self.history.append(line) self.pointer = len(self.history) ## self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ') else: line = '' # Clear if 2 blank lines in a row cmd_reset = 0 if len(self.lines) > 0: if self.lines[-1].rstrip() == '' and line.rstrip() == '': self.lines = [] cmd_reset = 1 if not cmd_reset: self.write(line + '\n', mode=1, prefix=unicode(self.ui.l_prompt.text()) + ' ') self.lines.append(line) if line == 'clear': # Clear Text self.prompt = '>>>' self.ui.tb_view.setText('') self.ui.le_cmd.setText('') self.lines = [] else: source = '\n'.join(self.lines) self.more = self.interpreter.runsource(source) self.indent = '' if self.more: self.prompt = sys.ps2 self.indent = line[0:len(line) - len(line.lstrip())] if line.rstrip(): if line.rstrip()[-1] == ':': self.indent += ' ' else: self.prompt = sys.ps1 self.lines = [] self.setCommandText(self.indent) self.ui.l_prompt.setText(self.prompt) def write(self, text, mode=0, prefix=None): # modes # 0 = output # 1 = input # 2 = error ## hack = self.ui.tb_view.toPlainText() ## hack.append(text+'\n') ## self.ui.tb_view.setText(hack) ## print len(text),len(text.rstrip()) self.writecount += 1 ## if text.rstrip() or 1: self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0) if mode == 2: # Error txt = '<font style="color:rgb(255,112,99);">' + str( QtCore.QString(text).toUtf8()).decode('utf-8').replace( '<', '<').replace('>', '>').replace( ' ', ' ').replace('\n', '<br>') + "</font>" txt = re_file.sub( r"<a style=" "color:rgb(121,213,255);" " href='\g<2>'>\g<2></a>", txt) self.ui.tb_view.insertHtml(txt) elif mode == 1: # Input txt = '<div style="color:rgb(89,197,254);">' if prefix: txt += '<span style="color:rgb(38,90,150);">' + prefix.replace( '>', '>') + '</span>' txt += str(QtCore.QString(text).toUtf8()).decode('utf-8').replace( '<', '<').replace('>', '>').replace( ' ', ' ').replace('\n', '<br>') + "</div>" self.ui.tb_view.insertHtml(txt) else: # Write txt = '<div style="color:rgb(255,255,255);">' + str( QtCore.QString(text).toUtf8()).decode('utf-8').replace( '<', '<').replace('>', '>').replace( ' ', ' ').replace('\n', '<br>') + "</div>" self.ui.tb_view.insertHtml(txt) self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0) def cmdKeyPress(self, e): key = e.key() handled = 0 if key == Qt.Key_Up: # Up if len(self.history): if self.pointer > 0: self.pointer -= 1 self.setCommandText(self.history[self.pointer]) handled = 1 elif key == Qt.Key_Down: # Down if len(self.history) and self.pointer < len(self.history): if self.pointer == len(self.history) - 1: self.setCommandText('') self.pointer += 1 handled = 1 else: self.pointer += 1 self.setCommandText(self.history[self.pointer]) handled = 1 elif key == Qt.Key_Enter or key == Qt.Key_Return: # Enter if self.reading: self.reading = 0 else: self.enter() handled = 1 elif key == Qt.Key_Tab: self.ui.le_cmd.insert(' ') handled = 1 # Ctrl if e.modifiers() & QtCore.Qt.ControlModifier: if key == QtCore.Qt.Key_V: # paste # V ## txt = QtGui.QApplication.clipboard().text('plain').split(QtCore.QRegExp("[\r\n]"),QtCore.QString.SkipEmptyParts) txt = str(QtGui.QApplication.clipboard().text( 'plain').toUtf8()).decode('utf-8').splitlines() if len(txt) > 0: self.ui.le_cmd.insert(txt[0]) if len(txt) > 1: self.enter() for t in txt[1:-1]: self.setCommandText(t) self.enter() self.setCommandText(txt[-1]) handled = 1 elif key == QtCore.Qt.Key_L: # launch # L from subprocess import Popen try: if os.name == 'nt': Popen(["pythonw", os.path.abspath(__file__)]) else: Popen(["python", os.path.abspath(__file__)]) except: QtGui.QMessageBox.warning( self, 'Error', 'The Python Shell could not open with your default Python install. Please make sure you have Python 2.7 (or 2.6) installed and the Python executable is in your system path' ) if not handled: ## QtGui.QLineEdit.keyPressEvent(self.ui.le_cmd,e) self.ui.le_cmd.widgetObject.keyPressEvent(self.ui.le_cmd, e) def setCommandText(self, text): self.ui.le_cmd.setText(text) if self.ui.le_cmd.type == 'qscintilla': self.ui.le_cmd.setCursorPosition(0, len(text)) def readline(self): """ Simulate stdin, stdout, and stderr. """ self.reading = 1 self.ui.le_cmd.setText('') self.ui.l_prompt.setText('?') ## self.moveCursor(QtGui.QTextCursor.End, 0) while self.reading: QtGui.QApplication.processEvents() line = self.ui.le_cmd.text() if len(line) == 0: return_line = '\n' else: return_line = str(line) self.write('\n') return return_line def writelines(self, text): """ Simulate stdin, stdout, and stderr. """ map(self.write, text) def flush(self): """ Simulate stdin, stdout, and stderr. """ pass def isatty(self): """ Simulate stdin, stdout, and stderr. """ return 1 #---Output Overrides def tb_out_keypress(self, e): key = e.key() handled = 0 # Copy ahead of disable if e.modifiers() & QtCore.Qt.ControlModifier: # Copy if key == Qt.Key_C: txt = str(self.ui.tb_view.textCursor().selectedText().toUtf8() ).replace('\xc2\xa0', ' ').decode('utf-8') ## QtGui.QApplication.clipboard().clear() ntxt = [] for ln in txt.splitlines(): t = ln if ln.startswith('>>> ') or ln.startswith('... '): t = ln[4:] ntxt.append(t) txt = '\n'.join(ntxt) QtGui.QApplication.clipboard().setText(txt) handled = 1 if not handled: QtGui.QTextEdit.keyPressEvent(self.ui.tb_view, e)
class ToolbarBehaviour_MDL(StateMachine): # Constants for this model StateNum=3 EventNames=["(create)*", "<Any-ButtonRelease-1>", "[Done]" ] StateNames=["Default", "Do Layout*", "Idle" ] ParentTable=[-1, # Default -- parent (None) -1, # Do Layout* -- parent (None) -1 # Idle -- parent (None) ] HistoryStateTable=[0, 0, 0 ] LeafStateTable=["Default", "Do Layout*", "Idle" ] OrthogonalInBetween=[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0] ] OrthogonalTable=[[0, 0, 0], [0, 0, 0], [0, 0, 0] ] IntervalTable=[None, None, None ] RescheduleTable=[-1, -1, -1 ] Hierarchy=[[0, 0, 0], # substates of state Default [0, 0, 0], # substates of state Do Layout* [0, 0, 0] # substates of state Idle ] CommonStateTable=[[-1, -1, -1], [-1, -1, -1], [-1, -1, -1] ] Description=None ##Lock=thread.allocate_lock() CurrentModel=None def __init__(self, Interpreter=None, Parent=None, OldInstance=None): # Variables self.Parent=Parent self.HistoryCount=0 self.state=None self.BackState=None if OldInstance!=None: self.Submodels=OldInstance.Submodels else: self.Submodels=[] for i in range(ToolbarBehaviour_MDL.StateNum): self.Submodels.append(None) self.history=[] for i in range(ToolbarBehaviour_MDL.StateNum): self.history.append(None) # Constructor for i in range(ToolbarBehaviour_MDL.StateNum): self.history[i]=History() self.history[i].States=[] self.history[i].Times=[] for j in range(ToolbarBehaviour_MDL.StateNum): self.history[i].States.append(-1) self.history[i].Times.append(-1) self.TimedTransitions=[] # used only when --ext is set for i in range(ToolbarBehaviour_MDL.StateNum): self.TimedTransitions.append(None) self.clearEnteredStates() self.HasInteractor=0 # Interpreter of action code if self.Parent==None: # Top-level model if Interpreter: self.DefaultInterpreter=Interpreter else: self.DefaultInterpreter=InteractiveInterpreter() self.setupInterpreter() ##self.EventsCond=threading.Condition() ##self.SchedulerCond=threading.Condition() self.Schedules=[] self.PendingEvents=None self.PendingEventsTail=None else: self.DefaultInterpreter=Interpreter self.Started=0 self.Stopped=0 self.description=ToolbarBehaviour_MDL.Description # Methods def isParent(self, sp, sc): return sc>=0 and (sp<0 or ToolbarBehaviour_MDL.Hierarchy[sp][sc]) def isInState(self, s, check_substate=1, use_backup=1): if isinstance(s, int): if use_backup: st=self.BackState else: st=self.state while st!=None: if st.StateID==s or (check_substate and self.isParent(s, st.StateID)): return 1 else: st=st.Next return 0 elif isinstance(s, str): i=0 while i<ToolbarBehaviour_MDL.StateNum: if s==ToolbarBehaviour_MDL.StateNames[i]: return self.isInState(i, check_substate, use_backup) i=i+1 i=0 while i<ToolbarBehaviour_MDL.StateNum: stname=ToolbarBehaviour_MDL.StateNames[i] if self.Submodels[i]!=None and startsWith(s, stname+"."): pos=len(stname)+1 SubmodelState=s[pos:] return self.isInState(i, 0, use_backup) and self.Submodels[i].isInState(SubmodelState, check_substate, use_backup); i=i+1 return 0 else: return 0 class main_callable: def __call__(self, argv): model=ToolbarBehaviour_MDL() cmd="" model.initModel() if model.HasInteractor: model.runInteractor() else: ##cond=thread.allocate_lock() while cmd!="exit": sys.__stdout__.write(model.getCurrentState()+" > ") cmd=string.strip(sys.__stdin__.readline()) if cmd=="exit": break if not model.Stopped: ##cond.acquire() ##model.event(cmd, [], cond) model.event(cmd, []) ##cond.acquire() ##cond.release() model.runFinalizer() main=main_callable() def initModel(self, run_initializer=1, run_enter_actions=1, TkInstance = None ): self.clearEnteredStates() if self.Parent==None and ToolbarBehaviour_MDL.Description!=None: sys.__stdout__.write(ToolbarBehaviour_MDL.Description+"\n") self.addInState(0) # init state "Default" self.recordEnteredState(0) if run_initializer: self.runInitializer() if not self.HasInteractor: self.start(None, run_enter_actions, TkInstance ) def applyMask(self, mask, dest): i=0 while i<ToolbarBehaviour_MDL.StateNum: dest[i]=dest[i] and mask[i] i=i+1 def handleEvent(self, se, params=[], cond=None, scheduler=None): if not self.Started: if cond: cond.release() return 0 self.params=params handled=0 table=[] i=0 while i<ToolbarBehaviour_MDL.StateNum: table.append(1) i=i+1 if self.state: self.BackState=self.state.copy() else: self.BackState=None e=self.eventStr2Int(se) if e==0: # event "(create)*" if table[0] and self.isInState(0) and self.testCondition(0): if (scheduler==self or scheduler==None) and table[0]: self.runActionCode(2) # output action(s) self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(0, 2) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[0], table) handled=1 elif e==1: # event "<Any-ButtonRelease-1>" if table[2] and self.isInState(2) and self.testCondition(1): if (scheduler==self or scheduler==None) and table[2]: self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(2, 1) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[2], table) handled=1 elif e==2: # event "[Done]" if table[1] and self.isInState(1) and self.testCondition(2): if (scheduler==self or scheduler==None) and table[1]: self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(1, 2) self.runEnterActionsForStates(self.StatesEntered, 1) self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[1], table) handled=1 if cond and self.Parent==None: # Top-level model cond.release() if not handled and e>=0 and (scheduler==self or scheduler==None) and ToolbarBehaviour_MDL.RescheduleTable[e]>=0: self.addSchedule(ToolbarBehaviour_MDL.RescheduleTable[e], ToolbarBehaviour_MDL.IntervalTable[e], ToolbarBehaviour_MDL.EventNames[e], scheduler) return handled def forceIntoState(self, s): changed=0 s2=self.state while s2!=None: HasCommonParent=0 for i in range(ToolbarBehaviour_MDL.StateNum): if self.isParent(i, s2.StateID) and self.isParent(i, s): HasCommonParent=1 if not self.hasOrthogonalStateInBetween(i, s2.StateID): self.changeState(s2.StateID, s) changed=1 if not HasCommonParent: self.changeState(s2.StateID, s) changed=1 s2=s2.Next if not changed: self.addInState(s) def changeState(self, s1, s2, check_history=0, top_level=0): # t1=common(s1, s2) t1=ToolbarBehaviour_MDL.CommonStateTable[s1][s2] self.recordHistory(t1) if t1>=0: self.removeOutStates(t1) else: self.state=None # t2=history(s2) t2=ToolbarBehaviour_MDL.HistoryStateTable[s2] if t2==0: # no history self.generateStates(t1, s2) elif t2==1: # normal history if not check_history: self.generateStates(t1, s2) elif self.hasHistoryRecorded(s2) and self.Submodels[s2]==None: self.generateStates(t1, self.history[s2].States[s2]) else: self.generateStates(t1, s2, 1) elif t2==2: # deep history if check_history and self.hasHistoryRecorded(s2): if self.Submodels[s2]: self.recordEnteredState(s2, 1, 1, t1) self.addInState(s2) else: for i in range(ToolbarBehaviour_MDL.StateNum): hs=self.history[s2].States[i] if hs>=0 and self.isLeafState(hs): self.recordEnteredState(hs, 1, 1, t1) self.addInState(hs) else: self.generateStates(t1, s2) def addInState(self, s): if not self.isInState(s, 1, 0): st=State() st.StateID=s st.Next=self.state self.state=st return 1 else: return 0 def generateStates(self, common, dest, history_type=0): if common==-1: if dest==0: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(0): self.recordEnteredState(0) self.addInState(0) # move into leaf state "Default" elif dest==1: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(1): self.recordEnteredState(1) self.addInState(1) # move into leaf state "Do Layout*" elif dest==2: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(2): self.recordEnteredState(2) self.addInState(2) # move into leaf state "Idle" elif common==0: if dest==0: if history_type!=2 or self.check_history(0): self.addInState(0) # move into leaf state "Default" elif common==1: if dest==1: if history_type!=2 or self.check_history(1): self.addInState(1) # move into leaf state "Do Layout*" elif common==2: if dest==2: if history_type!=2 or self.check_history(2): self.addInState(2) # move into leaf state "Idle" def removeOutStates(self, common_state): s=self.state prev=None while s!=None: if self.isParent(common_state, s.StateID): if prev==None: self.state=self.state.Next else: prev.Next=s.Next else: prev=s s=s.Next def eventStr2Int(self, event): for i in range(3): if event==ToolbarBehaviour_MDL.EventNames[i]: return i return -1 def stateInt2Str(self, state): if state==-1: return "" else: return ToolbarBehaviour_MDL.StateNames[state] def getCurrentStateList(self): sl=StringList() slend=sl s=self.state while s!=None: sm=self.Submodels[s.StateID] curstate=self.stateInt2Str(s.StateID) if sm!=None: slend.Next=sm.getCurrentStateList() while slend.Next!=None: slend.Next.str=curstate+"."+slend.Next.str slend=slend.Next else: slend.Next=StringList(curstate) slend=slend.Next s=s.Next return sl.Next def getCurrentState(self, states=None): if states==None: states=self.getCurrentStateList() if states!=None: states=states.sort() strst="['%s'%s]" % (states.str, self.getCurrentState(states)) else: strst="[]" else: if states.Next: strst=", '%s'%s" % (states.Next.str, self.getCurrentState(states.Next)) else: strst="" return strst def getParentState(self, state): return ToolbarBehaviour_MDL.ParentTable[state] def getSubstates(self, state): substates=None if state==-1: # substates of "" # add substate "Default" st=IntList() st.int=0 st.Next=substates substates=st # add substate "Do Layout*" st=IntList() st.int=1 st.Next=substates substates=st # add substate "Idle" st=IntList() st.int=2 st.Next=substates substates=st elif state==0: # substates of "Default" pass elif state==1: # substates of "Do Layout*" pass elif state==2: # substates of "Idle" pass return substates def isHistoryState(self, state): return ToolbarBehaviour_MDL.HistoryStateTable[state]>0 def isLeafState(self, state): if isinstance(state, int): return ToolbarBehaviour_MDL.LeafStateTable[state]!=None elif isinstance(state, str): for i in range(ToolbarBehaviour_MDL.StateNum): if ToolbarBehaviour_MDL.LeafStateTable[i]==None: continue if state==ToolbarBehaviour_MDL.LeafStateTable[i] and self.Submodels[i]==None: return 1 elif startsWith(state, ToolbarBehaviour_MDL.LeafStateTable[i]+".") and self.Submodels[i]!=None: SubmodelState=state[ToolbarBehaviour_MDL.LeafStateTable[i].length()+1:] return self.Submodels[i].isLeafState(SubmodelState) return 0 def isHistoryUp2Date(self, state, time): for i in range(ToolbarBehaviour_MDL.StateNum): if self.history[state].Times[i]>=time: return 1 return 0 def mergeHistory(self, state, states, times): max=-1 for i in range(ToolbarBehaviour_MDL.StateNum): if times[i]>max: max=times[i] if self.isHistoryUp2Date(state, max): for i in range(ToolbarBehaviour_MDL.StateNum): if times[i]>self.history[state].Times[i]: self.history[state].States[i]=states[i] self.history[state].Times[i]=times[i] else: self.history[state].States=copy.copy(states) self.history[state].Times=copy.copy(times) def recordHistory(self, top_state): curtime=self.HistoryCount self.HistoryCount=self.HistoryCount+1 s=self.state while s!=None: child=s.StateID states=[] times=[] for i in range(ToolbarBehaviour_MDL.StateNum): states.append(-1) times.append(-1) states[child]=child times[child]=curtime if top_state<0 or self.isParent(top_state, child): parent=self.getParentState(child) if self.isHistoryState(child): self.history[child].Submodel=self.Submodels[child] while parent>=0 and times[parent]!=curtime: states[parent]=child times[parent]=curtime if self.isHistoryState(parent): self.mergeHistory(parent, states, times) if parent==top_state: break child=parent parent=self.getParentState(child) s=s.Next def hasHistoryRecorded(self, state): for i in range(ToolbarBehaviour_MDL.StateNum): if self.history[state].States[i]!=-1: return 1 if self.Submodels[state]!=None: return 1 return 0 def hasOrthogonalStateInBetween(self, parent, leaf): return ToolbarBehaviour_MDL.OrthogonalInBetween[parent+1][leaf] def check_history(self, dest): s=self.state while s!=None: if self.isParent(dest, s.StateID) and not self.hasOrthogonalStateInBetween(dest, s.StateID): return 0 s=s.Next return 1 def getEnabledEvents(self): events=EventList() if self.isInState(0): events.Append("(create)*") if self.isInState(2): events.Append("<Any-ButtonRelease-1>") if self.isInState(1): events.Append("[Done]") return events.Next def getHierarchy(self, start_level, state_prefix): h=Hierarchy() lasth=h # Generate state "Default" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Default" if state_prefix==None: lasth.Next.PathName="Default" else: lasth.Next.PathName=state_prefix+".Default" lasth.Next.StateNum=0 lasth.Next.Level=start_level+0 lasth=lasth.Next # Generate state "Do Layout*" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Do Layout*" if state_prefix==None: lasth.Next.PathName="Do Layout*" else: lasth.Next.PathName=state_prefix+".Do Layout*" lasth.Next.StateNum=1 lasth.Next.Level=start_level+0 lasth=lasth.Next # Generate state "Idle" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Idle" if state_prefix==None: lasth.Next.PathName="Idle" else: lasth.Next.PathName=state_prefix+".Idle" lasth.Next.StateNum=2 lasth.Next.Level=start_level+0 lasth=lasth.Next return h.Next def topLevelHistory(self): s=self.state.StateID t=self.getParentState(s) while t!=-1: s=t t=self.getParentState(s) self.changeState(s, s) def runActionCode(self, code_num): if code_num==0: # model finalizer pass elif code_num==1: # model initializer pass elif code_num==2: # output action(s) of a transition self.runCode("self = eventhandler.get_event_params()") self.runCode("atom3i = self.parent") self.runCode("cb = atom3i.cb") elif code_num==3: # enter actions for state "Do Layout*" self.runCode("from FSB_Code.Layout import toolbarLayout") self.runCode("toolbarLayout(self)") self.runCode("eventhandler.event(\'[Done]\')") def testCondition(self, cond_num): if cond_num==0 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==1 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 elif cond_num==2 and \ eval("(1)", self.DefaultInterpreter.locals): return 1 return 0 def runEnterActions(self, state): if state==1: # enter action(s) for state "Do Layout*" self.runActionCode(3) def runExitActions(self, state): pass def compareSchedule(self, sched_a, sched_b): return cmp(sched_a[1], sched_b[1]) def addSchedule(self, id, interval, event, scheduler): if self.Parent!=None: # Non-top-level model self.Parent.addSchedule(id, interval, event, scheduler) return f=eval(interval, self.DefaultInterpreter.locals) ##self.SchedulerCond.acquire() t=time.time()+f s=[id, t, interval, event, scheduler] self.Schedules.append(s) self.Schedules.sort(self.compareSchedule) ##self.SchedulerCond.notify() ##self.SchedulerCond.release() def removeSchedule(self, id, scheduler): if self.Parent!=None: # Non-top-level model self.Parent.removeSchedule(id, scheduler) return ##self.SchedulerCond.acquire() i=0 while i<len(self.Schedules): if self.Schedules[i][0]==id and self.Schedules[i][4]==scheduler: del self.Schedules[i] else: i=i+1 ##self.SchedulerCond.release() def scheduler(self): if( not self.Schedules): return while( self.Schedules and self.Schedules[0][1]<=time.time()): this_sched=self.Schedules[0] del self.Schedules[0] self.event(this_sched[3], [], None, this_sched[4]) if self.Schedules: t=self.Schedules[0][1]-time.time() def recordAllEnteredStates(self): st=self.state while st!=None: self.recordEnteredState(st.StateID, 1, 1) st=st.Next def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1): # test if s is already recorded se=self.StatesEntered found=0 while se!=None: if se.int==s: found=1 break se=se.Next if not found: if superstates: parent=self.getParentState(s) if parent>=0 and parent!=commonstate: self.recordEnteredState(parent, 1, 0, commonstate) st=IntList() st.Next=self.StatesEntered st.int=s self.StatesEntered=st if submodel and self.Submodels[s]: self.Submodels[s].recordAllEnteredStates() def runAllEnterActions(self): self.runEnterActionsForStates(self.StatesEntered, 1) def runEnterActionsForStates(self, states, recursive=0): if states: self.runEnterActionsForStates(states.Next, 0) self.runEnterActions(states.int) if recursive: for s in self.Submodels: if s: s.runAllEnterActions() def runExitActionsForStates(self, common_state): substates=self.getSubstates(common_state) if substates==None: s=self.state while s!=None and s.StateID!=common_state: s=s.Next if s!=None and self.Submodels[s.StateID]: self.Submodels[s.StateID].runExitActionsForStates(-1) return s!=None else: has_current_substate=0 while substates!=None: res=self.runExitActionsForStates(substates.int) has_current_substate=has_current_substate or res if res: self.runExitActions(substates.int) substates=substates.Next return has_current_substate def runInitializer(self): self.runActionCode(1) for s in self.Submodels: if s: s.runInitializer() def runFinalizer(self): if self.Started: self.Started=0 for s in self.Submodels: if s: s.runFinalizer() self.runActionCode(0) if self.Parent==None: # Top-level model ##self.EventsCond.acquire() ##self.SchedulerCond.acquire() self.Stopped=1 ##self.EventsCond.notify() ##self.SchedulerCond.notify() ##self.SchedulerCond.release() ##self.EventsCond.release() else: self.Stopped=1 def clearEnteredStates(self): self.StatesEntered=None for s in self.Submodels: if s: s.clearEnteredStates() def get_current_state(self): return self.getCurrentState() def runCode(self, c): self.DefaultInterpreter.runsource(c+"\n", "<input>", "exec") def setupInterpreter(self): self.DefaultInterpreter.locals["eventhandler"]=self self.DefaultInterpreter.locals["dump_message"]=self.dump_message def get_event_params(self): return self.params def dump_message(self, msg): print msg def is_in_state(self, s, check_substate=1): return self.isInState(s, check_substate) def start(self, lock=None, run_enter_actions=1, TkInstance = None): if self.Parent==None: # Top-level model if run_enter_actions: self.runEnterActionsForStates(self.StatesEntered, 1) self.Started=1 if( TkInstance ): self.sleepMethod = TkInstance.after startTkMainloop = False else: import Tkinter TkInstance = Tkinter.Tk() self.sleepMethod = TkInstance.after startTkMainloop = True self.pollingStation() ##thread.start_new_thread(self.handleEvent_wrapper, ()) ##thread.start_new_thread(self.scheduler, ()) ## if lock: ## lock.release() else: self.Started=1 for submodel in self.Submodels: if submodel!=None: submodel.start() if( self.Parent==None and startTkMainloop == None ): TkInstance.mainloop() def pollingStation(self): self.sleepMethod( 100, self.pollingStation ) if self.Stopped: return #self.handleEvent_wrapper() self.scheduler() #todo: pollingStation\, def shutdown(self): pass def handleEvent_wrapper(self): if( self.PendingEvents==None ): return event=self.PendingEvents self.PendingEvents=self.PendingEvents.Next if self.PendingEvents==None: self.PendingEventsTail=None event.next=None self.handleEvent(event.Event[0], event.Event[1], event.Event[2], event.Event[3]) self.handleEvent_wrapper() def event(self, e, params=[], cond=None, scheduler=None): ev=EventList() ev.Event=[e, params, cond, scheduler] if self.PendingEventsTail!=None: self.PendingEventsTail.Next=ev else: self.PendingEvents=ev self.PendingEventsTail=ev self.handleEvent_wrapper()
def runsource(self, source): # Extend base class to stuff the source in the line cache first filename = self.stuffsource(source) self.more = 0 return InteractiveInterpreter.runsource(self, source, filename)
class behaviour_generated_no_link_with_gui(StateMachine): # Constants for this model StateNum=4 EventNames=["__INTERNAL_0_TIME_0", "press" ] StateNames=["Disabled", "Enabled", "Enabled.Green", "Enabled.Red" ] ParentTable=[-1, # Disabled -- parent (None) -1, # Enabled -- parent (None) 1, # Enabled.Green -- parent Enabled 1 # Enabled.Red -- parent Enabled ] HistoryStateTable=[0, 0, 0, 0 ] LeafStateTable=["Disabled", None, "Enabled.Green", "Enabled.Red" ] OrthogonalInBetween=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] Hierarchy=[[0, 0, 0, 0], # substates of state Disabled [0, 0, 1, 1], # substates of state Enabled [0, 0, 0, 0], # substates of state Enabled.Green [0, 0, 0, 0] # substates of state Enabled.Red ] CommonStateTable=[[0, -1, -1, -1], [-1, 1, 1, 1], [-1, 1, 2, 1], [-1, 1, 1, 3] ] Description=None # used only when --pyext is set Lock=thread.allocate_lock() CurrentModel=None def __init__(self, Interpreter=None): # Variables self.state=None self.Submodels=[] for i in range(behaviour_generated_no_link_with_gui.StateNum): self.Submodels.append(None) self.history=[] for i in range(behaviour_generated_no_link_with_gui.StateNum): self.history.append(None) self.TimedTransitions=[] # used only when --pyext is set for i in range(behaviour_generated_no_link_with_gui.StateNum): self.TimedTransitions.append(None) self.clearEnteredStates() # Constructor for i in range(behaviour_generated_no_link_with_gui.StateNum): self.history[i]=History() self.history[i].States=[] self.history[i].Times=[] for j in range(behaviour_generated_no_link_with_gui.StateNum): self.history[i].States.append(-1) self.history[i].Times.append(-1) # Interpreter of action code if Interpreter: self.DefaultInterpreter=Interpreter else: self.DefaultInterpreter=InteractiveInterpreter() self.HasInteractor=0 self.setupInterpreter() self.Started=0 self.EventsLock=thread.allocate_lock() self.PendingEvents=None self.PendingEventsTail=None self.HandleEventRunning=0 self.description=behaviour_generated_no_link_with_gui.Description # Methods def isParent(self, sp, sc): return sc>=0 and (sp<0 or behaviour_generated_no_link_with_gui.Hierarchy[sp][sc]) def isInState(self, s): if isinstance(s, int): st=self.state while st!=None: if st.StateID==s or self.isParent(s, st.StateID): return 1 else: st=st.Next return 0 elif isinstance(s, str): for i in range(behaviour_generated_no_link_with_gui.StateNum): if s==behaviour_generated_no_link_with_gui.StateNames[i]: return self.isInState(i) for i in range(behaviour_generated_no_link_with_gui.StateNum): if self.Submodels[i]!=None and startsWith(s, behaviour_generated_no_link_with_gui.StateNames[i]+"."): SubmodelState=s[len(behaviour_generated_no_link_with_gui.StateNames[i])+1:] return self.isInState(i) and self.Submodels[i].isInState(SubmodelState) return 0 def main(self, argv): model=behaviour_generated_no_link_with_gui() cmd="" model.initModel() if model.HasInteractor: model.runInteractor() else: if behaviour_generated_no_link_with_gui.Description: sys.__stdout__.write(behaviour_generated_no_link_with_gui.Description+"\n") lock=thread.allocate_lock() while cmd!="exit": sys.__stdout__.write(model.getCurrentState()+" > ") cmd=string.strip(sys.__stdin__.readline()) if cmd=="exit": break lock.acquire() model.event(cmd, [], lock) lock.acquire() lock.release() model.runFinalizer() def initModel(self, run_initializer=1, run_enter_actions=1): self.clearEnteredStates() self.Started=1 self.addInState(3) # init state "Enabled.Red" self.recordEnteredState(1) self.recordEnteredState(3) self.Started=1 if run_initializer: self.runInitializer() if not self.HasInteractor: self.start(run_enter_actions) def handleEvent(self, se, params=[], lock=None, call_submodels=1): if not self.Started: if lock: lock.release() return 0 e=self.eventStr2Int(se) self.EventsLock.acquire() self.HandleEventRunning=1 self.EventsLock.release() self.params=params if e==0: # event "__INTERNAL_0_TIME_0" if self.isInState(1) and self.testCondition(0): self.runExitActionsForStates(-1) self.clearEnteredStates() self.changeState(1, 0) self.runEnterActionsForStates(self.StatesEntered, 1) if lock: lock.release() self.checkPendingEvents() return 1 elif e==1: # event "press" if self.isInState(3) and self.testCondition(1): self.runExitActionsForStates(1) self.clearEnteredStates() self.changeState(3, 2) self.runEnterActionsForStates(self.StatesEntered, 1) if lock: lock.release() self.checkPendingEvents() return 1 if self.isInState(2) and self.testCondition(2): self.runExitActionsForStates(1) self.clearEnteredStates() self.changeState(2, 3) self.runEnterActionsForStates(self.StatesEntered, 1) if lock: lock.release() self.checkPendingEvents() return 1 if lock: lock.release() self.checkPendingEvents() return 0 def forceIntoState(self, s): changed=0 s2=self.state while s2!=None: HasCommonParent=0 for i in range(behaviour_generated_no_link_with_gui.StateNum): if self.isParent(i, s2.StateID) and self.isParent(i, s): HasCommonParent=1 if not self.hasOrthogonalStateInBetween(i, s2.StateID): self.changeState(s2.StateID, s) changed=1 if not HasCommonParent: self.changeState(s2.StateID, s) changed=1 s2=s2.Next if not changed: self.addInState(s) def changeState(self, s1, s2, check_history=0, top_level=0): # t1=common(s1, s2) t1=behaviour_generated_no_link_with_gui.CommonStateTable[s1][s2] self.recordHistory(t1) if t1>=0: self.removeOutStates(t1) else: self.state=None # t2=history(s2) t2=behaviour_generated_no_link_with_gui.HistoryStateTable[s2] if t2==0: # no history self.generateStates(t1, s2) elif t2==1: # normal history if not check_history: self.generateStates(t1, s2) elif self.hasHistoryRecorded(s2): self.generateStates(t1, self.history[s2].States[s2]) else: self.generateStates(t1, s2, 1) elif t2==2: # deep history if check_history and self.hasHistoryRecorded(s2): for i in range(behaviour_generated_no_link_with_gui.StateNum): hs=self.history[s2].States[i] if hs>=0 and self.isLeafState(hs): # used only when --pyext is set self.recordEnteredState(hs, 1, 1, t1) self.addInState(hs) else: self.generateStates(t1, s2) def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1): # test is s is already recorded se=self.StatesEntered found=0 while se!=None: if se.int==s: found=1 break se=se.Next if not found: if superstates: parent=self.getParentState(s) if parent>=0 and parent!=commonstate: self.recordEnteredState(parent, 1) st=IntList() st.Next=self.StatesEntered st.int=s self.StatesEntered=st if submodel and self.Submodels[s]: mdl=self.Submodels[s] st=mdl.state while st!=None: mdl.recordEnteredState(st.StateID, 1, 1) st=st.Next def addInState(self, s): if not self.isInState(s): st=State() st.StateID=s st.Next=self.state self.state=st return 1 else: return 0 def generateStates(self, common, dest, history_type=0): if common==-1: if dest==0: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(0): self.recordEnteredState(0) self.addInState(0) # move into leaf state "Disabled" elif dest==1: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(1): self.recordEnteredState(1) if history_type!=2 or self.check_history(3): self.recordEnteredState(3) self.addInState(3) # move into leaf state "Enabled.Red" elif dest==2: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(1): self.recordEnteredState(1) if history_type!=2 or self.check_history(2): self.recordEnteredState(2) self.addInState(2) # move into leaf state "Enabled.Green" elif dest==3: if history_type!=2 or self.check_history(-1): if history_type!=2 or self.check_history(1): self.recordEnteredState(1) if history_type!=2 or self.check_history(3): self.recordEnteredState(3) self.addInState(3) # move into leaf state "Enabled.Red" elif common==0: if dest==0: if history_type!=2 or self.check_history(0): self.addInState(0) # move into leaf state "Disabled" elif common==1: if dest==1: if history_type!=2 or self.check_history(1): if history_type!=2 or self.check_history(3): self.recordEnteredState(3) self.addInState(3) # move into leaf state "Enabled.Red" elif dest==2: if history_type!=2 or self.check_history(1): if history_type!=2 or self.check_history(2): self.recordEnteredState(2) self.addInState(2) # move into leaf state "Enabled.Green" elif dest==3: if history_type!=2 or self.check_history(1): if history_type!=2 or self.check_history(3): self.recordEnteredState(3) self.addInState(3) # move into leaf state "Enabled.Red" elif common==2: if dest==2: if history_type!=2 or self.check_history(2): self.addInState(2) # move into leaf state "Enabled.Green" elif common==3: if dest==3: if history_type!=2 or self.check_history(3): self.addInState(3) # move into leaf state "Enabled.Red" def removeOutStates(self, common_state): s=self.state prev=None while s!=None: if self.isParent(common_state, s.StateID): if prev==None: self.state=self.state.Next else: prev.Next=s.Next else: prev=s s=s.Next def eventStr2Int(self, event): for i in range(2): if event==behaviour_generated_no_link_with_gui.EventNames[i]: return i return -1 def stateInt2Str(self, state): if state==-1: return "" else: return behaviour_generated_no_link_with_gui.StateNames[state] def getCurrentStateList(self): sl=StringList() slend=sl s=self.state while s!=None: sm=self.Submodels[s.StateID] curstate=self.stateInt2Str(s.StateID) if sm!=None: slend.Next=sm.getCurrentStateList() while slend.Next!=None: slend.Next.str=curstate+"."+slend.Next.str slend=slend.Next else: slend.Next=StringList(curstate) slend=slend.Next s=s.Next return sl.Next def getCurrentState(self, states=None): if states==None: states=self.getCurrentStateList() if states!=None: strst="[%s'%s']" % (self.getCurrentState(states), states.str) else: strst="[]" else: if states.Next: strst="%s'%s', " % (self.getCurrentState(states.Next), states.Next.str) else: strst="" return strst def getParentState(self, state): return behaviour_generated_no_link_with_gui.ParentTable[state] def getSubstates(self, state): substates=None if state==-1: # substates of "" # add substate "Disabled" st=IntList() st.int=0 st.Next=substates substates=st # add substate "Enabled" st=IntList() st.int=1 st.Next=substates substates=st elif state==0: # substates of "Disabled" pass elif state==1: # substates of "Enabled" # add substate "Enabled.Green" st=IntList() st.int=2 st.Next=substates substates=st # add substate "Enabled.Red" st=IntList() st.int=3 st.Next=substates substates=st elif state==2: # substates of "Enabled.Green" pass elif state==3: # substates of "Enabled.Red" pass return substates def isHistoryState(self, state): return behaviour_generated_no_link_with_gui.HistoryStateTable[state]>0 def isLeafState(self, state): if isinstance(state, int): return behaviour_generated_no_link_with_gui.LeafStateTable[state]!=None elif isinstance(state, str): for i in range(behaviour_generated_no_link_with_gui.StateNum): if behaviour_generated_no_link_with_gui.LeafStateTable[i]==None: continue if state==behaviour_generated_no_link_with_gui.LeafStateTable[i] and self.Submodels[i]==None: return 1 elif startswith(state, behaviour_generated_no_link_with_gui.LeafStateTable[i]+".") and self.Submodels[i]!=None: SubmodelState=state[behaviour_generated_no_link_with_gui.LeafStateTable[i].length()+1:] return self.Submodels[i].isLeafState(SubmodelState) return 0 def isHistoryUp2Date(self, state, time): for i in range(behaviour_generated_no_link_with_gui.StateNum): if self.history[state].Times[i]>=time: return 1 return 0 def mergeHistory(self, state, states, times): max=-1 for i in range(behaviour_generated_no_link_with_gui.StateNum): if times[i]>max: max=times[i] if self.isHistoryUp2Date(state, max): for i in range(behaviour_generated_no_link_with_gui.StateNum): if times[i]>self.history[state].Times[i]: self.history[state].States[i]=states[i] self.history[state].Times[i]=times[i] else: self.history[state].States=copy.copy(states) self.history[state].Times=copy.copy(times) def recordHistory(self, top_state): curtime=time.time(); s=self.state; while s!=None: child=s.StateID states=[] times=[] for i in range(behaviour_generated_no_link_with_gui.StateNum): states.append(-1) times.append(-1) states[child]=child times[child]=curtime if top_state<0 or self.isParent(top_state, child): parent=self.getParentState(child) if self.isHistoryState(child): self.history[child].Submodel=self.Submodels[child] while parent!=top_state and times[parent]!=curtime: states[parent]=child times[parent]=curtime if self.isHistoryState(parent): self.mergeHistory(parent, states, times) child=parent parent=self.getParentState(child) s=s.Next def hasHistoryRecorded(self, state): for i in range(behaviour_generated_no_link_with_gui.StateNum): if self.history[state].States[i]!=-1: return 1 if self.Submodels[state]!=None: return 1 return 0 def hasOrthogonalStateInBetween(self, parent, leaf): return behaviour_generated_no_link_with_gui.OrthogonalInBetween[parent+1][leaf] def check_history(self, dest): s=self.state while s!=None: if self.isParent(dest, s.StateID) and not self.hasOrthogonalStateInBetween(dest, s.StateID): return 0 s=s.Next return 1 def getEnabledEvents(self): events=EventList() if self.isInState(1): events.Append("__INTERNAL_0_TIME_0") if self.isInState(3): events.Append("press") if self.isInState(2): events.Append("press") return events.Next def getHierarchy(self, start_level, state_prefix): h=Hierarchy() lasth=h # Generate state "Disabled" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Disabled" if state_prefix==None: lasth.Next.PathName="Disabled" else: lasth.Next.PathName=state_prefix+".Disabled" lasth.Next.StateNum=0 lasth.Next.Level=start_level+0 lasth=lasth.Next # Generate state "Enabled" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Enabled" if state_prefix==None: lasth.Next.PathName="Enabled" else: lasth.Next.PathName=state_prefix+".Enabled" lasth.Next.StateNum=1 lasth.Next.Level=start_level+0 lasth=lasth.Next # Generate state "Enabled.Green" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Green" if state_prefix==None: lasth.Next.PathName="Enabled.Green" else: lasth.Next.PathName=state_prefix+".Enabled.Green" lasth.Next.StateNum=2 lasth.Next.Level=start_level+1 lasth=lasth.Next # Generate state "Enabled.Red" in the hierarchy table lasth.Next=Hierarchy() lasth.Next.StateName="Red" if state_prefix==None: lasth.Next.PathName="Enabled.Red" else: lasth.Next.PathName=state_prefix+".Enabled.Red" lasth.Next.StateNum=3 lasth.Next.Level=start_level+1 lasth=lasth.Next return h.Next def topLevelHistory(self): s=self.state.StateID t=self.getParentState(s) while t!=-1: s=t t=self.getParentState(s) self.changeState(s, s) def runActionCode(self, code_num): if code_num==0: # model finalizer pass elif code_num==1: # model initializer pass elif code_num==2: # enter actions for state "Enabled" # a timed transition sched=Scheduler(self, "__INTERNAL_0_TIME_0", eval("10", self.DefaultInterpreter.locals), 1) sched.Next=self.TimedTransitions[1] self.TimedTransitions[1]=sched sched.start() elif code_num==3: # exit actions for state "Enabled" # clean up timed transitions if self.TimedTransitions[1]: self.TimedTransitions[1].clear() self.TimedTransitions[1]=None def testCondition(self, cond_num): if cond_num==0 and \ self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult: return 1 elif cond_num==1 and \ self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult: return 1 elif cond_num==2 and \ self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult: return 1 return 0 def runEnterActionsForStates(self, states, recursive=0): if states: self.runEnterActionsForStates(states.Next, 0) self.runEnterActions(states.int) if recursive: for s in self.Submodels: if s: s.runEnterActionsForStates(s.StatesEntered, 1) def runEnterActions(self, state): if state==1: # enter action(s) for state "Enabled" self.runActionCode(2) def runExitActions(self, state): if state==1: # exit action(s) for state "Enabled" self.runActionCode(3) def runExitActionsForStates(self, common_state): substates=self.getSubstates(common_state) if substates==None: s=self.state while s!=None and s.StateID!=common_state: s=s.Next if s!=None and self.Submodels[s.StateID]: self.Submodels[s.StateID].runExitActionsForStates(-1) return s!=None else: has_current_substate=0 while substates!=None: res=self.runExitActionsForStates(substates.int) has_current_substate=has_current_substate or res if res: self.runExitActions(substates.int) substates=substates.Next return has_current_substate def runInitializer(self): self.runActionCode(1) for s in self.Submodels: if s: s.runInitializer() def runFinalizer(self): if self.Started: for s in self.Submodels: if s: s.runFinalizer() self.runActionCode(0) self.Started=0 def runInteractor(self): pass def clearEnteredStates(self): self.StatesEntered=None for s in self.Submodels: if s: s.clearEnteredStates() def runCode(self, c): if len(c)>0: l="" for i in string.split(c, "\n"): if len(l)==0: l=i elif string.find(i, " ")!=0 and not (string.find(i, "else")==0 and string.strip(i[4:])==":") and \ string.find(i, "elif ")!=0 and string.find(i, "elif\t")!=0 and \ not (string.find(i, "except")==0 and string.strip(i[6:])==":") and \ string.find(i, "except ")!=0 and string.find(i, "except\t")!=0: self.DefaultInterpreter.runsource(l+"\n") l=i else: l=l+"\n"+i if len(l)>0: self.DefaultInterpreter.runsource(l+"\n") def setupInterpreter(self): self.DefaultInterpreter.locals["eventhandler"]=self self.DefaultInterpreter.locals["dump_message"]=self.dump_message def start(self, run_enter_actions=1): if run_enter_actions: self.runEnterActionsForStates(self.StatesEntered, 1) self.Started=1 if run_enter_actions: self.checkPendingEvents() def event(self, e, params=[], lock=None, call_submodels=1): self.EventsLock.acquire() running=self.HandleEventRunning if not running and self.Started: self.HandleEventRunning=1 self.EventsLock.release() if not running: thread.start_new_thread(self.handleEvent, (e, params, lock, call_submodels)) else: self.EventsLock.acquire() ev=EventList() ev.Event=[e, params, lock, call_submodels] if self.PendingEventsTail!=None: self.PendingEventsTail.Next=ev else: self.PendingEvents=ev self.PendingEventsTail=ev self.EventsLock.release() def checkPendingEvents(self): self.EventsLock.acquire() ev=self.PendingEvents if ev!=None: self.PendingEvents=ev.Next if self.PendingEvents==None: self.PendingEventsTail=None if ev: self.EventsLock.release() self.handleEvent(ev.Event[0], ev.Event[1], ev.Event[2], ev.Event[3]) else: self.HandleEventRunning=0 self.EventsLock.release() def get_event_params(self): return self.params def dump_message(self, msg): print msg def is_in_state(self, state, check_substate=0): i=0 while i<behaviour_generated_no_link_with_gui.StateNum and behaviour_generated_no_link_with_gui.StateNames[i]!=state: i=i+1 if i<behaviour_generated_no_link_with_gui.StateNum: return (not check_substate or self.isLeafState(i)) and self.isInState(i) else: return 0
class QShell(QtGui.QTextEdit): """This class embeds a python interperter in a QTextEdit Widget It is based on PyCute developed by Gerard Vermeulen. """ def __init__(self, locals=None, parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QtGui.QTextEdit.__init__(self, parent) self.setReadOnly(False) self.setWindowTitle("Console") # to exit the main interpreter by a Ctrl-D if QShell has no parent if parent is None: self.eofKey = QtCore.Qt.Key_D else: self.eofKey = None # flag for knowing when selecting text self.selectMode = False self.interpreter = None self.controller = None # storing current state #this is not working on mac #self.prev_stdout = sys.stdout #self.prev_stdin = sys.stdin #self.prev_stderr = sys.stderr # capture all interactive input/output #sys.stdout = self #sys.stderr = self #sys.stdin = self # user interface setup self.setAcceptRichText(False) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) conf = get_vistrails_configuration() shell_conf = conf.shell # font font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size) font.setFixedPitch(1) self.setFont(font) self.reset(locals) def load_package(self, pkg_name): reg = vistrails.core.modules.module_registry.get_module_registry() package = reg.get_package_by_name(pkg_name) def create_dict(modules, ns, m, mdesc): md = {} if len(ns) == 0: d = {'_module_desc': mdesc, '_package': pkg,} modules[m] = type('module', (vistrails_module,), d) else: if ns[0] in modules: md = create_dict(modules[ns[0]], ns[1:], m, mdesc) else: md = create_dict(md, ns[1:], m, mdesc) modules[ns[0]] = md return modules def create_namespace_path(root, modules): for k,v in modules.iteritems(): if isinstance(v, dict): d = create_namespace_path(k,v) modules[k] = d if root is not None: modules['_package'] = pkg return type(root, (object,), modules)() else: return modules def get_module_init(module_desc): def init(self, *args, **kwargs): self.__dict__['module'] = \ vistrails.api.add_module_from_descriptor(module_desc) return init def get_module(package): def getter(self, attr_name): desc_tuple = (attr_name, '') if desc_tuple in package.descriptors: module_desc = package.descriptors[desc_tuple] d = {'_module_desc': module_desc, '_package': self,} return type('module', (vistrails_module,), d) else: raise AttributeError("type object '%s' has no attribute " "'%s'" % (self.__class__.__name__, attr_name)) return getter d = {'__getattr__': get_module(package),} pkg = type(package.name, (object,), d)() modules = {} for (m,ns) in package.descriptors: module_desc = package.descriptors[(m,ns)] modules = create_dict(modules, ns.split('|'), m, module_desc) modules = create_namespace_path(None, modules) for (k,v) in modules.iteritems(): setattr(pkg, k, v) return pkg def selected_modules(self): shell_modules = [] modules = vistrails.api.get_selected_modules() for module in modules: d = {'_module': module} shell_modules.append(type('module', (vistrails_module,), d)()) return shell_modules def reset(self, locals): """reset(locals) -> None Reset shell preparing it for a new session. """ locals['load_package'] = self.load_package locals['selected_modules'] = self.selected_modules if self.interpreter: del self.interpreter self.interpreter = InteractiveInterpreter(locals) # last line + last incomplete lines self.line = '' self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.last = 0 # interpreter prompt. if hasattr(sys, "ps1"): sys.ps1 else: sys.ps1 = ">>> " if hasattr(sys, "ps2"): sys.ps2 else: sys.ps2 = "... " # interpreter banner self.write('VisTrails shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.write(sys.ps1) def flush(self): """flush() -> None. Simulate stdin, stdout, and stderr. """ pass def isatty(self): """isatty() -> int Simulate stdin, stdout, and stderr. """ return 1 def readline(self): """readline() -> str Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) while self.reading: qApp.processOneEvent() if len(self.line) == 0: return '\n' else: return self.line def write(self, text): """write(text: str) -> None Simulate stdin, stdout, and stderr. """ cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.insertPlainText(text) cursor = self.textCursor() self.last = cursor.position() def insertFromMimeData(self, source): if source.hasText(): cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.__insertText(source.text()) def scroll_bar_at_bottom(self): """Returns true if vertical bar exists and is at bottom, or if vertical bar does not exist.""" bar = self.verticalScrollBar() if not bar: return True return bar.value() == bar.maximum() def __run(self): """__run() -> None Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) # self.set_controller() should_scroll = self.scroll_bar_at_bottom() self.pointer = 0 self.history.append(self.line) self.lines.append(self.line) source = '\n'.join(self.lines) self.write('\n') self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() if should_scroll: bar = self.verticalScrollBar() if bar: bar.setValue(bar.maximum()) def __clearLine(self): """__clearLine() -> None Clear input line buffer. """ self.line = "" self.point = 0 def __insertText(self, text): """__insertText(text) -> None Insert text at the current cursor position. """ self.insertPlainText(text) self.line = self.line[:self.point] + text + self.line[self.point:] self.point += len(text) # def add_pipeline(self, p): # """ # add_pipeline(p) -> None # Set the active pipeline in the command shell. This replaces the modules # variable with the list of current active modules of the selected pipeline. # """ # if self.controller: # self.interpreter.active_pipeline = self.controller.current_pipeline # else: # self.interpreter.active_pipeline = p # cmd = 'active_pipeline = self.shell.interpreter.active_pipeline' # self.interpreter.runcode(cmd) # cmd = 'modules = self.vistrails_interpreter.find_persistent_entities(active_pipeline)[0]' # self.interpreter.runcode(cmd) def set_controller(self, controller=None): """set_controller(controller: VistrailController) -> None Set the current VistrailController on the shell. """ self.controller = controller if controller: self.interpreter.active_pipeline = self.controller.current_pipeline cmd = 'active_pipeline = self.shell.interpreter.active_pipeline' self.interpreter.runcode(cmd) cmd = 'modules = self.vistrails_interpreter.' \ 'find_persistent_entities(active_pipeline)[0]' self.interpreter.runcode(cmd) # def set_pipeline(self): # """set_active_pipeline() -> None # Makes sure that the pipeline being displayed is present in the shell for # direct inspection and manipulation # """ # self.add_pipeline(None) def keyPressEvent(self, e): """keyPressEvent(e) -> None Handle user input a key at a time. Notice that text might come more than one keypress at a time if user is a fast enough typist! """ text = e.text() key = e.key() # NB: Sometimes len(str(text)) > 1! if len(text) and all(ord(x) >= 32 and ord(x) < 127 for x in str(text)): # exit select mode and jump to end of text cursor = self.textCursor() if self.selectMode or cursor.hasSelection(): self.selectMode = False cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.__insertText(text) return if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey: self.parent().closeSession() if e.modifiers() & QtCore.Qt.ControlModifier: if key == QtCore.Qt.Key_C or key == QtCore.Qt.Key_Insert: self.copy() elif key == QtCore.Qt.Key_V: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.paste() elif key == QtCore.Qt.Key_A: self.selectAll() self.selectMode = True else: e.ignore() return if e.modifiers() & QtCore.Qt.ShiftModifier: if key == QtCore.Qt.Key_Insert: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) self.paste() else: e.ignore() return # exit select mode and jump to end of text cursor = self.textCursor() if self.selectMode or cursor.hasSelection(): self.selectMode = False cursor.movePosition(QtGui.QTextCursor.End) cursor.clearSelection() self.setTextCursor(cursor) if key == QtCore.Qt.Key_Backspace: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 self.line = self.line[:self.point] + self.line[self.point+1:] elif key == QtCore.Qt.Key_Delete: QtGui.QTextEdit.keyPressEvent(self, e) self.line = self.line[:self.point] + self.line[self.point+1:] elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter: if self.reading: self.reading = 0 else: self.__run() elif key == QtCore.Qt.Key_Tab: self.__insertText(text) elif key == QtCore.Qt.Key_Left: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 elif key == QtCore.Qt.Key_Right: if self.point < len(self.line): QtGui.QTextEdit.keyPressEvent(self, e) self.point += 1 elif key == QtCore.Qt.Key_Home: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.StartOfLine) cursor.setPosition(cursor.position() + 4) self.setTextCursor(cursor) self.point = 0 elif key == QtCore.Qt.Key_End: QtGui.QTextEdit.keyPressEvent(self, e) self.point = len(self.line) elif key == QtCore.Qt.Key_Up: if len(self.history): if self.pointer == 0: self.pointer = len(self.history) self.pointer -= 1 self.__recall() elif key == QtCore.Qt.Key_Down: if len(self.history): self.pointer += 1 if self.pointer == len(self.history): self.pointer = 0 self.__recall() else: e.ignore() def __recall(self): """__recall() -> None Display the current item from the command history. """ cursor = self.textCursor() cursor.setPosition(self.last) cursor.select(QtGui.QTextCursor.LineUnderCursor) cursor.removeSelectedText() self.setTextCursor(cursor) self.insertPlainText(sys.ps1) self.__clearLine() self.__insertText(self.history[self.pointer]) def focusNextPrevChild(self, next): """focusNextPrevChild(next) -> None Suppress tabbing to the next window in multi-line commands. """ if next and self.more: return 0 return QtGui.QTextEdit.focusNextPrevChild(self, next) def mousePressEvent(self, e): """mousePressEvent(e) -> None Keep the cursor after the last prompt. """ if e.button() == QtCore.Qt.LeftButton: self.selectMode = True QtGui.QTextEdit.mousePressEvent(self, e) # cursor = self.textCursor() # cursor.movePosition(QtGui.QTextCursor.End) # self.setTextCursor(cursor) return def hide(self): """suspend() -> None Called when hiding the parent window in order to recover the previous state. """ #recovering the state sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ sys.stdin = sys.__stdin__ def show(self): """show() -> None Store previous state and starts capturing all interactive input and output. """ # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self self.setFocus() def saveSession(self, fileName): """saveSession(fileName: str) -> None Write its contents to a file """ output = open(str(fileName), 'w') output.write(self.toPlainText()) output.close() def restart(self, locals=None): """restart(locals=None) -> None Restart a new session """ self.clear() self.reset(locals) def contentsContextMenuEvent(self,ev): """ contentsContextMenuEvent(ev) -> None Suppress the right button context menu. """ return
class PyCute(QTextEdit): reading = 0 history = [] pointer = 0 def __init__(self, locals=None, log='', parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, you can exit the interpreter by typing Ctrl-D. """ QTextEdit.__init__(self) self.interpreter = Interpreter(locals) self.connect(self, SIGNAL("returnPressed()"), self.onReturnPressed) # session log self.log = log or 'PyCute.log' # to exit the main interpreter by a Ctrl-D if PyCute has no parent if parent is None: self.eofKey = Qt.Key_D else: self.eofKey = None # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self # user interface setup self.setTextFormat(QTextEdit.PlainText) self.setWrapPolicy(QTextEdit.Anywhere) self.setCaption('PyCute -- a Python Shell for PyQt -- ' 'http://gerard.vermeulen.free.fr') # font if os.name == 'posix': font = QFont("Fixed", 12) elif os.name == 'nt' or os.name == 'dos': font = QFont("Courier New", 8) else: raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'" font.setFixedPitch(1) self.setFont(font) # geometry height = 40*QFontMetrics(font).lineSpacing() request = QSize(600, height) if parent is not None: request = request.boundedTo(parent.size()) self.resize(request) # interpreter prompt. try: sys.ps1 except AttributeError: sys.ps1 = ">>> " try: sys.ps2 except AttributeError: sys.ps2 = "... " # interpreter banner self.write('The PyCute shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.') self.ps1() # __init__() def write(self, line): self.append(line.rstrip('\n')) self.moveCursor(QTextEdit.MoveEnd, 0) # write() def flush(self): pass # flush() def ps1(self): self.append(sys.ps1) self.moveCursor(QTextEdit.MoveEnd, 0) self.mark = self.getCursorPosition() # ps1() def ps2(self): self.append(sys.ps2) self.moveCursor(QTextEdit.MoveEnd, 0) # ps2() def tab(self): self.insert(' ') self.moveCursor(QTextEdit.MoveEnd, 0) # tab() def getLines(self): apply(self.setSelection, self.mark + self.getCursorPosition()) lines = self.selectedText() return str(lines) # getLines() def readline(self): lines = self.getLines() self.history.insert(0, (self.mark, lines)) self.moveCursor(QTextEdit.MoveEnd, 0) self.mark = self.getCursorPosition() self.reading = 1 while self.reading: qApp.processOneEvent() return self.getLines().rstrip() or '\n' # readline() def push(self): lines = self.getLines() if not self.interpreter.runsource(lines.replace(sys.ps2, '')): self.history.insert(0, (self.mark, lines)) #print self.history self.ps1() else: self.ps2() # push() def onReturnPressed(self): if self.reading: self.reading = 0 else: self.push() # onReturnPressed() def keyPressEvent(self, e): ascii = e.ascii() key = e.key() state = e.state() text = e.text() #print "'%s' '%s' '%s' '%s'" % (ascii, key, state, text) if state & Qt.ControlButton and key == self.eofKey: try: file = open(self.log, "w") file.write(str(self.text())) file.close() except: pass sys.exit() return if state & Qt.ControlButton and key == Qt.Key_I: self.tab() return if key == Qt.Key_Tab: # completion return if key == Qt.Key_Return and not self.reading: position = self.getCursorPosition() if self.mark > position: for mark, lines in self.history: if mark < position: apply(self.setCursorPosition, self.mark) self.insert(lines.rstrip('\n')) return else: return QTextEdit.keyPressEvent(self, e)
class PythonWidget(HistoryConsoleWidget): """ A basic in-process Python interpreter. """ # Emitted when a command has been executed in the interpeter. executed = QtCore.Signal() #-------------------------------------------------------------------------- # 'object' interface #-------------------------------------------------------------------------- def __init__(self, parent=None): super(PythonWidget, self).__init__(parent) # PythonWidget attributes. self.locals = dict(__name__='__console__', __doc__=None) self.interpreter = InteractiveInterpreter(self.locals) # PythonWidget protected attributes. self._buffer = StringIO() self._bracket_matcher = BracketMatcher(self._control) self._call_tip_widget = CallTipWidget(self._control) self._completion_lexer = CompletionLexer(PythonLexer()) self._hidden = False self._highlighter = PythonWidgetHighlighter(self) self._last_refresh_time = 0 # file-like object attributes. self.encoding = sys.stdin.encoding # Configure the ConsoleWidget. self.tab_width = 4 self._set_continuation_prompt('... ') # Configure the CallTipWidget. self._call_tip_widget.setFont(self.font) self.font_changed.connect(self._call_tip_widget.setFont) # Connect signal handlers. document = self._control.document() document.contentsChange.connect(self._document_contents_change) # Display the banner and initial prompt. self.reset() #-------------------------------------------------------------------------- # file-like object interface #-------------------------------------------------------------------------- def flush(self): """ Flush the buffer by writing its contents to the screen. """ self._buffer.seek(0) text = self._buffer.getvalue() self._buffer.close() self._buffer = StringIO() self._append_plain_text(text) self._control.moveCursor(QtGui.QTextCursor.End) def readline(self, prompt=None): """ Read and return one line of input from the user. """ return self._readline(prompt) def write(self, text, refresh=True): """ Write text to the buffer, possibly flushing it if 'refresh' is set. """ if not self._hidden: self._buffer.write(text) if refresh: current_time = time() if current_time - self._last_refresh_time > 0.05: self.flush() self._last_refresh_time = current_time def writelines(self, lines, refresh=True): """ Write a list of lines to the buffer. """ for line in lines: self.write(line, refresh=refresh) #--------------------------------------------------------------------------- # 'ConsoleWidget' abstract interface #--------------------------------------------------------------------------- def _is_complete(self, source, interactive): """ Returns whether 'source' can be completely processed and a new prompt created. When triggered by an Enter/Return key press, 'interactive' is True; otherwise, it is False. """ if interactive: lines = source.splitlines() if len(lines) == 1: try: return compile_command(source) is not None except: # We'll let the interpeter handle the error. return True else: return lines[-1].strip() == '' else: return True def _execute(self, source, hidden): """ Execute 'source'. If 'hidden', do not show any output. See parent class :meth:`execute` docstring for full details. """ # Save the current std* and point them here old_stdin = sys.stdin old_stdout = sys.stdout old_stderr = sys.stderr sys.stdin = sys.stdout = sys.stderr = self # Run the source code in the interpeter self._hidden = hidden try: more = self.interpreter.runsource(source) finally: self._hidden = False # Restore std* unless the executed changed them if sys.stdin is self: sys.stdin = old_stdin if sys.stdout is self: sys.stdout = old_stdout if sys.stderr is self: sys.stderr = old_stderr self.executed.emit() self._show_interpreter_prompt() def _prompt_started_hook(self): """ Called immediately after a new prompt is displayed. """ if not self._reading: self._highlighter.highlighting_on = True def _prompt_finished_hook(self): """ Called immediately after a prompt is finished, i.e. when some input will be processed and a new prompt displayed. """ if not self._reading: self._highlighter.highlighting_on = False def _tab_pressed(self): """ Called when the tab key is pressed. Returns whether to continue processing the event. """ # Perform tab completion if: # 1) The cursor is in the input buffer. # 2) There is a non-whitespace character before the cursor. text = self._get_input_buffer_cursor_line() if text is None: return False complete = bool(text[:self._get_input_buffer_cursor_column()].strip()) if complete: self._complete() return not complete #--------------------------------------------------------------------------- # 'ConsoleWidget' protected interface #--------------------------------------------------------------------------- def _event_filter_console_keypress(self, event): """ Reimplemented for smart backspace. """ if event.key() == QtCore.Qt.Key_Backspace and \ not event.modifiers() & QtCore.Qt.AltModifier: # Smart backspace: remove four characters in one backspace if: # 1) everything left of the cursor is whitespace # 2) the four characters immediately left of the cursor are spaces col = self._get_input_buffer_cursor_column() cursor = self._control.textCursor() if col > 3 and not cursor.hasSelection(): text = self._get_input_buffer_cursor_line()[:col] if text.endswith(' ') and not text.strip(): cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor, 4) cursor.removeSelectedText() return True return super(PythonWidget, self)._event_filter_console_keypress(event) def _insert_continuation_prompt(self, cursor): """ Reimplemented for auto-indentation. """ super(PythonWidget, self)._insert_continuation_prompt(cursor) source = self.input_buffer space = 0 for c in source.splitlines()[-1]: if c == '\t': space += 4 elif c == ' ': space += 1 else: break if source.rstrip().endswith(':'): space += 4 cursor.insertText(' ' * space) #--------------------------------------------------------------------------- # 'PythonWidget' public interface #--------------------------------------------------------------------------- def execute_file(self, path, hidden=False): """ Attempts to execute file with 'path'. If 'hidden', no output is shown. """ self.execute('execfile("%s")' % path, hidden=hidden) def reset(self): """ Resets the widget to its initial state. Similar to ``clear``, but also re-writes the banner. """ self._reading = False self._highlighter.highlighting_on = False self._control.clear() self._append_plain_text(self._get_banner()) self._show_interpreter_prompt() #--------------------------------------------------------------------------- # 'PythonWidget' protected interface #--------------------------------------------------------------------------- def _call_tip(self): """ Shows a call tip, if appropriate, at the current cursor location. """ # Decide if it makes sense to show a call tip cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.Left) if cursor.document().characterAt(cursor.position()) != '(': return False context = self._get_context(cursor) if not context: return False # Look up the context and show a tip for it symbol, leftover = self._get_symbol_from_context(context) doc = getattr(symbol, '__doc__', None) if doc is not None and not leftover: self._call_tip_widget.show_call_info(doc=doc) return True return False def _complete(self): """ Performs completion at the current cursor location. """ context = self._get_context() if context: symbol, leftover = self._get_symbol_from_context(context) if len(leftover) == 1: leftover = leftover[0] if symbol is None: names = self.interpreter.locals.keys() names += __builtin__.__dict__.keys() else: names = dir(symbol) completions = [n for n in names if n.startswith(leftover)] if completions: cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.Left, n=len(context[-1])) self._complete_with_items(cursor, completions) def _get_banner(self): """ Gets a banner to display at the beginning of a session. """ banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \ '"license" for more information.' return banner % (sys.version, sys.platform) def _get_context(self, cursor=None): """ Gets the context for the specified cursor (or the current cursor if none is specified). """ if cursor is None: cursor = self._get_cursor() cursor.movePosition(QtGui.QTextCursor.StartOfBlock, QtGui.QTextCursor.KeepAnchor) text = cursor.selection().toPlainText() return self._completion_lexer.get_context(text) def _get_symbol_from_context(self, context): """ Find a python object in the interpeter namespace from a context (a list of names). """ context = map(str, context) if len(context) == 0: return None, context base_symbol_string = context[0] symbol = self.interpreter.locals.get(base_symbol_string, None) if symbol is None: symbol = __builtin__.__dict__.get(base_symbol_string, None) if symbol is None: return None, context context = context[1:] for i, name in enumerate(context): new_symbol = getattr(symbol, name, None) if new_symbol is None: return symbol, context[i:] else: symbol = new_symbol return symbol, [] def _show_interpreter_prompt(self): """ Shows a prompt for the interpreter. """ self.flush() self._show_prompt('>>> ') #------ Signal handlers ---------------------------------------------------- def _document_contents_change(self, position, removed, added): """ Called whenever the document's content changes. Display a call tip if appropriate. """ # Calculate where the cursor should be *after* the change: position += added document = self._control.document() if position == self._get_cursor().position(): self._call_tip()
class QShell(QtGui.QTextEdit): """This class embeds a python interperter in a QTextEdit Widget It is based on PyCute developed by Gerard Vermeulen. """ def __init__(self, locals=None, parent=None): """Constructor. The optional 'locals' argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key "__name__" set to "__console__" and key "__doc__" set to None. The optional 'log' argument specifies the file in which the interpreter session is to be logged. The optional 'parent' argument specifies the parent widget. If no parent widget has been specified, it is possible to exit the interpreter by Ctrl-D. """ QtGui.QTextEdit.__init__(self, parent) self.setReadOnly(False) # to exit the main interpreter by a Ctrl-D if QShell has no parent if parent is None: self.eofKey = QtCore.Qt.Key_D else: self.eofKey = None self.interpreter = None # storing current state #this is not working on mac #self.prev_stdout = sys.stdout #self.prev_stdin = sys.stdin #self.prev_stderr = sys.stderr # capture all interactive input/output #sys.stdout = self #sys.stderr = self #sys.stdin = self # user interface setup self.setAcceptRichText(False) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) app = gui.application.VistrailsApplication shell_conf = app.configuration.shell # font font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size) font.setFixedPitch(1) self.setCurrentFont(font) self.reset(locals) def reset(self, locals): """reset(locals) -> None Reset shell preparing it for a new session. """ if self.interpreter: del self.interpreter self.interpreter = InteractiveInterpreter(locals) # last line + last incomplete lines self.line = QtCore.QString() self.lines = [] # the cursor position in the last line self.point = 0 # flag: the interpreter needs more input to run the last lines. self.more = 0 # flag: readline() is being used for e.g. raw_input() and input() self.reading = 0 # history self.history = [] self.pointer = 0 self.last = 0 # interpreter prompt. if hasattr(sys, "ps1"): sys.ps1 else: sys.ps1 = ">>> " if hasattr(sys, "ps2"): sys.ps2 else: sys.ps2 = "... " # interpreter banner self.write('VisTrails shell running Python %s on %s.\n' % (sys.version, sys.platform)) self.write('Type "copyright", "credits" or "license"' ' for more information on Python.\n') self.write(sys.ps1) def flush(self): """flush() -> None. Simulate stdin, stdout, and stderr. """ pass def isatty(self): """isatty() -> int Simulate stdin, stdout, and stderr. """ return 1 def readline(self): """readline() -> str Simulate stdin, stdout, and stderr. """ self.reading = 1 self.__clearLine() cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) while self.reading: qApp.processOneEvent() if self.line.length() == 0: return '\n' else: return str(self.line) def write(self, text): """write(text: str) -> None Simulate stdin, stdout, and stderr. """ self.insertPlainText(text) cursor = self.textCursor() self.last = cursor.position() def scroll_bar_at_bottom(self): """Returns true if vertical bar exists and is at bottom, or if vertical bar does not exist.""" bar = self.verticalScrollBar() if not bar: return True return bar.value() == bar.maximum() def __run(self): """__run() -> None Append the last line to the history list, let the interpreter execute the last line(s), and clean up accounting for the interpreter results: (1) the interpreter succeeds (2) the interpreter fails, finds no errors and wants more line(s) (3) the interpreter fails, finds errors and writes them to sys.stderr """ should_scroll = self.scroll_bar_at_bottom() self.pointer = 0 self.history.append(QtCore.QString(self.line)) self.lines.append(str(self.line)) source = '\n'.join(self.lines) self.write('\n') self.more = self.interpreter.runsource(source) if self.more: self.write(sys.ps2) else: self.write(sys.ps1) self.lines = [] self.__clearLine() if should_scroll: bar = self.verticalScrollBar() if bar: bar.setValue(bar.maximum()) def __clearLine(self): """__clearLine() -> None Clear input line buffer. """ self.line.truncate(0) self.point = 0 def __insertText(self, text): """__insertText(text) -> None Insert text at the current cursor position. """ self.insertPlainText(text) self.line.insert(self.point, text) self.point += text.length() def keyPressEvent(self, e): """keyPressEvent(e) -> None Handle user input a key at a time. """ text = e.text() key = e.key() if not text.isEmpty(): ascii = ord(str(text)) else: ascii = -1 if text.length() and ascii>=32 and ascii<127: self.__insertText(text) return if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey: self.parent().closeSession() if (e.modifiers() & QtCore.Qt.ControlModifier or e.modifiers() & QtCore.Qt.ShiftModifier): e.ignore() return if key == QtCore.Qt.Key_Backspace: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 self.line.remove(self.point, 1) elif key == QtCore.Qt.Key_Delete: QtGui.QTextEdit.keyPressEvent(self, e) self.line.remove(self.point, 1) elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter: if self.reading: self.reading = 0 else: self.__run() elif key == QtCore.Qt.Key_Tab: self.__insertText(text) elif key == QtCore.Qt.Key_Left: if self.point: QtGui.QTextEdit.keyPressEvent(self, e) self.point -= 1 elif key == QtCore.Qt.Key_Right: if self.point < self.line.length(): QtGui.QTextEdit.keyPressEvent(self, e) self.point += 1 elif key == QtCore.Qt.Key_Home: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.StartOfLine) cursor.setPosition(cursor.position() + 4) self.setTextCursor(cursor) self.point = 0 elif key == QtCore.Qt.Key_End: QtGui.QTextEdit.keyPressEvent(self, e) self.point = self.line.length() elif key == QtCore.Qt.Key_Up: if len(self.history): if self.pointer == 0: self.pointer = len(self.history) self.pointer -= 1 self.__recall() elif key == QtCore.Qt.Key_Down: if len(self.history): self.pointer += 1 if self.pointer == len(self.history): self.pointer = 0 self.__recall() else: e.ignore() def __recall(self): """__recall() -> None Display the current item from the command history. """ cursor = self.textCursor() cursor.setPosition(self.last) cursor.select(QtGui.QTextCursor.LineUnderCursor) cursor.removeSelectedText() self.setTextCursor(cursor) self.insertPlainText(sys.ps1) self.__clearLine() self.__insertText(self.history[self.pointer]) def focusNextPrevChild(self, next): """focusNextPrevChild(next) -> None Suppress tabbing to the next window in multi-line commands. """ if next and self.more: return 0 return QtGui.QTextEdit.focusNextPrevChild(self, next) def mousePressEvent(self, e): """mousePressEvent(e) -> None Keep the cursor after the last prompt. """ if e.button() == QtCore.Qt.LeftButton: cursor = self.textCursor() cursor.movePosition(QtGui.QTextCursor.End) self.setTextCursor(cursor) return # def suspend(self): # """suspend() -> None # Called when hiding the parent window in order to recover the previous # state. # """ # #recovering the state # sys.stdout = self.prev_stdout # sys.stderr = self.prev_stderr # sys.stdin = self.prev_stdin def show(self): """show() -> None Store previous state and starts capturing all interactive input and output. """ # # storing current state # self.prev_stdout = sys.stdout # self.prev_stdin = sys.stdin # self.prev_stderr = sys.stderr # capture all interactive input/output sys.stdout = self sys.stderr = self sys.stdin = self def saveSession(self, fileName): """saveSession(fileName: str) -> None Write its contents to a file """ output = open(str(fileName), 'w') output.write(self.toPlainText()) output.close() def restart(self, locals=None): """restart(locals=None) -> None Restart a new session """ self.clear() self.reset(locals) def contentsContextMenuEvent(self,ev): """ contentsContextMenuEvent(ev) -> None Suppress the right button context menu. """ return