Package SPyRO :: Module codepools
[hide private]
[frames] | no frames]

Source Code for Module SPyRO.codepools

  1  #coding: iso-8859-1; 
  2  ############################################################################ 
  3  #                                                                          # 
  4  #    This file 'codepools.py'                                              # 
  5  #    is part of 'SPyRO: Simple Python Remote Objects'                      # 
  6  #    Copyright (C) 2004-2005 by Eric Sadit Tellez Avila                    # 
  7  #    Copyright (C) 2005-2006 by Eric Sadit Tellez Avila                    # 
  8  #    Copyright (C) 2007 by Eric Sadit Tellez Avila                         # 
  9  #    Copyright (C) 2008 by Eric Sadit Tellez Avila                         # 
 10  #    sadit@lsc.fie.umich.mx or donsadit@gmail.com                          # 
 11  #                                                                          # 
 12  #    is part of 'Dweba: Distributed Web Application Framework (for Python)'# 
 13  #    Copyright (C) 2008      by Eric Sadit Tellez Avila                    # 
 14  #                                                                          # 
 15  #    This program is free software; you can redistribute it and#or modify  # 
 16  #    it under the terms of the GNU General Public License as published by  # 
 17  #    the Free Software Foundation; either version 2 of the License, or     # 
 18  #    (at your option) any later version.                                   # 
 19  #                                                                          # 
 20  #    This program is distributed in the hope that it will be useful,       # 
 21  #    but WITHOUT ANY WARRANTY; without even the implied warranty of        # 
 22  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         # 
 23  #    GNU General Public License for more details.                          # 
 24  #                                                                          # 
 25  #    You should have received a copy of the GNU General Public License     # 
 26  #    along with this program; if not, write to the                         # 
 27  #    Free Software Foundation, Inc.,                                       # 
 28  #    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             # 
 29  ############################################################################ 
 30   
 31  import os 
 32  import sys 
 33  from threading import Lock 
 34  from exec_code import exec_code 
 35  import policies 
 36  import warn 
 37   
 38  import types 
