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

Source Code for Module Ganga.GPIDev.Base.Objects

  1  ################################################################################ 
  2  # Ganga Project. http://cern.ch/ganga 
  3  # 
  4  # $Id: Objects.py,v 1.5.2.10 2009-07-24 13:35:53 ebke Exp $ 
  5  ################################################################################ 
  6  # NOTE: Make sure that _data and __dict__ of any GangaObject are only referenced 
  7  # here - this is necessary for write locking and lazy loading! 
  8  # IN THIS FILE: 
  9  # * Make sure every time _data or __dict__ is accessed that _data is not None. If yes, do: 
 10  #    obj._getReadAccess() 
 11  # * Make sure every write access is preceded with: 
 12  #    obj._getWriteAccess() 
 13  #   and followed by 
 14  #    obj._setDirty() 
 15   
 16  import Ganga.Utility.logging 
 17  logger = Ganga.Utility.logging.getLogger(modulename=1) 
 18   
 19  from Ganga.Utility.Plugin import allPlugins, PluginManagerError 
 20  from Ganga.Utility.Config import Config 
 21   
 22  import types 
 23  import copy 
 24   
 25  import Ganga.GPIDev.Schema as Schema 
 26   
 27  from Proxy import GPIProxyClassFactory, ProxyDataDescriptor, ProxyMethodDescriptor, GangaAttributeError, isType, TypeMismatchError 
 28  from Ganga.Core import GangaValueError 
 29   
 30  from Ganga.Utility.logic import implies 
 31  from Ganga.Utility.util import canLoopOver, isStringLike 
 32   
 33       
