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
42 - def __init__(self, globals, lokals):
43 self.globals = globals 44 self.locals = lokals 45 46 self.completions = keyword.kwlist + \ 47 __builtin__.__dict__.keys() + \ 48 __main__.__dict__.keys()
49
50 - def complete(self, text, state):
51 if state == 0: 52 text = text.split(' ')[-1] 53 if "." in text: 54 self.matches = self.attr_matches(text) 55 else: 56 self.matches = self.global_matches(text) 57 try: 58 return self.matches[state] 59 except IndexError: 60 return None
61
62 - def update(self, globs, locs):
63 self.globals = globs 64 self.locals = locs 65 66 for key in self.locals.keys(): 67 if not key in self.completions: 68 self.completions.append(key) 69 for key in self.globals.keys(): 70 if not key in self.completions: 71 self.completions.append(key)
72
73 - def global_matches(self, text):
74 matches = [] 75 n = len(text) 76 for word in self.completions: 77 if word[:n] == text: 78 matches.append(word) 79 return matches
80
81 - def attr_matches(self, text):
82 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) 83 if not m: 84 return 85 expr, attr = m.group(1, 3) 86 87 obj = eval(expr, self.globals, self.locals) 88 words = dir(obj) 89 90 matches = [] 91 n = len(attr) 92 for word in words: 93 if word[:n] == attr: 94 matches.append("%s.%s" % (expr, word)) 95 return matches
96 97
98 -class GtkInterpreter(threading.Thread):
99 """Run a gtk main() in a separate thread. 100 Python commands can be passed to the thread where they will be executed. 101 This is implemented by periodically checking for passed code using a 102 GTK timeout callback. 103 """ 104 TIMEOUT = 100 # Millisecond interval between timeouts. 105
106 - def __init__(self, globals=None, locals=None):
107 threading.Thread.__init__(self) 108 self.ready = threading.Condition() 109 self.globs = globals or {'__name__': 110 '__console__', 'gtk': gtk} 111 self.locs = locals or {} 112 self._has_quit = False 113 self.cmd = '' # Current code block 114 self.new_cmd = None # Waiting line of code, or None if none waiting 115 116 self.completer = Completer(self.globs, self.locs)
117
118 - def run(self):
119 print self.banner 120 readline.set_completer(self.completer.complete) 121 readline.parse_and_bind('tab: complete') 122 ps1 = getattr(self, 'ps1', '>>> ') 123 ps2 = getattr(self, 'ps1', '... ') 124 read = self.reader 125 126 prompt = ps1 127 try: 128 while True: 129 command = read(prompt) + '\n' # raw_input strips newlines 130 prompt = self.feed(command) and ps1 or ps2 131 except (EOFError, KeyboardInterrupt): 132 pass 133 print 134 self._has_quit = True
135
136 - def code_exec(self):
137 """Execute waiting code. Called every timeout period.""" 138 self.ready.acquire() 139 140 if self._has_quit: 141 if self.main_loop: 142 self.main_loop.quit() 143 return False 144 145 if self.new_cmd != None: 146 self.ready.notify() 147 self.cmd = self.cmd + self.new_cmd 148 self.new_cmd = None 149 try: 150 code = codeop.compile_command(self.cmd[:-1]) 151 if code: 152 self.cmd = '' 153 exec code in self.globs, self.locs 154 self.completer.update(self.globs, self.locs) 155 except Exception: 156 traceback.print_exc() 157 self.cmd = '' 158 159 self.ready.release() 160 return True
161
162 - def feed_sync(self, code):
163 if (not code) or (code[-1]<>'\n'): 164 code = code +'\n' # raw_input strips newline 165 self.ready.acquire() 166 self.completer.update(self.globs, self.locs) 167 self.new_cmd = code 168 self.code_exec() 169 self.ready.release() 170 return not self.cmd
171
172 - def feed(self, code):
173 """Feed a line of code to the thread. 174 This function will block until the code checked by the GTK thread. 175 Return true if executed the code. 176 Returns false if deferring execution until complete block available. 177 """ 178 # raw_input strips newline 179 if (not code) or (code[-1]<>'\n'): 180 code = code +'\n' 181 self.completer.update(self.globs, self.locs) 182 self.ready.acquire() 183 self.new_cmd = code 184 self.ready.wait() # Wait until processed in timeout interval 185 self.ready.release() 186 187 return not self.cmd
188
189 - def interact(self, banner=None, reader=None, block=False):
190 self.banner = banner or 'Interactive GTK Shell' 191 self.reader = reader or raw_input 192 gobject.timeout_add(self.TIMEOUT, self.code_exec) 193 gtk.gdk.threads_init() 194 self.start() 195 self.main_loop = block and gobject.MainLoop() 196 if self.main_loop: 197 self.main_loop.run()
198 199 # Read user input in a loop, and send each line to the interpreter thread. 200 201
202 -def interact(banner=None, reader=None, local=None):
203 interpreter = GtkInterpreter(locals=local) 204 interpreter.interact(banner, reader)
205 206 if __name__=="__main__": 207 interpreter = GtkInterpreter() 208 interpreter.feed_sync("import sys") 209 interpreter.feed_sync("sys.path.append('.')") 210 211 if len(sys.argv) > 1: 212 for file in open(sys.argv[1]).readlines(): 213 interpreter.feed_sync(file) 214 215 banner = 'Interactive GTK Shell' 216 py_version = string.join(map(str, sys.version_info[:3]), '.') 217 pygtk_version = string.join(map(str, gtk.pygtk_version), '.') 218 gtk_version = string.join(map(str, gtk.gtk_version), '.') 219 banner += '\nPython %s, Pygtk %s, GTK+ %s' % (py_version, pygtk_version, 220 gtk_version) 221 222 interpreter.interact(banner, block=True) 223