39 -def _set_booleans():
40 BooleanType = types.IntType 41 __builtins__['True'] = 1 42 __builtins__['False'] = 0
43 44 try: 45 BooleanType = types.BooleanType 46 True 47 except: 48 warn.warn("An old version of python or jython was detected") 49 _set_booleans() 50 51 ############################################################################## 52 ############################################################################## 53 ##### The server class set 54 ############################################################################## 55 ############################################################################## 56
57 -class ServerObjectPool:
58 """ The pool of objects interface. This class is a basic 59 pool implemented with a dictionary. To create a different 60 pool of objects is necessary to create a class that implement 61 every method in this interface. 62 """
63 - def __init__(self, objects = None):
64 """ Init the ServerObjectPool object with a """ 65 if objects is None: 66 objects = {} 67 self.objects = objects
68
69 - def setobj(self, name, obj, authobj = None):
70 """ Register an object |obj| with the ID |name| """ 71 self.objects[name] = (obj,authobj)
72
73 - def getobj(self, name):
74 """ Get an object and its authorization data, it must raise a 75 KeyError exception if |name| is not present in the pool """ 76 return self.objects[name]
77
78 - def delobj(self, name):
79 """ Remove an object with name |name|""" 80 del self.objects[name]
81
82 - def setsend(self, newid, ret, auth = None):
83 """ Register an object (to send by reference)""" 84 self.setobj(newid, ret, auth) 85 return newid
86
87 -class ItemCodePool: pass
88
89 -class CodeLoader:
90 - def read(self, name):
91 raise KeyError("This method must be overloaded")
92
93 - def getmtime(self, name):
94 return 0
95
96 -class FileSystemCodeLoader(CodeLoader):
97 - def __init__(self):
98 pass
99
100 - def read(self, filename):
101 f = file(filename) 102 d = f.read() 103 f.close() 104 return d
105
106 - def getmtime(self, filename):
107 return os.stat(filename).st_mtime
108
109 -class ZipCodeLoader(CodeLoader):
110 - def __init__(self, zipfile, originseparator='/'):
111 self.zipfile = zipfile 112 self.originseparator = originseparator
113
114 - def read(self, filename):
115 filename = filename.replace(os.path.sep, self.originseparator) 116 return self.zipfile.read(filename)
117
118 - def getmtime(self, filename):
119 filename = filename.replace(os.path.sep, self.originseparator) 120 self.zipfile.getinfo(filename) 121 return 0
122
123 -class CodePool:
124 """ Register python modules and executes functions in modules. 125 The registration of objects must not be used, instead a list of module's path is given. 126 The registrarion is supported to serve setsend calls. The getobj method reads modules 127 from path. The module is loaded the first time that is requested, next requests uses 128 a cached version of the module. If the module changes in the disk, is reloaded 129 (if checkupdates=True, True by default). Every 130 time that the module is readed it can execute global statments 131 132 """
133 - def __init__(self, path, checkupdates=True, codeloader=None):
134 """ Init the ServerObjectPool object with a """ 135 self.path = path 136 self.objects = {} 137 self.cache = {} # name : timestamp, filename 138 self.lock = Lock() 139 self.gvars = {} 140 if codeloader is None: 141 codeloader = FileSystemCodeLoader() 142 self.codeloader = codeloader 143 self.checkupdates = checkupdates
144
145 - def setobj(self, name, obj, authobj = None):
146 """ Register an object |obj| with the ID |name| """ 147 self.lock.acquire() 148 self.objects[name] = (obj,authobj) 149 self.lock.release()
150
151 - def _import_(self, name, _globals, _locals, fromlist):
152 """ 153 Replace function of __import__ to support 154 import modules from the code pool 155 """ 156 try: 157 return self.getobj(name)[0] 158 # return imp.load_module(name,*imp.find_module(name,self.path)) 159 except KeyError,e: 160 return __import__(name,_globals,_locals,fromlist)
161
162 - def _reload_(self, mod):
163 """ Reload an SPyRO module or a python module """ 164 try: 165 import sys 166 sys.modules[mod.__name__] = self.getobj(mod.__name__)[0] 167 except KeyError: 168 reload(mod)
169
170 - def getobj(self, name):
171 """ Get an object and its authorization data, it must raise a 172 KeyError exception if |name| is not present in the pool """ 173 if name[0] != '!': 174 try: 175 obj, authobj = self.objects[name] 176 if not obj or self.checkupdates: 177 self.loadmodule(name, authobj) 178 except (KeyError, IndexError), err: 179 authobj = None 180 self.loadmodule(name, authobj) 181 return self.objects[name]
182
183 - def loadmodule(self, name, authobj):
184 """ Loads a python's module in the object path (self.path) 185 The authority object is set to the |_spyro_authentication| global 186 variable in the module. 187 If it is not present the |authobj| argument is used instead. 188 189 """ 190 if name.startswith('.') or os.path.sep in name: 191 return 192 for p in self.path: 193 filename = os.path.join(p, name + '.py') 194 codeloader = self.codeloader 195 try: 196 mtime = codeloader.getmtime(filename) 197 except: 198 continue 199 try: 200 _filename, _mtime = self.cache[name] 201 if _filename == filename and _mtime == mtime: return 202 except KeyError: 203 pass 204 lvars = ItemCodePool() 205 lvars.__dict__['__builtins__'] = {} 206 lvars.__dict__.update(__builtins__) 207 lvars.__dict__['__builtins__']['__import__'] = self._import_ 208 lvars.__dict__['__name__'] = name 209 # lvars.__dict__['reload'] = self._reload_ 210 # Double setobj operation: 211 # Work around to prevent recursive import loops 212 # first: 213 self.setobj(name, lvars, authobj) 214 exec_code(filename, self.gvars, lvars, codeloader.read(filename)) 215 self.cache[name] = (filename, mtime) 216 try: 217 auth = lvars._spyro_authentication 218 except AttributeError: 219 if authobj == None: # default accessor 220 auth = lvars._spyro_authentication = policies.PublicAllowCall() 221 else: 222 auth = authobj 223 # second and final 224 self.setobj(name, lvars, auth) 225 return lvars
226
227 - def delobj(self, name):
228 """ Remove an object with name |name|""" 229 del self.objects[name] 230 try: 231 del self.cache[name] 232 except: 233 pass
234
235 - def setsend(self, newid, ret, auth = None):
236 """ Register an object (to send by reference)""" 237 self.setobj(newid, ret, auth) 238 return newid
239 240
241 -class ModulePool(ServerObjectPool):
242 """ 243 Register python modules as SPyRO objects. The modules must exists in a given path 244 and will be appended to system path (sys.path) if the path is not in the sys.path. 245 246 If the source code changes, the module will be reloaded. 247 The packages can exists in a zip files too, or any other supported python package 248 container, just giving the |statfunction| like os.stat function 249 250 """
251 - def __init__(self, path, checkupdates=True, statfunction=os.stat):
252 """ Initialize the pool """ 253 ServerObjectPool.__init__(self) 254 self.path = [] 255 for x in path: 256 x = os.path.abspath(x) 257 self.path.append(x) 258 try: 259 sys.path.index(x) 260 except ValueError: 261 sys.path.append(x) 262 self.cache = {} # objectname : timestamp 263 self.statfunction = statfunction 264 self.checkupdates = checkupdates
265
266 - def getobj(self, name):
267 """ Get an object and its authorization data, it must raise a 268 KeyError exception if |name| is not present in the pool """ 269 try: 270 res = ServerObjectPool.getobj(self, name) 271 if res[0] is None: 272 raise KeyError("Fake") 273 else: 274 return res 275 except KeyError, e: 276 try: 277 __import__(name) 278 except ImportError: 279 warn.warn("==================== Import error in ModulePool.getobj %s"%repr(name)) 280 raise e 281 except SyntaxError: 282 warn.warn("==================== Syntax error importing a module ModulePool.getobj %s"%repr(name)) 283 raise 284 m = sys.modules[name] 285 abspath = os.path.abspath(m.__file__) 286 if self.checkupdates: 287 if abspath[-1] == 'c': # .pyc -> .py 288 abspath = abspath[:-1] 289 try: 290 try: 291 mtime = self.cache[name] 292 newmtime = self.statfunction(abspath).st_mtime 293 if mtime != newmtime: 294 self.cache[name] = newmtime 295 reload(m) 296 except KeyError: 297 self.cache[name] = self.statfunction(abspath).st_mtime 298 except (OSError, IOError),e: # deletion of the module or package, or something with the network FS 299 raise e 300 for p in self.path: 301 if abspath.startswith(p): 302 try: 303 auth = m._spyro_authentication 304 except AttributeError: 305 auth = m._spyro_authentication = policies.PublicAllowCall() 306 return (m, auth) 307 raise e
308