34 -class Node(object):
35 _parent = None 36 _index_cache = None 37
38 - def __init__(self, parent):
39 self._data= {} 40 self._setParent(parent)
41
42 - def __getstate__(self):
43 dict = self.__dict__.copy() 44 dict['_data'] = dict['_data'].copy() 45 dict['_parent'] = None 46 dict['_registry'] = None 47 dict['_index_cache'] = None 48 return dict
49
50 - def __setstate__(self, dict):
51 for n, v in dict['_data'].items(): 52 if isinstance(v,Node): 53 v._setParent(self) 54 if hasattr(v,"__iter__") and not hasattr(v,"iteritems"): 55 # set the parent of the list or dictionary (or other iterable) items 56 for i in v: 57 if isinstance(i,Node): 58 i._setParent(self) 59 60 self.__dict__ = dict
61
62 - def __copy__(self, memo = None):
63 cls = type(self) 64 obj = super(cls, cls).__new__(cls) 65 dict = self.__dict__.copy() #FIXME: this is different than for deepcopy... is this really correct? 66 obj.__dict__ = dict 67 return obj
68
69 - def __deepcopy__(self, memo = None):
70 cls = type(self) 71 obj = super(cls, cls).__new__(cls) 72 dict = self.__getstate__() 73 for n in dict: 74 dict[n] = copy.deepcopy(dict[n],memo) # FIXED 75 obj.__setstate__(dict) 76 return obj
77
78 - def _getParent(self):
79 return self._parent
80 #if "_data" in self.__dict__ and not self._data is None: 81 # return self._data['parent'] 82 #return None 83
84 - def _setParent(self, parent):
85 self._parent = parent
86 #if not self._data is None: 87 # self._data['parent'] = parent 88 89 # get the root of the object tree 90 # if parent does not exist then the root is the 'self' object 91 # cond is an optional function which may cut the search path: when it returns True, then the parent is returned as root
92 - def _getRoot(self,cond=None):
93 if self._parent is None: 94 return self 95 root = None 96 obj = self 97 while not obj is None: 98 root = obj 99 if cond and cond(root): 100 break 101 obj = obj._getParent() 102 return root
103 104 # accept a visitor pattern
105 - def accept(self,visitor):
106 visitor.nodeBegin(self) 107 108 def getdata(name): 109 try: 110 return getattr(self,name) 111 except AttributeError: 112 return self._data[name]
113 114 for (name,item) in self._schema.simpleItems(): 115 if item['visitable']: 116 visitor.simpleAttribute(self,name,getdata(name),item['sequence']) 117 118 for (name,item) in self._schema.componentItems(): 119 if item['visitable']: 120 visitor.componentAttribute(self,name,getdata(name),item['sequence']) 121 122 visitor.nodeEnd(self)
123 124 # clone self and return a properly initialized object
125 - def clone(self):
126 return copy.deepcopy(self)
127 128 # copy all the properties recursively from the srcobj 129 # if schema of self and srcobj are not compatible raises a ValueError 130 # ON FAILURE LEAVES SELF IN INCONSISTENT STATE
131 - def copyFrom(self,srcobj):
132 # Check if this object is derived from the source object, then the copy will not throw away information 133 if not isinstance(self, srcobj.__class__) and not isinstance(srcobj, self.__class__): 134 raise GangaValueError("copyFrom: Cannot copy from %s to %s!" % (srcobj.__class__, self.__class__)) 135 for name,item in self._schema.allItems(): 136 if not self._schema.hasAttribute(name): 137 #raise ValueError('copyFrom: incompatible schema: source=%s destination=%s'%(srcobj._name,self._name)) 138 setattr(self,name,self._schema.getDefaultValue(name)) 139 elif not item['copyable']: 140 setattr(self,name,self._schema.getDefaultValue(name)) 141 else: 142 c = copy.deepcopy(getattr(srcobj,name)) 143 setattr(self,name,c)
144
145 - def printTree(self,f=None, sel='' ):
146 from VPrinter import VPrinter 147 self.accept(VPrinter(f,sel))
148
149 - def printSummaryTree(self,level = 0, verbosity_level = 0, whitespace_marker = '', out = None, selection = ''):
150 """If this method is overridden, the following should be noted: 151 152 level: the hierachy level we are currently at in the object tree. 153 verbosity_level: How verbose the print should be. Currently this is always 0. 154 whitespace_marker: If printing on multiple lines, this allows the default indentation to be replicated. 155 The first line should never use this, as the substitution is 'name = %s' % printSummaryTree() 156 out: An output stream to print to. The last line of output should be printed without a newline.' 157 selection: See VPrinter for an explaintion of this. 158 """ 159 from VPrinter import VSummaryPrinter 160 self.accept(VSummaryPrinter(level, verbosity_level, whitespace_marker, out, selection))
161
162 - def __eq__(self,node):
163 164 if self is node: 165 return 1 166 167 if not node or not self._schema.isEqual(node._schema): 168 return 0 169 170 for (name,item) in self._schema.allItems(): 171 if item['comparable']: 172 if getattr(self,name) != getattr(node,name): 173 return 0 174 return 1
175
176 - def __ne__(self,node):
177 return not self == node
178 179 ################################################################################
180 -class Descriptor(object):
181 - def __init__(self, name, item):
182 self._name = name 183 self._item = item 184 self._getter_name = None 185 self._checkset_name = None 186 self._filter_name = None 187 188 try: 189 self._getter_name = item['getter'] 190 except KeyError: 191 pass 192 193 try: 194 self._checkset_name = item['checkset'] 195 except KeyError: 196 pass 197 198 try: 199 self._filter_name = item['filter'] 200 except KeyError: 201 pass
202
203 - def _bind_method(self,obj,name):
204 if name is None: 205 return None 206 return getattr(obj,name)
207
208 - def _check_getter(self):
209 if self._getter_name: 210 raise AttributeError('cannot modify or delete "%s" property (declared as "getter")'%self._name)
211
212 - def __get__(self, obj, cls):
213 if obj is None: 214 return cls._schema[self._name] 215 else: 216 result = None 217 g = self._bind_method(obj,self._getter_name) 218 if g: 219 result = g() 220 else: 221 #LAZYLOADING 222 if obj._data is None and not obj._index_cache is None and self._name in obj._index_cache: 223 result = obj._index_cache[self._name] 224 else: 225 obj._getReadAccess() 226 result = obj._data[self._name] 227 228 return result
229
230 - def __set__(self, obj, val):
231 232 from Ganga.GPIDev.Lib.GangaList.GangaList import GangaList, makeGangaList 233 234 cs = self._bind_method(obj,self._checkset_name) 235 if cs: 236 cs(val) 237 filter = self._bind_method(obj, self._filter_name) 238 if filter: 239 val = filter(val) 240 241 #LOCKING 242 obj._getWriteAccess() 243 244 #self._check_getter() 245 246 def cloneVal(v): 247 #print 'cloneVal:',self._name,v,item['optional'],item['load_default'], item['defvalue'] 248 if v is None: 249 assert(item['optional']) 250 return None 251 else: 252 assert(isinstance(v, Node)) 253 if isinstance(v, GangaList): 254 catagories = v.getCategory() 255 len_cat = len(catagories) 256 #we pass on empty lists, as the catagory is yet to be defined 257 if (len_cat > 1) or ((len_cat == 1) and (catagories[0] != item['category'])): 258 raise GangaAttributeError('%s: attempt to assign a list containing incompatible objects %s to the property in category "%s"' %(self._name, v,item['category'])) 259 else: 260 if v._category != item['category']: 261 raise GangaAttributeError('%s: attempt to assign an incompatible object %s to the property in category "%s"' %(self._name, v,item['category'])) 262 v = v.clone() 263 v._setParent(obj) 264 return v
265 266 item = obj._schema[self._name] 267 268 if item.isA(Schema.ComponentItem): 269 if item['sequence']: 270 ## checklist=filter(lambda x: not implies(x is None,item['optional']) or x._category != item['category'],val) 271 ## if len(checklist) > 0: 272 ## raise AttributeError('%s: attempt to assign incompatible objects %s to the property in category "%s"'%(self._name, str(checklist),item['category'])) 273 val = makeGangaList(val,cloneVal, parent = obj) 274 else: 275 val = cloneVal(val) 276 277 ## if val is None: 278 ## assert(item['optional']) 279 ## else: 280 ## assert(isinstance(val, Node)) 281 ## if val._category != item['category']: 282 ## raise AttributeError('%s: attempt to assign an incompatible object %s to the property in category "%s"' %(self._name, val,item['category'])) 283 ## val = cloneVal(val) 284 else: 285 if item['sequence']: 286 val = makeGangaList(val, parent = obj) 287 288 obj._data[self._name] = val 289 290 obj._setDirty()
291 292
293 - def __delete__(self, obj):
294 #self._check_getter() 295 del obj._data[self._name]
296 297
298 -class ObjectMetaclass(type):
299 _descriptor = Descriptor
300 - def __init__(cls, name, bases, dict):
301 super(ObjectMetaclass, cls).__init__(name, bases, dict) 302 303 # ignore the 'abstract' base class 304 # FIXME: this mechanism should be based on explicit cls._name or alike 305 if name == 'GangaObject': 306 return 307 308 logger.debug("Metaclass.__init__: class %s name %s bases %s",cls,name,bases) 309 310 # all Ganga classes must have (even empty) schema 311 assert(not cls._schema is None) 312 313 # produce a GPI class (proxy) 314 proxyClass = GPIProxyClassFactory(name,cls) 315 316 # export public methods of this class and also of all the bases 317 # this class is scanned last to extract the most up-to-date docstring 318 dictlist = [b.__dict__ for b in cls.__mro__] 319 for di in range(0, len(dictlist)): 320 d = dictlist[len(dictlist)-1-di] 321 for k in d: 322 if k in cls._exportmethods: 323 try: 324 internal_name = "_export_"+k 325 method = d[internal_name] 326 except KeyError: 327 internal_name = k 328 method = d[k] 329 if not (type(method) == types.FunctionType): 330 continue 331 f = ProxyMethodDescriptor(k,internal_name) 332 f.__doc__ = method.__doc__ 333 setattr(proxyClass, k, f) 334 335 # sanity checks for schema... 336 if not '_schema' in dict.keys(): 337 s = "Class %s must _schema (it cannot be silently inherited)" % (name,) 338 logger.error(s) 339 raise ValueError(s) 340 341 if not cls._schema._pluginclass is None: 342 logger.warning('Possible schema clash in class %s between %s and %s',name,cls._name,cls._schema._pluginclass._name) 343 344 # export visible properties... do not export hidden properties 345 for attr, item in cls._schema.allItems(): 346 setattr(cls, attr, cls._descriptor(attr, item)) 347 if not item['hidden']: 348 setattr(proxyClass, attr, ProxyDataDescriptor(attr)) 349 350 # additional check of type 351 # bugfix #40220: Ensure that default values satisfy the declared types in the schema 352 for attr, item in cls._schema.simpleItems(): 353 if not item['getter']: 354 item._check_type(item['defvalue'],'.'.join([name,attr]),enableGangaList=False) 355 356 # create reference in schema to the pluginclass 357 cls._schema._pluginclass = cls 358 359 # store generated proxy class 360 cls._proxyClass = proxyClass 361 362 # register plugin class 363 if not cls._declared_property('hidden') or cls._declared_property('enable_plugin'): 364 allPlugins.add(cls,cls._category,cls._name) 365 366 # create a configuration unit for default values of object properties 367 if not cls._declared_property('hidden') or cls._declared_property('enable_config'): 368 cls._schema.createDefaultConfig()
369 370
371 -class GangaObject(Node):
372 __metaclass__ = ObjectMetaclass 373 _schema = None # obligatory, specified in the derived classes 374 _proxyClass = None # created automatically 375 _registry = None # automatically set for Root objects 376 _exportmethods= [] # optional, specified in the derived classes 377 378 # by default classes are not hidden, config generation and plugin registration is enabled 379 _hidden = 1 # optional, specify in the class if you do not want to export it publicly in GPI, 380 # the class will not be registered as a plugin unless _enable_plugin is defined 381 # the test if the class is hidden is performed by x._declared_property('hidden') 382 # which makes sure that _hidden must be *explicitly* declared, not inherited 383 384 # additional properties that may be set in derived classes which were declared as _hidden: 385 # _enable_plugin = 1 -> allow registration of _hidden classes in the allPlugins dictionary 386 # _enable_config = 1 -> allow generation of [default_X] configuration section with schema properties 387 388 # the constructor is directly used by the GPI proxy so the GangaObject must be fully initialized
389 - def __init__(self):
390 # IMPORTANT: if you add instance attributes like in the line below 391 # make sure to update the __getstate__ method as well 392 self._proxyObject = None # use cache to help preserve proxy objects identity in GPI 393 self._dirty = False # dirty flag is true if the object has been modified locally and its contents is out-of-sync with its repository 394 395 super(GangaObject, self).__init__(None) 396 for attr, item in self._schema.allItems(): 397 setattr(self, attr, self._schema.getDefaultValue(attr))
398 399 # Overwrite default values with any config values specified 400 #self.setPropertiesFromConfig() 401 402 # construct an object of this type from the arguments. Defaults to copy constructor.
403 - def __construct__(self,args):
404 # act as a copy constructor applying the object conversion at the same time (if applicable) 405 if len(args) == 0: 406 return 407 elif len(args) == 1: 408 self.copyFrom(args[0]) 409 else: 410 raise TypeMismatchError("Constructor expected one or zero non-keyword arguments, got %i" % len(args))
411
412 - def __getstate__(self):
413 # IMPORTANT: keep this in sync with the __init__ 414 self._getReadAccess() 415 dict = super(GangaObject, self).__getstate__() 416 dict['_proxyObject'] = None 417 dict['_dirty'] = False 418 return dict
419
420 - def __setstate__(self, dict):
421 self._getWriteAccess() 422 super(GangaObject, self).__setstate__(dict) 423 self._setParent(None) 424 self._proxyObject = None 425 self._dirty = False
426 427 # on the deepcopy reset all non-copyable properties as defined in the schema
428 - def __deepcopy__(self, memo = None):
429 self._getReadAccess() 430 c = super(GangaObject,self).__deepcopy__(memo) 431 for name,item in self._schema.allItems(): 432 if not item['copyable']: 433 setattr(c,name,self._schema.getDefaultValue(name)) 434 return c
435
436 - def accept(self, visitor):
437 self._getReadAccess() 438 super(GangaObject, self).accept(visitor)
439
440 - def _getWriteAccess(self):
441 """ tries to get write access to the object. 442 Raise LockingError (or so) on fail """ 443 root = self._getRoot() 444 reg = root._getRegistry() 445 if reg is not None: 446 reg._write_access(root)
447
448 - def _releaseWriteAccess(self):
449 """ releases write access to the object. 450 Raise LockingError (or so) on fail 451 Please use only if the object is expected to be used by other sessions""" 452 root = self._getRoot() 453 reg = root._getRegistry() 454 if reg is not None: 455 reg._release_lock(root)
456
457 - def _getReadAccess(self):
458 """ makes sure the objects _data is there and the object itself has a recent state. 459 Raise RepositoryError""" 460 root = self._getRoot() 461 reg = root._getRegistry() 462 if reg is not None: 463 reg._read_access(root,self)
464 #print "excepting because of access to ", self._name 465 #import traceback 466 #traceback.print_stack() 467 #raise Exception(self._name) 468 469 # define when the object is read-only (for example a job is read-only in the states other than new)
470 - def _readonly(self):
471 r = self._getRoot() 472 # is object a root for itself? check needed otherwise infinite recursion 473 if r is None or r is self: return 0 474 else: 475 return r._readonly()
476 477 # set the registry for this object (assumes this object is a root object)
478 - def _setRegistry(self, registry):
479 assert self._getParent() is None 480 self._registry = registry
481 482 # get the registry for the object by getting the registry associated with the root object (if any)
483 - def _getRegistry(self):
484 r = self._getRoot() 485 try: 486 return r._registry 487 except AttributeError: 488 return None
489
490 - def _getRegistryID(self):
491 try: 492 return self._registry.find(self) 493 except AttributeError: 494 return None
495 496 497 # mark object as "dirty" and inform the registry about it 498 # the registry is always associated with the root object
499 - def _setDirty(self, dummy=1):
500 self._dirty = True 501 parent = self._getParent() 502 if parent is not None: 503 parent._setDirty() 504 if self._registry is not None: 505 self._registry._dirty(self)
506
507 - def _setFlushed(self):
508 self._dirty = False
509 510 # post __init__ hook automatically called by GPI Proxy __init__
511 - def _auto__init__(self):
512 pass
513 514 515 516 # return True if _name attribute was explicitly defined in the class 517 # this means that implicit (inherited) _name attribute has no effect in the derived class 518 # example: cls._declared_property('hidden') => True if there is class attribute _hidden explicitly declared
519 - def _declared_property(self,name):
520 return '_'+name in self.__dict__
521 522 _declared_property = classmethod(_declared_property) 523 524 # get the job object associated with self or raise an assertion error 525 # the FIRST PARENT Job is returned... 526 # this method is for convenience and may well be moved to some subclass
527 - def getJobObject(self):
528 from Ganga.GPIDev.Lib.Job import Job 529 r = self._getRoot(cond=lambda o: isinstance(o,Job)) 530 if not isinstance(r,Job): 531 raise AssertionError('no job associated with object '+repr(self)) 532 return r
533 534 # Customization of the GPI attribute assignment: Attribute Filters 535 # 536 # Example of usage: 537 # if some properties depend on the value of other properties in a complex way such as: 538 # changing platform of Gaudi should change the version if it is not supported... etc. 539 # 540 # Semantics: 541 # gpi_proxy.x = v --> gpi_proxy._impl._attribute_filter__set__('x',v) 542 # gpi_proxy.y = [v1,v2] --> gpi_proxy._impl._attribute_filter__set__('x',[v1,v2]) 543 # 544 # is used for *all* kinds of attributes (component and simple) 545 # 546 # Attribute Filters are used mainly for side effects such as modification of the state of the self object 547 # (as described above). 548 # 549 # Attribute Filter may also perform an additional conversion of the value which is being assigned. 550 # 551 # Returns the attribute value (converted or original) 552 #
553 - def _attribute_filter__set__(self,name,v):
554 return v
555 556 # define the default component object filter: 557 # obj.x = "Y" <=> obj.x = Y() 558
559 -def string_type_shortcut_filter(val,item):
560 if type(val) is type(''): 561 if item is None: 562 raise ValueError('cannot apply default string conversion, probably you are trying to use it in the constructor') 563 from Ganga.Utility.Plugin import allPlugins, PluginManagerError 564 try: 565 obj = allPlugins.find(item['category'],val)() 566 obj._auto__init__() 567 return obj 568 except PluginManagerError,x: 569 raise ValueError(x) 570 return None
571 572 # FIXME: change into classmethod (do they inherit?) and then change stripComponentObject to use class instead of 573 # FIXME: object (object model clearly fails with sequence of Files) 574 # FIXME: test: ../bin/ganga -c local_lhcb.ini run.py TestNativeSpecific.testFileSequence 575 576 577 from Filters import allComponentFilters 578 allComponentFilters.setDefault(string_type_shortcut_filter) 579 580 # 581 # 582 # $Log: not supported by cvs2svn $ 583 # Revision 1.5.2.9 2009/07/14 14:44:17 ebke 584 # * several bugfixes 585 # * changed indexing for XML/Pickle 586 # * introduce index update minimal time of 20 seconds (reduces lag for typing 'jobs') 587 # * subjob splitting and individual flushing for XML/Pickle 588 # 589 # Revision 1.5.2.8 2009/07/13 22:10:53 ebke 590 # Update for the new GangaRepository: 591 # * Moved dict interface from Repository to Registry 592 # * Clearly specified Exceptions to be raised by Repository 593 # * proper exception handling in Registry 594 # * moved _writable to _getWriteAccess, introduce _getReadAccess 595 # * clarified locking, logic in Registry, less in Repository 596 # * index reading support in XML (no writing, though..) 597 # * general index reading on registry.keys() 598 # 599 # Revision 1.5.2.7 2009/07/10 12:14:10 ebke 600 # Fixed wrong sequence in __set__: only dirty _after_ writing! 601 # 602 # Revision 1.5.2.6 2009/07/10 11:33:06 ebke 603 # Preparations and fixes for lazy loading 604 # 605 # Revision 1.5.2.5 2009/07/08 15:27:50 ebke 606 # Removed load speed bottleneck for pickle - reduced __setstate__ time by factor 3. 607 # 608 # Revision 1.5.2.4 2009/07/08 12:51:52 ebke 609 # Fixes some bugs introduced in the latest version 610 # 611 # Revision 1.5.2.3 2009/07/08 12:36:54 ebke 612 # Simplified _writable 613 # 614 # Revision 1.5.2.2 2009/07/08 11:18:21 ebke 615 # Initial commit of all - mostly small - modifications due to the new GangaRepository. 616 # No interface visible to the user is changed 617 # 618 # Revision 1.5.2.1 2009/06/04 12:00:37 moscicki 619 # *** empty log message *** 620 # 621 # Revision 1.5 2009/05/20 13:40:22 moscicki 622 # added filter property for GangaObjects 623 # 624 # added Utility.Config.expandgangasystemvars() filter which expands @{VAR} in strings, where VAR is a configuration option defined in the System section 625 # Usage example: specify @{GANGA_PYTHONPATH} in the configuration file to make pathnames relative to the location of Ganga release; specify @{GANGA_VERSION} to expand to current Ganga version. etc. 626 # 627 # modified credentials package (ICommandSet) to use the expandgangasystemvars() filter. 628 # 629 # Revision 1.4 2009/04/27 09:22:56 moscicki 630 # fix #29745: use __mro__ rather than first-generation of base classes 631 # 632 # Revision 1.3 2009/02/24 14:57:56 moscicki 633 # set parent correctly for GangaList items (in __setstate__) 634 # 635 # Revision 1.2 2008/09/09 14:37:16 moscicki 636 # bugfix #40220: Ensure that default values satisfy the declared types in the schema 637 # 638 # factored out type checking into schema module, fixed a number of wrongly declared schema items in the core 639 # 640 # Revision 1.1 2008/07/17 16:40:52 moscicki 641 # migration of 5.0.2 to HEAD 642 # 643 # the doc and release/tools have been taken from HEAD 644 # 645 # Revision 1.27.4.10 2008/03/31 15:30:26 kubam 646 # More flexible internal logic of hiding the plugin classes derived from GangaObject: 647 # 648 # # by default classes are not hidden, config generation and plugin registration is enabled 649 # 650 # _hidden = 1 # optional, specify in the class if you do not want to export it publicly in GPI, 651 # # the class will not be registered as a plugin unless _enable_plugin is defined 652 # # the test if the class is hidden is performed by x._declared_property('hidden') 653 # 654 # # additional properties that may be set in derived classes which were declared as _hidden: 655 # # _enable_plugin = 1 -> allow registration of _hidden classes in the allPlugins dictionary 656 # # _enable_config = 1 -> allow generation of [default_X] configuration section with schema properties 657 # 658 # This fixes: bug #34470: config [defaults_GridProxy] missing (issue of _hidden property of GangaObject) 659 # 660 # Revision 1.27.4.9 2008/02/28 15:44:31 moscicki 661 # fixed set parent problem for GangaList (and removed Will's hack which was already commented out) 662 # 663 # Revision 1.27.4.8 2008/02/12 09:25:24 amuraru 664 # removed Will's hack to set the parent, it causes side effects in subjobs accessor(to be checked) 665 # 666 # Revision 1.27.4.7 2008/02/06 17:02:00 moscicki 667 # small fix 668 # 669 # Revision 1.27.4.6 2008/02/06 13:00:21 wreece 670 # Adds a bit of a HACK as a tempory measure. The parent of a GangaList is being lost somewhere (I suspect due to a copy). I've added it back manually in __get__. 671 # 672 # Revision 1.27.4.5 2008/02/06 09:28:48 wreece 673 # 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. 674 # 675 # Revision 1.27.4.4 2007/12/18 09:05:04 moscicki 676 # integrated typesystem from Alvin and made more uniform error reporting 677 # 678 # Revision 1.27.4.3 2007/11/14 13:03:54 wreece 679 # Changes to make shortcuts work correctly with gangalists. all but one tests should now pass. 680 # 681 # Revision 1.27.4.2 2007/11/07 15:10:02 moscicki 682 # merged in pretty print and GangaList support from ganga-5-dev-branch-4-4-1-will-print branch 683 # 684 # 685 # Revision 1.27.4.1 2007/10/30 15:25:53 moscicki 686 # fixed #29745: Inherited functions of GangaObjects cannot be exported via _exportmethods 687 # 688 # Revision 1.27.8.3 2007/10/30 21:22:02 wreece 689 # Numerous small fixes and work arounds. And a new test. 690 # 691 # Revision 1.27.8.2 2007/10/30 14:30:23 wreece 692 # 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. 693 # 694 # Revision 1.27.8.1 2007/10/30 12:12:08 wreece 695 # First version of the new print_summary functionality. Lots of changes, but some known limitations. Will address in next version. 696 # 697 # Revision 1.27 2007/07/27 13:52:00 moscicki 698 # merger updates from Will (from GangaMergers-1-0 branch) 699 # 700 # Revision 1.26.12.1 2007/05/14 13:32:11 wreece 701 # Adds the merger related code on a seperate branch. All tests currently 702 # run successfully. 703 # 704 # Revision 1.26 2006/07/27 20:09:54 moscicki 705 # _getJobObject() renamed -> getJobObject() and finding FIRST PARENT JOB 706 # _getRoot() : cond optional argument (to cut the search path e.g. for getJobObject()) 707 # 708 # getDefaultValue() moved to Schema object 709 # 710 # "checkset" metaproperty implemented in schema (to check the direct updates to job.status) 711 # modified the "getter" metaproperty implementation 712 # create automatically the configuration units with default property values 713 # 714 # Revision 1.25 2006/02/10 14:18:44 moscicki 715 # removed obsoleted eval for default properties from config file 716 # 717 # Revision 1.24 2006/01/09 16:36:55 moscicki 718 # - support for defining default properties in the configuration 719 # config file example: 720 # 721 # [LSF_Properties] 722 # queue = myQueue 723 # 724 # [LCG_Properties] 725 # requirements.CE = myCE 726 # 727 # [Job_Properties] 728 # application = DaVinci 729 # application.version = v99r2 730 # 731 # Revision 1.23 2005/12/02 15:27:13 moscicki 732 # support for "visitable" metaproperty 733 # support for hidden GPI classes 734 # "hidden" properties not visible in the proxies 735 # support for 'getter' type of property (a binding) for job.master 736 # 737 # Revision 1.22 2005/11/14 10:29:55 moscicki 738 # adapted to changed interface of allPlugins.add() method 739 # 740 # Revision 1.21 2005/11/01 16:43:51 moscicki 741 # added isStringLike condition to avoid unnecesary looping over strings 742 # 743 # Revision 1.20 2005/11/01 14:04:55 moscicki 744 # added missing implementation of GangaObject.__setstate__ 745 # fixed the implementation of Node.__setstate__ to correctly set parent for objects which are contained in iterable simple items (lists, dictionaries) etc. (contributed by AS) 746 # 747 # Revision 1.19 2005/11/01 11:09:48 moscicki 748 # changes to support import/export (KH): 749 # - The printTree method accepts an additional argument, which 750 # it passes on to VPrinter as the value for "selection". 751 # 752 # Revision 1.18 2005/08/26 09:53:24 moscicki 753 # copy __doc__ for exported method 754 # _getJobObject() helper method in GangaObject 755 # 756 # Revision 1.17 2005/08/24 15:41:19 moscicki 757 # automatically generated help for properties, disabled the SchemaHelper and few other improvements to the help system 758 # 759 # Revision 1.16 2005/08/23 17:15:06 moscicki 760 # *** empty log message *** 761 # 762 # 763 # 764