Package Ganga :: Package GPIDev :: Package Base :: Module Proxy
[hide private]
[frames] | no frames]

Source Code for Module Ganga.GPIDev.Base.Proxy

  1  ################################################################################ 
  2  # Ganga Project. http://cern.ch/ganga 
  3  # 
  4  # $Id: Proxy.py,v 1.2.4.3 2009-07-10 11:29:27 ebke Exp $ 
  5  ################################################################################ 
  6   
  7  import Ganga.Utility.logging 
  8  logger = Ganga.Utility.logging.getLogger(modulename=1) 
  9   
 10  import Ganga.GPIDev.Schema as Schema 
 11   
 12  from Ganga.Core import GangaException,GangaAttributeError,ProtectedAttributeError,ReadOnlyObjectError,TypeMismatchError,SchemaError 
 13   
 14  from Ganga.Utility.util import importName 
 15   
 16  #some proxy related convieniance methods 
17 -def isProxy(obj):
18 """Checks if an object is a proxy""" 19 return isinstance(obj, GPIProxyObject)
20
21 -def isType(obj, type_or_seq):
22 """Checks whether on object is of the specified type, stripping proxies as needed.""" 23 return isinstance(stripProxy(obj), type_or_seq)
24
25 -def stripProxy(obj):
26 """Removes the proxy if there is one""" 27 result = obj 28 if isProxy(obj): 29 result = obj._impl 30 return result
31
32 -def addProxy(obj):
33 """Adds a proxy to a GangaObject""" 34 from Ganga.GPIDev.Base.Objects import GangaObject 35 if isinstance(obj, GangaObject): 36 return GPIProxyObjectFactory(obj) 37 return obj
38
39 -def getProxyAttr(obj, attr_name):
40 """Gets an attribute from a proxied object""" 41 return getattr(stripProxy(obj), attr_name)
42
43 -def runProxyMethod(obj, method_name, *args):
44 """Calls a method on the object, removing the proxy if needed""" 45 fp = getProxyAttr(obj,method_name) 46 return fp(*args)
47 48 # apply object conversion or if it fails, strip the proxy and extract the object implementation
49 -def stripComponentObject(v,cfilter,item):
50 51 from Ganga.GPIDev.Base import GangaObject 52 53 def getImpl(v): 54 if v is None: 55 if not item['optional']: 56 raise TypeMismatchError(None,'component is mandatory and None may not be used') 57 return v 58 if isinstance(v, GangaObject): 59 return v 60 if not isinstance(v, GPIProxyObject): 61 raise TypeMismatchError("cannot assign value '%s', expected a '%s' object "%(repr(v),item['category'])) 62 return v._impl
63 64 vv = cfilter(v,item) 65 if vv is None: 66 return getImpl(v) 67 else: 68 return vv 69 70 from Ganga.GPIDev.TypeCheck import _valueTypeAllowed 71 valueTypeAllowed = lambda val,valTypeList: _valueTypeAllowed(val,valTypeList,logger) 72
73 -class ProxyDataDescriptor(object):
74 - def __init__(self, name):
75 self._name = name
76
77 - def __get__(self, obj, cls):
78 # at class level return a helper object (for textual description) 79 if obj is None: 80 #return Schema.make_helper(getattr(cls._impl,self._name)) 81 return getattr(cls._impl,self._name) 82 83 val = getattr(obj._impl, self._name) 84 85 # apply object conversion or if it failes, make the wrapper proxy 86 def disguiseComponentObject(v): 87 # get the proxy for implementation object 88 def getProxy(v): 89 from Ganga.GPIDev.Base import GangaObject 90 if not isinstance(v, GangaObject): 91 raise GangaAttributeError("invalid type: cannot assign '%s' to attribute '%s'"%(repr(v),self._name)) 92 return GPIProxyObjectFactory(v)
93 94 # convert implementation object to GPI value according to the static method defined in the implementation object 95 def object2value(v): 96 return None
97 98 vv = object2value(v) 99 if vv is None: 100 # allow None to be a legal value for optional component items 101 if v is None: return None 102 else: 103 return getProxy(v) 104 else: 105 return vv 106 107 # apply attribute conversion 108 def disguiseAttribute(v): 109 #FIXME: this is obsoleted method 110 from Ganga.GPIDev.Base import GangaObject 111 if isinstance(v,GangaObject): 112 return GPIProxyObjectFactory(v) 113 return v 114 115 # wrap proxy 116 item = obj._impl._schema[self._name] 117 118 if item['proxy_get']: 119 return getattr(obj._impl,item['proxy_get'])() 120 121 if item.isA(Schema.ComponentItem): 122 disguiser = disguiseComponentObject 123 else: 124 disguiser = disguiseAttribute 125 126 from Ganga.GPIDev.Lib.GangaList.GangaList import makeGangaList 127 if item['sequence'] and isinstance(val,list): 128 val = makeGangaList(val,disguiser) 129 130 return disguiser(val) 131
132 - def _check_type(self, obj, val):
133 item = obj._impl._schema[self._name] 134 return item._check_type(val, self._name)
135
136 - def __set__(self, obj, val):
137 item = obj._impl._schema[self._name] 138 139 if item['protected']: 140 raise ProtectedAttributeError('"%s" attribute is protected and cannot be modified'%(self._name,)) 141 if obj._impl._readonly(): 142 raise ReadOnlyObjectError('object %s is read-only and attribute "%s" cannot be modified now'%(repr(obj),self._name)) 143 144 # apply attribute conversion 145 def stripAttribute(v): 146 # just warn 147 #print '**** checking',v,v.__class__, isinstance(val,GPIProxyObject) 148 if isinstance(v,GPIProxyObject): 149 v = v._impl 150 logger.debug('%s property: assigned a component object (_impl used)',self._name) 151 return obj._impl._attribute_filter__set__(self._name,v)
152 153 # unwrap proxy 154 if item.isA(Schema.ComponentItem): 155 from Filters import allComponentFilters 156 item = obj._impl._schema.getItem(self._name) 157 cfilter = allComponentFilters[item['category']] 158 stripper = lambda v: stripComponentObject(v,cfilter,item) 159 else: 160 stripper = stripAttribute 161 162 from Ganga.GPIDev.Lib.GangaList.GangaList import GangaList, makeGangaList 163 if item['sequence']: 164 # we need to explicitly check for the list type, because simple values (such as strings) may be iterable 165 if isType(val, (GangaList,list)): 166 #create GangaList 167 val = makeGangaList(val,stripper) 168 else: 169 # val is not iterable 170 if item['strict_sequence']: 171 raise GangaAttributeError('cannot assign a simple value %s to a strict sequence attribute %s.%s (a list is expected instead)'%(repr(val),obj._impl._schema.name,self._name)) 172 val = makeGangaList(stripper(val)) 173 else: 174 val = stripper(val) 175 176 # apply attribute filter to component items 177 if item.isA(Schema.ComponentItem): 178 val = stripAttribute(val) 179 180 self._check_type(obj,val) 181 setattr(obj._impl, self._name, val) 182 183
184 -class ProxyMethodDescriptor(object):
185 - def __init__(self, name, internal_name):
186 self._name = name 187 self._internal_name = internal_name
188 - def __get__(self, obj, cls):
189 if obj is None: 190 return getattr(cls._impl,self._internal_name) 191 return getattr(obj._impl, self._internal_name)
192 193 ################################################################################ 194 195 # helper to create a wrapper for an existing ganga object
196 -def GPIProxyObjectFactory(obj):
197 if obj._proxyObject is None: 198 cls = obj._proxyClass 199 proxy = super(cls, cls).__new__(cls) 200 proxy.__dict__['_impl'] = obj #FIXME: NEW STYLE CLASS CAN DO __DICT__?? 201 obj._proxyObject = proxy 202 logger.debug('generated the proxy '+repr(proxy)) 203 else: 204 logger.debug('reusing the proxy '+repr(obj._proxyObject)) 205 return obj._proxyObject # FIXED
206 207 # this class serves only as a 'tag' for all generated GPI proxy classes 208 # so we can test with isinstance rather then relying on more generic but less user friendly checking of attribute x._impl
209 -class GPIProxyObject(object): pass
210 211 # create a new GPI class for a given ganga (plugin) class
212 -def GPIProxyClassFactory(name, pluginclass):
213 214 def helptext(f,s): 215 f.__doc__ = s % {'classname':name,'objname':name.lower(),'shortvarname':name[0].lower()}
216 217 # construct the class on-the-fly using the functions below as methods for the new class 218 219 def _init(self,*args,**kwds): 220 #if len(args) > 1: 221 # logger.warning('extra arguments in the %s constructor ignored: %s',name,args[1:]) 222 223 # at the object level _impl is a ganga plugin object 224 self.__dict__['_impl'] = pluginclass() 225 self._impl.__construct__(map(stripProxy,args)) 226 227 # initialize all properties from keywords of the constructor 228 for k in kwds: 229 if self._impl._schema.hasAttribute(k): 230 setattr(self,k,kwds[k]) 231 else: 232 logger.warning('keyword argument in the %s constructur ignored: %s=%s (not defined in the schema)',name,k,kwds[k]) 233 234 self._impl._proxyObject = self 235 self._impl._auto__init__() 236 237 from Ganga.Utility.strings import ItemizedTextParagraph 238 239 itbuf = ItemizedTextParagraph('Properties:',linesep='') 240 241 for n,item in pluginclass._schema.allItems(): 242 if not item['hidden']: 243 itbuf.addLine(n,item.describe()) 244 245 if not pluginclass.__doc__: 246 pluginclass.__doc__ = 'Documentation missing.' 247 248 pluginclass.__doc__.strip() 249 pluginclass.__doc__ += "\n\n" 250 251 publicdoc = pluginclass.__doc__ + itbuf.getString() 252 helptext(pluginclass,'This is a Ganga.GPI.%(classname)s implementation class. Refer to Ganga.GPI.%(classname)s.__doc__ for documentation.') 253 254 helptext(_init, """GPI %(classname)s object constructor: 255 %(classname)s() : create %(objname)s with default settings; 256 %(classname)s(%(shortvarname)s) : make a copy of %(shortvarname)s; 257 %(classname)s(%(shortvarname)s,x=a,...): make a copy of %(shortvarname)s and set property 'x' to a, etc.. 258 """) 259 260 def _str(self): 261 import StringIO 262 sio = StringIO.StringIO() 263 self._impl.printSummaryTree(0,0,'',out = sio) 264 return sio.getvalue() 265 helptext(_str,"""Return a printable string representing %(classname)s object as a tree of properties.""") 266 267 def _repr(self): 268 try: 269 return self._impl._repr() 270 except AttributeError: 271 return '<'+repr(self._impl)+' PROXY at '+hex(abs(id(self)))+'>' 272 helptext(_repr,"Return an short representation of %(classname)s object.") 273 274 def _eq(self,x): 275 result = False 276 if isinstance(x, GPIProxyObject): result = self._impl.__eq__(x._impl) 277 else: result = self._impl.__eq__(x) 278 return result 279 helptext(_eq,"Equality operator (==), compare the %(classname)s properties which are declared as [comparable].") 280 281 def _ne(self,x): 282 return self._impl.__ne__(x._impl) 283 helptext(_ne,"Non-equality operator (!=).") 284 285 def _copy(self): 286 c = self._impl.clone() 287 c._auto__init__() 288 return GPIProxyObjectFactory(c) 289 290 helptext(_copy,"Make an identical copy of self.") 291 292 def _setattr(self,x,v): 293 'something' 294 if x == '_impl': 295 raise AttributeError("Internal implementation object '_impl' cannot be reassigned") 296 297 if not self._impl._schema.hasAttribute(x): 298 raise GangaAttributeError("'%s' has no attribute '%s'" % (self._impl._name,x)) 299 300 object.__setattr__(self,x,v) 301 helptext(_setattr,"""Set a property of %(classname)s with consistency and safety checks. 302 Setting a [protected] or a unexisting property raises AttributeError.""") 303 304 305 306 # but at the class level _impl is a ganga plugin class 307 d = { '_impl' : pluginclass, 308 '__init__' : _init, 309 '__str__' : _str, 310 '__repr__': _repr, 311 '__eq__': _eq, 312 '__ne__': _ne, 313 'copy' : _copy, 314 '__doc__' : publicdoc, 315 '__setattr__': _setattr 316 } 317 318 ## TODO: this makes GangaList inherit from the list 319 ## this is not tested and specifically the TestGangaList/testAllListMethodsExported should be verified 320 ##if name == "GangaList": 321 ## return type(name, (GPIProxyObject,list), d) 322 323 return type(name, (GPIProxyObject,), d) 324 325 # 326 # 327 # $Log: not supported by cvs2svn $ 328 # Revision 1.2.4.2 2009/07/08 15:39:15 ebke 329 # removed object_filter__get__ 330 # 331 # Revision 1.2.4.1 2009/07/08 11:18:21 ebke 332 # Initial commit of all - mostly small - modifications due to the new GangaRepository. 333 # No interface visible to the user is changed 334 # 335 # Revision 1.2 2008/09/09 14:37:16 moscicki 336 # bugfix #40220: Ensure that default values satisfy the declared types in the schema 337 # 338 # factored out type checking into schema module, fixed a number of wrongly declared schema items in the core 339 # 340 # Revision 1.1 2008/07/17 16:40:52 moscicki 341 # migration of 5.0.2 to HEAD 342 # 343 # the doc and release/tools have been taken from HEAD 344 # 345 # Revision 1.32.4.15 2008/07/02 13:19:35 moscicki 346 # TODO comment 347 # 348 # Revision 1.32.4.14 2008/06/04 10:34:54 moscicki 349 # fixed typecheck function naming 350 # 351 # Revision 1.32.4.13 2008/06/02 11:42:12 moscicki 352 # fixed typo... 353 # 354 # Revision 1.32.4.12 2008/05/27 18:02:50 kuba 355 # fixed bug #36836, .ganga.log in afs home directory 356 # 357 # Revision 1.32.4.11 2008/02/29 09:16:17 moscicki 358 # fix from Will Reece 359 # 360 # Revision 1.32.4.10 2008/02/28 15:45:30 moscicki 361 # fixed GangaList typechecking problem 362 # 363 # Revision 1.32.4.9 2008/02/06 16:26:30 moscicki 364 # typelist == None => disable type checking 365 # extra warnings for incomplete typesystem information 366 # 367 # Revision 1.32.4.8 2008/02/06 09:48:44 wreece 368 # Allows the proxy stripper a NoOp if the object has already been stripped. 369 # 370 # Revision 1.32.4.7 2008/02/06 09:28:48 wreece 371 # First pass at a cleanup of the gangalist stuff. I've made changes so the diffs with the 4.4 series are more transparent. Currently still test failures. 372 # 373 # Revision 1.32.4.6 2007/12/18 16:40:39 moscicki 374 # bugfix 375 # 376 # Revision 1.32.4.5 2007/12/18 09:05:03 moscicki 377 # integrated typesystem from Alvin and made more uniform error reporting 378 # 379 # Revision 1.32.4.4 2007/11/20 14:29:49 wreece 380 # Corrects typo in TFile, and removes extra methods from Proxy. Typo was causing tests to fail. 381 # 382 # Revision 1.32.4.3 2007/11/14 13:03:54 wreece 383 # Changes to make shortcuts work correctly with gangalists. all but one tests should now pass. 384 # 385 # Revision 1.32.4.2 2007/11/07 17:02:10 moscicki 386 # merged against Ganga-4-4-0-dev-branch-kuba-slices with a lot of manual merging 387 # 388 # Revision 1.32.4.1 2007/11/07 15:10:02 moscicki 389 # merged in pretty print and GangaList support from ganga-5-dev-branch-4-4-1-will-print branch 390 # 391 # Revision 1.32.8.2 2007/10/30 14:30:23 wreece 392 # Non-working update. Adds in Kuba's exported methods dodge. It is now possible to define a _export_ version of a method for external use and a undecorated method for internal use. 393 # 394 # Revision 1.32.8.1 2007/10/30 12:12:08 wreece 395 # First version of the new print_summary functionality. Lots of changes, but some known limitations. Will address in next version. 396 # 397 # Revision 1.32 2007/07/10 13:08:29 moscicki 398 # docstring updates (ganga devdays) 399 # 400 # Revision 1.31 2007/07/10 07:50:52 moscicki 401 # fixed #27541 402 # 403 # Revision 1.30.8.1 2007/06/18 10:16:34 moscicki 404 # slices prototype 405 # 406 # Revision 1.30 2007/03/07 09:24:34 moscicki 407 # AGAIN: fixed a problem of assigning iterable plain value (such as string) to a non-strict sequence (so x.files = "abc" was yelding 3 files "a","b","c" 408 # 409 # added GangaAttributeError exception 410 # 411 # Revision 1.29 2007/03/06 16:38:24 moscicki 412 # fixed a problem of assigning iterable plain value (such as string) to a non-strict sequence (so x.files = "abc" was yelding 3 files "a","b","c" 413 # 414 # Revision 1.28 2007/03/05 12:03:01 moscicki 415 # explicit switch for strict_sequence (default is True), if the sequence is non-strict then a single value v will be converted to [v] on assignment, for example non-strict File sequence yields obj.x = 'a' <=> obj.x = [File('a')] <=> obj.x = File('a') 416 # 417 # Revision 1.27 2007/02/28 18:20:49 moscicki 418 # moved GangaException to Ganga.Core 419 # 420 # Revision 1.26 2006/10/23 11:00:42 moscicki 421 # minor logger fixed (level changed) 422 # 423 # Revision 1.25 2006/09/15 14:19:44 moscicki 424 # Fixed bug #12229 overview: FutureWarning from Python 425 # 426 # Revision 1.24 2006/08/11 13:13:05 adim 427 # Added: GangaException as a markup base class for all exception that need to be printed in a usable way in IPython shell 428 # 429 # Revision 1.23 2005/12/02 15:28:46 moscicki 430 # customizable _repr() method on GPI objects 431 # 432 # Revision 1.22 2005/11/14 13:58:27 moscicki 433 # fixed a getter filter bug 434 # 435 # Revision 1.21 2005/11/14 10:30:37 moscicki 436 # enabled getter attribute filter 437 # 438 # Revision 1.20 2005/09/21 09:09:14 moscicki 439 # "better" repr text for proxies 440 # 441 # Revision 1.19 2005/08/26 13:21:47 moscicki 442 # do not document hidden properties 443 # 444 # Revision 1.18 2005/08/26 10:21:31 karl 445 # KH: Minor correction: linesep -> separator 446 # 447 # Revision 1.17 2005/08/26 09:54:55 moscicki 448 # minor changes 449 # 450 # Revision 1.16 2005/08/24 15:41:19 moscicki 451 # automatically generated help for properties, disabled the SchemaHelper and few other improvements to the help system 452 # 453 # Revision 1.15 2005/08/23 17:15:06 moscicki 454 # *** empty log message *** 455 # 456 # 457 # 458