Package flumotion :: Package extern :: Module code
[hide private]

Source Code for Module flumotion.extern.code

  1  #!/usr/bin/env python 
  2  # Can be run standalone, or as a module 
  3   
  4  # gpython.py: GTK+-compatible read-eval-print loop. 
  5  # Adopted for use in Flumotion by Andy Wingo. 
  6  # 
  7  # Copyright (C) 2001 Brian McErlean 
  8  # Copyright (C) 2003 John Finlay 
  9  # Copyright (C) 2004 Guilherme Salgado 
 10  # Copyright (C) 2005 Andy Wingo 
 11  # 
 12  # gpython.py originates in ActiveState Python Cookbook Recipe 65109, 
 13  # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109. 
 14  # 
 15  # Following the Cookbook license policy at 
 16  # http://aspn.activestate.com/ASPN/Cookbook/Python, this file is 
 17  # licensed under the same terms as Python itself. 
 18   
 19   
 20  import __builtin__ 
 21  import __main__ 
 22  import codeop 
 23  import keyword 
 24  import re 
 25  import readline 
 26  import threading 
 27  import traceback 
 28  import sys 
 29  import string 
 30   
 31  import pygtk 
 32  pygtk.require("2.0") 
 33  import gobject 
 34  import gtk 
 35   
 36   
 37  __all__ = ['interact'] 
 38   
 39   
40 -class Completer:
41 - def __init__ (self, globals, lokals):
42 self.globals = globals 43 self.locals = lokals 44 45 self.completions = keyword.kwlist + \ 46 __builtin__.__dict__.keys() + \ 47 __main__.__dict__.keys()
48 - def complete (self, text, state):
49 if state == 0: 50 text = text.split(' ')[-1] 51 if "." in text: 52 self.matches = self.attr_matches (text) 53 else: 54 self.matches = self.global_matches (text) 55 try: 56 return self.matches[state] 57 except IndexError: 58 return None
59
60 - def update (self, globs, locs):
61 self.globals = globs 62 self.locals = locs 63 64 for key in self.locals.keys (): 65 if not key in self.completions: 66 self.completions.append (key) 67 for key in self.globals.keys (): 68 if not key in self.completions: 69 self.completions.append (key)
70
71 - def global_matches (self, text):
72 matches = [] 73 n = len (text) 74 for word in self.completions: 75 if word[:n] == text: 76 matches.append (word) 77 return matches
78
79 - def attr_matches (self, text):
80 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) 81 if not m: 82 return 83 expr, attr = m.group(1, 3) 84 85 obj = eval (expr, self.globals, self.locals) 86 words = dir(obj) 87 88 matches = [] 89 n = len(attr) 90 for word in words: 91 if word[:n] == attr: 92 matches.append ("%s.%s" % (expr, word)) 93 return matches
94
95 -class GtkInterpreter (threading.Thread):
96 """Run a gtk main() in a separate thread. 97 Python commands can be passed to the thread where they will be executed. 98 This is implemented by periodically checking for passed code using a 99 GTK timeout callback. 100 """ 101 TIMEOUT = 100 # Millisecond interval between timeouts. 102
103 - def __init__ (self, globals=None, locals=None):
104 threading.Thread.__init__ (self) 105 self.ready = threading.Condition () 106 self.globs = globals or {'__name__':'__console__', 'gtk':gtk} 107 self.locs = locals or {} 108 self._has_quit = False 109 self.cmd = '' # Current code block 110 self.new_cmd = None # Waiting line of code, or None if none waiting 111 112 self.completer = Completer (self.globs, self.locs)
113
114 - def run (self):
115 print self.banner 116 readline.set_completer (self.completer.complete) 117 readline.parse_and_bind ('tab: complete') 118 ps1 = getattr(self,'ps1','>>> ') 119 ps2 = getattr(self,'ps1','... ') 120 read = self.reader 121 122 prompt = ps1 123 try: 124 while True: 125 command = read (prompt) + '\n' # raw_input strips newlines 126 prompt = self.feed (command) and ps1 or ps2 127 except (EOFError, KeyboardInterrupt): pass 128 print 129 self._has_quit = True
130
131 - def code_exec (self):
132 """Execute waiting code. Called every timeout period.""" 133 self.ready.acquire () 134 135 if self._has_quit: 136 if self.main_loop: 137 self.main_loop.quit() 138 return False 139 140 if self.new_cmd != None: 141 self.ready.notify () 142 self.cmd = self.cmd + self.new_cmd 143 self.new_cmd = None 144 try: 145 code = codeop.compile_command (self.cmd[:-1]) 146 if code: 147 self.cmd = '' 148 exec code in self.globs, self.locs 149 self.completer.update (self.globs, self.locs) 150 except Exception: 151 traceback.print_exc () 152 self.cmd = '' 153 154 self.ready.release() 155 return True
156
157 - def feed_sync (self, code):
158 if (not code) or (code[-1]<>'\n'): code = code +'\n' # raw_input strips newline 159 self.ready.acquire () 160 self.completer.update (self.globs, self.locs) 161 self.new_cmd = code 162 self.code_exec() 163 self.ready.release () 164 return not self.cmd
165
166 - def feed (self, code):
167 """Feed a line of code to the thread. 168 This function will block until the code checked by the GTK thread. 169 Return true if executed the code. 170 Returns false if deferring execution until complete block available. 171 """ 172 if (not code) or (code[-1]<>'\n'): code = code +'\n' # raw_input strips newline 173 self.completer.update (self.globs, self.locs) 174 self.ready.acquire() 175 self.new_cmd = code 176 self.ready.wait () # Wait until processed in timeout interval 177 self.ready.release () 178 179 return not self.cmd
180
181 - def interact(self, banner=None, reader=None, block=False):
182 self.banner = banner or 'Interactive GTK Shell' 183 self.reader = reader or raw_input 184 gobject.timeout_add (self.TIMEOUT, self.code_exec) 185 gtk.gdk.threads_init() 186 self.start() 187 self.main_loop = block and gobject.MainLoop() 188 if self.main_loop: 189 self.main_loop.run()
190 191 # Read user input in a loop, and send each line to the interpreter thread. 192
193 -def interact(banner=None, reader=None, local=None):
194 interpreter = GtkInterpreter(locals=local) 195 interpreter.interact(banner, reader)
196 197 if __name__=="__main__": 198 interpreter = GtkInterpreter() 199 interpreter.feed_sync ("import sys") 200 interpreter.feed_sync ("sys.path.append('.')") 201 202 if len (sys.argv) > 1: 203 for file in open (sys.argv[1]).readlines (): 204 interpreter.feed_sync (file) 205 206 banner = 'Interactive GTK Shell' 207 py_version = string.join(map(str, sys.version_info[:3]), '.') 208 pygtk_version = string.join(map(str, gtk.pygtk_version), '.') 209 gtk_version = string.join(map(str, gtk.gtk_version), '.') 210 banner += '\nPython %s, Pygtk %s, GTK+ %s' % (py_version, pygtk_version, 211 gtk_version) 212 213 interpreter.interact(banner, block=True) 214