.. _user_interfaces-interactive2: user_interfaces example code: interactive2.py ============================================= [`source code `_] :: from __future__ import print_function # GTK Interactive Console # (C) 2003, Jon Anderson # See www.python.org/2.2/license.html for # license details. # import gtk import gtk.gdk import code import os import sys import pango import __builtin__ import __main__ banner = """GTK Interactive Python Console Thanks to Jon Anderson %s """ % sys.version banner += """ Welcome to matplotlib. help(matplotlib) -- some general information about matplotlib help(plotting) -- shows a list of plot specific commands """ class Completer(object): """ Taken from rlcompleter, with readline references stripped, and a local dictionary to use. """ def __init__(self, locals): self.locals = locals def complete(self, text, state): """Return the next possible completion for 'text'. This is called successively with state == 0, 1, 2, ... until it returns None. The completion should begin with 'text'. """ if state == 0: if "." in text: self.matches = self.attr_matches(text) else: self.matches = self.global_matches(text) try: return self.matches[state] except IndexError: return None def global_matches(self, text): """Compute matches when text is a simple name. Return a list of all keywords, built-in functions and names currently defines in __main__ that match. """ import keyword matches = [] n = len(text) for list in [keyword.kwlist, __builtin__.__dict__.keys(), __main__.__dict__.keys(), self.locals.keys()]: for word in list: if word[:n] == text and word != "__builtins__": matches.append(word) return matches def attr_matches(self, text): """Compute matches when text contains a dot. Assuming the text is of the form NAME.NAME....[NAME], and is evaluatable in the globals of __main__, it will be evaluated and its attributes (as revealed by dir()) are used as possible completions. (For class instances, class members are are also considered.) WARNING: this can still invoke arbitrary C code, if an object with a __getattr__ hook is evaluated. """ import re m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) if not m: return expr, attr = m.group(1, 3) object = eval(expr, __main__.__dict__, self.locals) words = dir(object) if hasattr(object, '__class__'): words.append('__class__') words = words + get_class_members(object.__class__) matches = [] n = len(attr) for word in words: if word[:n] == attr and word != "__builtins__": matches.append("%s.%s" % (expr, word)) return matches def get_class_members(klass): ret = dir(klass) if hasattr(klass, '__bases__'): for base in klass.__bases__: ret = ret + get_class_members(base) return ret class OutputStream(object): """ A Multiplexing output stream. It can replace another stream, and tee output to the original stream and too a GTK textview. """ def __init__(self, view, old_out, style): self.view = view self.buffer = view.get_buffer() self.mark = self.buffer.create_mark("End", self.buffer.get_end_iter(), False) self.out = old_out self.style = style self.tee = 1 def write(self, text): if self.tee: self.out.write(text) end = self.buffer.get_end_iter() if self.view is not None: self.view.scroll_to_mark(self.mark, 0, True, 1, 1) self.buffer.insert_with_tags(end, text, self.style) class GTKInterpreterConsole(gtk.ScrolledWindow): """ An InteractiveConsole for GTK. It's an actual widget, so it can be dropped in just about anywhere. """ def __init__(self): gtk.ScrolledWindow.__init__(self) self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.text = gtk.TextView() self.text.set_wrap_mode(True) self.interpreter = code.InteractiveInterpreter() self.completer = Completer(self.interpreter.locals) self.buffer = [] self.history = [] self.banner = banner self.ps1 = ">>> " self.ps2 = "... " self.text.add_events(gtk.gdk.KEY_PRESS_MASK) self.text.connect("key_press_event", self.key_pressed) self.current_history = -1 self.mark = self.text.get_buffer().create_mark("End", self.text.get_buffer().get_end_iter(), False) # setup colors self.style_banner = gtk.TextTag("banner") self.style_banner.set_property("foreground", "saddle brown") self.style_ps1 = gtk.TextTag("ps1") self.style_ps1.set_property("foreground", "DarkOrchid4") self.style_ps1.set_property("editable", False) self.style_ps1.set_property("font", "courier") self.style_ps2 = gtk.TextTag("ps2") self.style_ps2.set_property("foreground", "DarkOliveGreen") self.style_ps2.set_property("editable", False) self.style_ps2.set_property("font", "courier") self.style_out = gtk.TextTag("stdout") self.style_out.set_property("foreground", "midnight blue") self.style_err = gtk.TextTag("stderr") self.style_err.set_property("style", pango.STYLE_ITALIC) self.style_err.set_property("foreground", "red") self.text.get_buffer().get_tag_table().add(self.style_banner) self.text.get_buffer().get_tag_table().add(self.style_ps1) self.text.get_buffer().get_tag_table().add(self.style_ps2) self.text.get_buffer().get_tag_table().add(self.style_out) self.text.get_buffer().get_tag_table().add(self.style_err) self.stdout = OutputStream(self.text, sys.stdout, self.style_out) self.stderr = OutputStream(self.text, sys.stderr, self.style_err) sys.stderr = self.stderr sys.stdout = self.stdout self.current_prompt = None self.write_line(self.banner, self.style_banner) self.prompt_ps1() self.add(self.text) self.text.show() def reset_history(self): self.history = [] def reset_buffer(self): self.buffer = [] def prompt_ps1(self): self.current_prompt = self.prompt_ps1 self.write_line(self.ps1, self.style_ps1) def prompt_ps2(self): self.current_prompt = self.prompt_ps2 self.write_line(self.ps2, self.style_ps2) def write_line(self, text, style=None): start, end = self.text.get_buffer().get_bounds() if style is None: self.text.get_buffer().insert(end, text) else: self.text.get_buffer().insert_with_tags(end, text, style) self.text.scroll_to_mark(self.mark, 0, True, 1, 1) def push(self, line): self.buffer.append(line) if len(line) > 0: self.history.append(line) source = "\n".join(self.buffer) more = self.interpreter.runsource(source, "<>") if not more: self.reset_buffer() return more def key_pressed(self, widget, event): if event.keyval == gtk.gdk.keyval_from_name('Return'): return self.execute_line() if event.keyval == gtk.gdk.keyval_from_name('Up'): self.current_history = self.current_history - 1 if self.current_history < - len(self.history): self.current_history = - len(self.history) return self.show_history() elif event.keyval == gtk.gdk.keyval_from_name('Down'): self.current_history = self.current_history + 1 if self.current_history > 0: self.current_history = 0 return self.show_history() elif event.keyval == gtk.gdk.keyval_from_name('Home'): l = self.text.get_buffer().get_line_count() - 1 start = self.text.get_buffer().get_iter_at_line_offset(l, 4) self.text.get_buffer().place_cursor(start) return True elif event.keyval == gtk.gdk.keyval_from_name('space') and event.state & gtk.gdk.CONTROL_MASK: return self.complete_line() return False def show_history(self): if self.current_history == 0: return True else: self.replace_line(self.history[self.current_history]) return True def current_line(self): start, end = self.current_line_bounds() return self.text.get_buffer().get_text(start, end, True) def current_line_bounds(self): txt_buffer = self.text.get_buffer() l = txt_buffer.get_line_count() - 1 start = txt_buffer.get_iter_at_line(l) if start.get_chars_in_line() >= 4: start.forward_chars(4) end = txt_buffer.get_end_iter() return start, end def replace_line(self, txt): start, end = self.current_line_bounds() self.text.get_buffer().delete(start, end) self.write_line(txt) def execute_line(self, line=None): if line is None: line = self.current_line() self.write_line("\n") else: self.write_line(line + "\n") more = self.push(line) self.text.get_buffer().place_cursor(self.text.get_buffer().get_end_iter()) if more: self.prompt_ps2() else: self.prompt_ps1() self.current_history = 0 self.window.raise_() return True def complete_line(self): line = self.current_line() tokens = line.split() token = tokens[-1] completions = [] p = self.completer.complete(token, len(completions)) while p is not None: completions.append(p) p = self.completer.complete(token, len(completions)) if len(completions) != 1: self.write_line("\n") self.write_line("\n".join(completions), self.style_ps1) self.write_line("\n") self.current_prompt() self.write_line(line) else: i = line.rfind(token) line = line[0:i] + completions[0] self.replace_line(line) return True def main(): w = gtk.Window() console = GTKInterpreterConsole() console.set_size_request(640, 480) w.add(console) def destroy(arg=None): gtk.main_quit() def key_event(widget, event): if gtk.gdk.keyval_name(event.keyval) == 'd' and \ event.state & gtk.gdk.CONTROL_MASK: destroy() return False w.connect("destroy", destroy) w.add_events(gtk.gdk.KEY_PRESS_MASK) w.connect('key_press_event', key_event) w.show_all() console.execute_line('import matplotlib') console.execute_line("matplotlib.use('GTKAgg')") console.execute_line('matplotlib.interactive(1)') console.execute_line('from pylab import *') if len(sys.argv) > 1: fname = sys.argv[1] if not os.path.exists(fname): print('%s does not exist' % fname) for line in file(fname): line = line.strip() console.execute_line(line) gtk.main() if __name__ == '__main__': main() Keywords: python, matplotlib, pylab, example, codex (see :ref:`how-to-search-examples`)