Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-05-16 00:57:56

0001 from __future__ import print_function
0002 from builtins import range, object
0003 import inspect
0004 
0005 class _ConfigureComponent(object):
0006     """Denotes a class that can be used by the Processes class"""
0007     def _isTaskComponent(self):
0008         return False
0009 
0010 class PrintOptions(object):
0011     def __init__(self, indent = 0, deltaIndent = 4, process = True, targetDirectory = None, useSubdirectories = False):
0012         self.indent_= indent
0013         self.deltaIndent_ = deltaIndent
0014         self.isCfg = process
0015         self.targetDirectory = targetDirectory
0016         self.useSubdirectories = useSubdirectories
0017     def indentation(self):
0018         return ' '*self.indent_
0019     def indent(self):
0020         self.indent_ += self.deltaIndent_
0021     def unindent(self):
0022         self.indent_ -= self.deltaIndent_
0023 
0024 class _SpecialImportRegistry(object):
0025     """This class collects special import statements of configuration types"""
0026     def __init__(self):
0027         self._registry = {}
0028 
0029     def _reset(self):
0030         for lst in self._registry.values():
0031             lst[1] = False
0032 
0033     def registerSpecialImportForType(self, cls, impStatement):
0034         className = cls.__name__
0035         if className in self._registry:
0036             raise RuntimeError("Error: the configuration type '%s' already has an import statement registered '%s'" % (className, self._registry[className][0]))
0037         self._registry[className] = [impStatement, False]
0038 
0039     def registerUse(self, obj):
0040         className = obj.__class__.__name__
0041         try:
0042             self._registry[className][1] = True
0043         except KeyError:
0044             pass
0045 
0046     def getSpecialImports(self):
0047         coll = set()
0048         for (imp, used) in self._registry.values():
0049             if used:
0050                 coll.add(imp)
0051         return sorted(coll)
0052 
0053 specialImportRegistry = _SpecialImportRegistry()
0054 
0055 class _ParameterTypeBase(object):
0056     """base class for classes which are used as the 'parameters' for a ParameterSet"""
0057     def __init__(self):
0058         self.__dict__["_isFrozen"] = False
0059         self.__isTracked = True
0060         self._isModified = False
0061     def isModified(self):
0062         return self._isModified
0063     def resetModified(self):
0064         self._isModified=False
0065     def configTypeName(self):
0066         if self.isTracked():
0067             return type(self).__name__
0068         return 'untracked '+type(self).__name__
0069     def pythonTypeName(self):
0070         if self.isTracked():
0071             return 'cms.'+type(self).__name__
0072         return 'cms.untracked.'+type(self).__name__
0073     def dumpPython(self, options=PrintOptions()):
0074         specialImportRegistry.registerUse(self)
0075         return self.pythonTypeName()+"("+self.pythonValue(options)+")"
0076     def __repr__(self):
0077         return self.dumpPython()
0078     def isTracked(self):
0079         return self.__isTracked
0080     def setIsTracked(self,trackness):
0081         self.__isTracked = trackness
0082     def isFrozen(self):
0083         return self._isFrozen 
0084     def setIsFrozen(self):
0085         self._isFrozen = True
0086     def isCompatibleCMSType(self,aType):
0087         return isinstance(self,aType)
0088     def _checkAndReturnValueWithType(self, valueWithType):
0089         if isinstance(valueWithType, type(self)):
0090             return valueWithType
0091         raise TypeError("Attempted to assign type {from_} to type {to}".format(from_ = str(type(valueWithType)), to = str(type(self))) )
0092 
0093  
0094 class _SimpleParameterTypeBase(_ParameterTypeBase):
0095     """base class for parameter classes which only hold a single value"""
0096     def __init__(self,value):
0097         super(_SimpleParameterTypeBase,self).__init__()
0098         self._value = value
0099         if not self._isValid(value):
0100             raise ValueError(str(value)+" is not a valid "+str(type(self)))
0101     def value(self):
0102         return self._value
0103     def setValue(self,value):
0104         if not self._isValid(value):
0105             raise ValueError(str(value)+" is not a valid "+str(type(self)))
0106         if value!=self._value:
0107             self._isModified=True
0108             self._value=value
0109     def configValue(self, options=PrintOptions()):
0110         return str(self._value)
0111     def pythonValue(self, options=PrintOptions()):
0112         return self.configValue(options)
0113     def __eq__(self,other):
0114         if isinstance(other,_SimpleParameterTypeBase):
0115             return self._value == other._value
0116         return self._value == other
0117     def __ne__(self,other):
0118         if isinstance(other,_SimpleParameterTypeBase):
0119             return self._value != other._value
0120         return self._value != other
0121     def __lt__(self,other):
0122         if isinstance(other,_SimpleParameterTypeBase):
0123             return self._value < other._value
0124         return self._value < other
0125     def __le__(self,other):
0126         if isinstance(other,_SimpleParameterTypeBase):
0127             return self._value <= other._value
0128         return self._value <= other
0129     def __gt__(self,other):
0130         if isinstance(other,_SimpleParameterTypeBase):
0131             return self._value > other._value
0132         return self._value > other
0133     def __ge__(self,other):
0134         if isinstance(other,_SimpleParameterTypeBase):
0135             return self._value >= other._value
0136         return self._value >= other
0137 
0138 
0139 class UsingBlock(_SimpleParameterTypeBase):
0140     """For injection purposes, pretend this is a new parameter type
0141        then have a post process step which strips these out
0142     """
0143     def __init__(self,value, s='', loc=0, file=''):
0144         super(UsingBlock,self).__init__(value)
0145         self.s = s
0146         self.loc = loc
0147         self.file = file
0148         self.isResolved = False
0149     @staticmethod
0150     def _isValid(value):
0151         return isinstance(value,str)
0152     def _valueFromString(value):
0153         """only used for cfg-parsing"""
0154         return string(value)
0155     def insertInto(self, parameterSet, myname):
0156         value = self.value()
0157         #  doesn't seem to handle \0 correctly
0158         #if value == '\0':
0159         #    value = ''
0160         parameterSet.addString(self.isTracked(), myname, value)
0161     def dumpPython(self, options=PrintOptions()):
0162         if options.isCfg:
0163             return "process."+self.value()
0164         else:
0165             return self.value()
0166 
0167 
0168 class _Parameterizable(object):
0169     """Base class for classes which allow addition of _ParameterTypeBase data"""
0170     def __init__(self,*arg,**kargs):
0171         self.__dict__['_Parameterizable__parameterNames'] = []
0172         self.__dict__["_isFrozen"] = False
0173         self.__dict__['_Parameterizable__validator'] = None
0174         """The named arguments are the 'parameters' which are added as 'python attributes' to the object"""
0175         if len(arg) != 0:
0176             #raise ValueError("unnamed arguments are not allowed. Please use the syntax 'name = value' when assigning arguments.")
0177             for block in arg:
0178                 # Allow __PSet for testing
0179                 if type(block).__name__ not in ["PSet", "__PSet"]:
0180                     raise ValueError("Only PSets can be passed as unnamed argument blocks.  This is a "+type(block).__name__)
0181                 self.__setParameters(block.parameters_())
0182         self.__setParameters(kargs)
0183         self._isModified = False
0184         
0185     def parameterNames_(self):
0186         """Returns the name of the parameters"""
0187         return self.__parameterNames[:]
0188     def isModified(self):
0189         if self._isModified:
0190             return True
0191         for name in self.parameterNames_():
0192             param = self.__dict__[name]
0193             if isinstance(param, _Parameterizable) and param.isModified():
0194                 self._isModified = True
0195                 return True
0196         return False
0197 
0198     def hasParameter(self, params):
0199         """
0200         _hasParameter_
0201 
0202         check that pset provided has the attribute chain
0203         specified.
0204 
0205         Eg, if params is [ 'attr1', 'attr2', 'attr3' ]
0206         check for pset.attr1.attr2.attr3
0207 
0208         returns True if parameter exists, False if not
0209         """
0210         return (self.getParameter(params) != None)
0211 
0212     def getParameter(self, params):
0213         """
0214         _getParameter_
0215 
0216         Retrieve the specified parameter from the PSet Provided
0217         given the attribute chain
0218 
0219         returns None if not found
0220         """
0221         lastParam = self
0222         # Don't accidentally iterate over letters in a string
0223         if type(params).__name__ == 'str':
0224             return getattr(self, params, None)
0225         for param in params:
0226             lastParam = getattr(lastParam, param, None)
0227             if lastParam == None:
0228                 return None
0229         return lastParam
0230 
0231     def parameters_(self):
0232         """Returns a dictionary of copies of the user-set parameters"""
0233         import copy
0234         result = dict()
0235         for name in self.parameterNames_():
0236                result[name]=copy.deepcopy(self.__dict__[name])
0237         return result
0238 
0239     def __addParameter(self, name, value):
0240         if name == 'allowAnyLabel_':
0241             self.__validator = value
0242             self._isModified = True
0243             return
0244         if not isinstance(value,_ParameterTypeBase):
0245             if self.__validator is not None:
0246                 value = self.__validator.convert_(value)
0247             else:
0248                 self.__raiseBadSetAttr(name)
0249         if name in self.__dict__:
0250             message = "Duplicate insert of member " + name
0251             message += "\nThe original parameters are:\n"
0252             message += self.dumpPython() + '\n'
0253             raise ValueError(message)
0254         self.__dict__[name]=value
0255         self.__parameterNames.append(name)
0256         self._isModified = True
0257 
0258     def __setParameters(self,parameters):
0259         v = None
0260         for name,value in parameters.items():
0261             if name == 'allowAnyLabel_':
0262                 v = value
0263                 continue
0264             self.__addParameter(name, value)
0265         if v is not None:
0266             self.__validator=v
0267     def __setattr__(self,name,value):
0268         #since labels are not supposed to have underscores at the beginning
0269         # I will assume that if we have such then we are setting an internal variable
0270         if self.isFrozen() and not (name in ["_Labelable__label","_isFrozen"] or name.startswith('_')): 
0271             message = "Object already added to a process. It is read only now\n"
0272             message +=  "    %s = %s" %(name, value)
0273             message += "\nThe original parameters are:\n"
0274             message += self.dumpPython() + '\n'           
0275             raise ValueError(message)
0276         # underscored names bypass checking for _ParameterTypeBase
0277         if name[0]=='_':
0278             super(_Parameterizable,self).__setattr__(name,value)
0279         elif not name in self.__dict__:
0280             self.__addParameter(name, value)
0281             self._isModified = True
0282         else:
0283             # handle the case where users just replace with a value, a = 12, rather than a = cms.int32(12)
0284             if isinstance(value,_ParameterTypeBase):
0285                 self.__dict__[name] = self.__dict__[name]._checkAndReturnValueWithType(value)
0286             else:
0287                 self.__dict__[name].setValue(value)
0288             self._isModified = True
0289 
0290     def isFrozen(self):
0291         return self._isFrozen
0292     def setIsFrozen(self):
0293         self._isFrozen = True
0294         for name in self.parameterNames_():
0295             self.__dict__[name].setIsFrozen() 
0296     def __delattr__(self,name):
0297         if self.isFrozen():
0298             raise ValueError("Object already added to a process. It is read only now")
0299         super(_Parameterizable,self).__delattr__(name)
0300         self.__parameterNames.remove(name)
0301     @staticmethod
0302     def __raiseBadSetAttr(name):
0303         raise TypeError(name+" does not already exist, so it can only be set to a CMS python configuration type")
0304     def dumpPython(self, options=PrintOptions()):
0305         specialImportRegistry.registerUse(self)
0306         sortedNames = sorted(self.parameterNames_())
0307         if len(sortedNames) > 200:
0308         #Too many parameters for a python function call
0309         # The solution is to create a temporary dictionary which
0310         # is constructed by concatenating long lists (with maximum
0311         # 200 entries each) together.
0312         # This looks like
0313         #  **dict( [(...,...), ...] + [...] + ... )
0314             others = []
0315             usings = []
0316             for name in sortedNames:
0317                 param = self.__dict__[name]
0318                 # we don't want minuses in names
0319                 name2 = name.replace('-','_')
0320                 options.indent()
0321                 #_UsingNodes don't get assigned variables
0322                 if name.startswith("using_"):
0323                     usings.append(options.indentation()+param.dumpPython(options))
0324                 else:
0325                     others.append((name2, param.dumpPython(options)))
0326                 options.unindent()
0327 
0328             resultList = ',\n'.join(usings)
0329             longOthers = options.indentation()+"**dict(\n"
0330             options.indent()
0331             longOthers += options.indentation()+"[\n"
0332             entriesInList = 0
0333             options.indent()
0334             for n,v in others:
0335                 entriesInList +=1
0336                 if entriesInList > 200:
0337                     #need to start a new list
0338                     options.unindent()
0339                     longOthers += options.indentation()+"] +\n"+options.indentation()+"[\n"
0340                     entriesInList = 0
0341                     options.indent()
0342                 longOthers += options.indentation()+'("'+n+'" , '+v+' ),\n'
0343             
0344             longOthers += options.indentation()+"]\n"
0345             options.unindent()
0346             longOthers +=options.indentation()+")\n"
0347             options.unindent()
0348             ret = []
0349             if resultList:
0350                 ret.append(resultList)
0351             if longOthers:
0352                 ret.append(longOthers)
0353             return ",\n".join(ret)
0354         #Standard case, small number of parameters
0355         others = []
0356         usings = []
0357         for name in sortedNames:
0358             param = self.__dict__[name]
0359             # we don't want minuses in names
0360             name2 = name.replace('-','_')
0361             options.indent()
0362             #_UsingNodes don't get assigned variables
0363             if name.startswith("using_"):
0364                 usings.append(options.indentation()+param.dumpPython(options))
0365             else:
0366                 others.append(options.indentation()+name2+' = '+param.dumpPython(options))
0367             options.unindent()
0368         # usings need to go first
0369         resultList = usings
0370         resultList.extend(others)
0371         if self.__validator is not None:
0372             options.indent()
0373             resultList.append(options.indentation()+"allowAnyLabel_="+self.__validator.dumpPython(options))
0374             options.unindent()
0375         return ',\n'.join(resultList)+'\n'
0376     def __repr__(self):
0377         return self.dumpPython()
0378     def insertContentsInto(self, parameterSet):
0379         for name in self.parameterNames_():
0380             param = getattr(self,name)
0381             param.insertInto(parameterSet, name)
0382 
0383 
0384 class _TypedParameterizable(_Parameterizable):
0385     """Base class for classes which are Parameterizable and have a 'type' assigned"""
0386     def __init__(self,type_,*arg,**kargs):
0387         self.__dict__['_TypedParameterizable__type'] = type_
0388         #the 'type' is also placed in the 'arg' list and we need to remove it
0389         #if 'type_' not in kargs:
0390         #    arg = arg[1:]
0391         #else:
0392         #    del args['type_']
0393         super(_TypedParameterizable,self).__init__(*arg,**kargs)
0394         saveOrigin(self, 1) 
0395     def _place(self,name,proc):
0396         self._placeImpl(name,proc)
0397     def type_(self):
0398         """returns the type of the object, e.g. 'FooProducer'"""
0399         return self.__type
0400     def copy(self):
0401         returnValue =_TypedParameterizable.__new__(type(self))
0402         params = self.parameters_()
0403         returnValue.__init__(self.__type,**params)
0404         returnValue._isModified = self._isModified
0405         return returnValue
0406     def clone(self, *args, **params):
0407         """Copies the object and allows one to modify the parameters of the clone.
0408         New parameters may be added by specify the exact type
0409         Modifying existing parameters can be done by just specifying the new
0410           value without having to specify the type.
0411         A parameter may be removed from the clone using the value None.
0412            #remove the parameter foo.fred
0413            mod.toModify(foo, fred = None)
0414         A parameter embedded within a PSet may be changed via a dictionary
0415            #change foo.fred.pebbles to 3 and foo.fred.friend to "barney"
0416            mod.toModify(foo, fred = dict(pebbles = 3, friend = "barney)) )
0417         """
0418         returnValue =_TypedParameterizable.__new__(type(self))
0419         myparams = self.parameters_()
0420 
0421         # Prefer parameters given in PSet blocks over those in clone-from module
0422         for block in args:
0423             # Allow __PSet for testing
0424             if type(block).__name__ not in ["PSet", "__PSet"]:
0425                 raise ValueError("Only PSets can be passed as unnamed argument blocks.  This is a "+type(block).__name__)
0426             for name in block.parameterNames_():
0427                 try:
0428                     del myparams[name]
0429                 except KeyError:
0430                     pass
0431 
0432         _modifyParametersFromDict(myparams, params, self._Parameterizable__raiseBadSetAttr)
0433         if self._Parameterizable__validator is not None:
0434             myparams["allowAnyLabel_"] = self._Parameterizable__validator
0435 
0436         returnValue.__init__(self.__type,*args,
0437                              **myparams)
0438         returnValue._isModified = False
0439         returnValue._isFrozen = False
0440         saveOrigin(returnValue, 1)
0441         return returnValue
0442 
0443     @staticmethod
0444     def __findDefaultsFor(label,type):
0445         #This routine is no longer used, but I might revive it in the future
0446         import sys
0447         import glob
0448         choices = list()
0449         for d in sys.path:
0450             choices.extend(glob.glob(d+'/*/*/'+label+'.py'))
0451         if not choices:
0452             return None
0453         #now see if any of them have what we want
0454         #the use of __import__ is taken from an example
0455         # from the www.python.org documentation on __import__
0456         for c in choices:
0457             #print " found file "+c
0458             name='.'.join(c[:-3].split('/')[-3:])
0459             #name = c[:-3].replace('/','.')
0460             mod = __import__(name)
0461             components = name.split('.')
0462             for comp in components[1:]:
0463                 mod = getattr(mod,comp)
0464             if hasattr(mod,label):
0465                 default = getattr(mod,label)
0466                 if isinstance(default,_TypedParameterizable):
0467                     if(default.type_() == type):
0468                         params = dict()
0469                         for name in default.parameterNames_():
0470                             params[name] = getattr(default,name)
0471                         return params
0472         return None
0473 
0474     def directDependencies(self):
0475         return []
0476     
0477     def dumpConfig(self, options=PrintOptions()):
0478         config = self.__type +' { \n'
0479         for name in self.parameterNames_():
0480             param = self.__dict__[name]
0481             options.indent()
0482             config+=options.indentation()+param.configTypeName()+' '+name+' = '+param.configValue(options)+'\n'
0483             options.unindent()
0484         config += options.indentation()+'}\n'
0485         return config
0486 
0487     def dumpPython(self, options=PrintOptions()):
0488         specialImportRegistry.registerUse(self)
0489         result = "cms."+str(type(self).__name__)+'("'+self.type_()+'"'
0490         nparam = len(self.parameterNames_())
0491         if nparam == 0:
0492             result += ")\n"
0493         else:
0494             result += ",\n"+_Parameterizable.dumpPython(self,options)+options.indentation() + ")\n"
0495         return result
0496 
0497     def dumpPythonAttributes(self, myname, options):
0498         """ dumps the object with all attributes declared after the constructor"""
0499         result = ""
0500         for name in sorted(self.parameterNames_()):
0501             param = self.__dict__[name]
0502             result += options.indentation() + myname + "." + name + " = " + param.dumpPython(options) + "\n"
0503         return result
0504 
0505     def nameInProcessDesc_(self, myname):
0506         return myname;
0507     def moduleLabel_(self, myname):
0508         return myname
0509     def appendToProcessDescList_(self, lst, myname):
0510         lst.append(self.nameInProcessDesc_(myname))
0511     def insertInto(self, parameterSet, myname):
0512         newpset = parameterSet.newPSet()
0513         newpset.addString(True, "@module_label", self.moduleLabel_(myname))
0514         newpset.addString(True, "@module_type", self.type_())
0515         newpset.addString(True, "@module_edm_type", type(self).__name__)
0516         self.insertContentsInto(newpset)
0517         parameterSet.addPSet(True, self.nameInProcessDesc_(myname), newpset)
0518 
0519 
0520 
0521 class _Labelable(object):
0522     """A 'mixin' used to denote that the class can be paired with a label (e.g. an EDProducer)"""
0523     def label_(self):
0524         if not hasattr(self, "_Labelable__label"):
0525            raise RuntimeError("module has no label.  Perhaps it wasn't inserted into the process?")
0526         return self.__label
0527     def hasLabel_(self):
0528         return hasattr(self, "_Labelable__label") and self.__label is not None
0529     def setLabel(self,label):
0530         if self.hasLabel_() :
0531             if self.label_() != label and label is not None :
0532                 msg100 = "Attempting to change the label of a Labelable object, possibly an attribute of the Process\n"
0533                 msg101 = "Old label = "+self.label_()+"  New label = "+label+"\n"
0534                 msg102 = "Type = "+str(type(self))+"\n"
0535                 msg103 = "Some possible solutions:\n"
0536                 msg104 = "  1. Clone modules instead of using simple assignment. Cloning is\n"
0537                 msg105 = "  also preferred for other types when possible.\n"
0538                 msg106 = "  2. Declare new names starting with an underscore if they are\n"
0539                 msg107 = "  for temporaries you do not want propagated into the Process. The\n"
0540                 msg108 = "  underscore tells \"from x import *\" and process.load not to import\n"
0541                 msg109 = "  the name.\n"
0542                 msg110 = "  3. Reorganize so the assigment is not necessary. Giving a second\n"
0543                 msg111 = "  name to the same object usually causes confusion and problems.\n"
0544                 msg112 = "  4. Compose Sequences: newName = cms.Sequence(oldName)\n"
0545                 raise ValueError(msg100+msg101+msg102+msg103+msg104+msg105+msg106+msg107+msg108+msg109+msg110+msg111+msg112)
0546         self.__label = label
0547     def label(self):
0548         #print "WARNING: _Labelable::label() needs to be changed to label_()"
0549         return self.__label
0550     def __str__(self):
0551         #this is probably a bad idea
0552         # I added this so that when we ask a path to print
0553         # we will see the label that has been assigned
0554         return str(self.__label)
0555     def dumpSequenceConfig(self):
0556         return str(self.__label)
0557     def dumpSequencePython(self, options=PrintOptions()):
0558         if options.isCfg:
0559             return 'process.'+str(self.__label)
0560         else:
0561             return str(self.__label)
0562     def _findDependencies(self,knownDeps,presentDeps):
0563         #print 'in labelled'
0564         myDeps=knownDeps.get(self.label_(),None)
0565         if myDeps!=None:
0566             if presentDeps != myDeps:
0567                 raise RuntimeError("the module "+self.label_()+" has two dependencies \n"
0568                                    +str(presentDeps)+"\n"
0569                                    +str(myDeps)+"\n"
0570                                    +"Please modify sequences to rectify this inconsistency")
0571         else:
0572             myDeps=set(presentDeps)
0573             knownDeps[self.label_()]=myDeps
0574         presentDeps.add(self.label_())
0575 
0576 
0577 class _Unlabelable(object):
0578     """A 'mixin' used to denote that the class can be used without a label (e.g. a Service)"""
0579     pass
0580 
0581 class _ValidatingListBase(list):
0582     """Base class for a list which enforces that its entries pass a 'validity' test"""
0583     def __init__(self,*arg,**args):        
0584         super(_ValidatingListBase,self).__init__(arg)
0585         if 0 != len(args):
0586             raise SyntaxError("named arguments ("+','.join([x for x in args])+") passsed to "+str(type(self)))
0587         if not type(self)._isValid(iter(self)):
0588             raise TypeError("wrong types ("+','.join([str(type(value)) for value in iter(self)])+
0589                             ") added to "+str(type(self)))
0590     def __setitem__(self,key,value):
0591         if isinstance(key,slice):
0592             if not self._isValid(value):
0593                 raise TypeError("wrong type being inserted into this container "+self._labelIfAny())
0594         else:
0595             if not self._itemIsValid(value):
0596                 raise TypeError("can not insert the type "+str(type(value))+" in container "+self._labelIfAny())
0597         super(_ValidatingListBase,self).__setitem__(key,value)
0598     @classmethod
0599     def _isValid(cls,seq):
0600         # see if strings get reinterpreted as lists
0601         if isinstance(seq, str):
0602             return False
0603         for item in seq:
0604             if not cls._itemIsValid(item):
0605                 return False
0606         return True
0607     def _itemFromArgument(self, x):
0608         return x
0609     def _convertArguments(self, seq):
0610         if isinstance(seq, str):
0611             yield seq
0612         for x in seq:
0613             yield self._itemFromArgument(x)
0614     def append(self,x):
0615         if not self._itemIsValid(x):
0616             raise TypeError("wrong type being appended to container "+self._labelIfAny())
0617         super(_ValidatingListBase,self).append(self._itemFromArgument(x))
0618     def extend(self,x):
0619         if not self._isValid(x):
0620             raise TypeError("wrong type being extended to container "+self._labelIfAny())
0621         super(_ValidatingListBase,self).extend(self._convertArguments(x))
0622     def __add__(self,rhs):
0623         if not self._isValid(rhs):
0624             raise TypeError("wrong type being added to container "+self._labelIfAny())
0625         import copy
0626         value = copy.copy(self)
0627         value.extend(rhs)
0628         return value
0629     def insert(self,i,x):
0630         if not self._itemIsValid(x):
0631             raise TypeError("wrong type being inserted to container "+self._labelIfAny())
0632         super(_ValidatingListBase,self).insert(i,self._itemFromArgument(x))
0633     def _labelIfAny(self):
0634         result = type(self).__name__
0635         if hasattr(self, '__label'):
0636             result += ' ' + self.__label
0637         return result
0638 
0639 class _ValidatingParameterListBase(_ValidatingListBase,_ParameterTypeBase):
0640     def __init__(self,*arg,**args):        
0641         _ParameterTypeBase.__init__(self)
0642         if len (arg) == 1 and not isinstance(arg[0],str):
0643             try:
0644                 arg = iter(arg[0])
0645             except TypeError:
0646                 pass
0647         super(_ValidatingParameterListBase,self).__init__(*arg,**args)
0648     def value(self):
0649         return list(self)
0650     def setValue(self,v):
0651         self[:] = []
0652         self.extend(v)
0653         self._isModified=True
0654     def configValue(self, options=PrintOptions()):
0655         config = '{\n'
0656         first = True
0657         for value in iter(self):
0658             options.indent()
0659             config += options.indentation()
0660             if not first:
0661                 config+=', '
0662             config+=  self.configValueForItem(value, options)+'\n'
0663             first = False
0664             options.unindent()
0665         config += options.indentation()+'}\n'
0666         return config
0667     def configValueForItem(self,item, options):
0668         return str(item)
0669     def pythonValueForItem(self,item, options):
0670         return self.configValueForItem(item, options)
0671     def __repr__(self):
0672         return self.dumpPython()
0673     def dumpPython(self, options=PrintOptions()):
0674         specialImportRegistry.registerUse(self)
0675         result = self.pythonTypeName()+"("
0676         n = len(self)
0677         if hasattr(self, "_nPerLine"):
0678             nPerLine = self._nPerLine
0679         else:
0680             nPerLine = 5
0681         if n>nPerLine: options.indent()
0682         if n>=256:
0683             #wrap in a tuple since they don't have a size constraint
0684             result+=" ("
0685         for i, v in enumerate(self):
0686             if i == 0:
0687                 if n>nPerLine: result += '\n'+options.indentation()
0688             else:
0689                 if i % nPerLine == 0:
0690                     result += ',\n'+options.indentation()
0691                 else:
0692                     result += ', '
0693             result += self.pythonValueForItem(v,options)
0694         if n>nPerLine:
0695             options.unindent()
0696             result += '\n'+options.indentation()
0697         if n>=256:
0698             result +=' ) '
0699         result += ')'
0700         return result            
0701     def directDependencies(self):
0702         return []
0703     @staticmethod
0704     def _itemsFromStrings(strings,converter):
0705         return (converter(x).value() for x in strings)
0706 
0707 def saveOrigin(obj, level):
0708     import sys
0709     fInfo = inspect.getframeinfo(sys._getframe(level+1))
0710     obj._filename = fInfo.filename
0711     obj._lineNumber =fInfo.lineno
0712 
0713 def _modifyParametersFromDict(params, newParams, errorRaiser, keyDepth=""):
0714     if len(newParams):
0715         #need to treat items both in params and myparams specially
0716         for key,value in newParams.items():
0717             if key in params:
0718                 if value is None:
0719                     del params[key]
0720                 elif isinstance(value, dict):
0721                     if isinstance(params[key],_Parameterizable):
0722                         pset = params[key]
0723                         p =pset.parameters_()
0724                         oldkeys = set(p.keys())
0725                         _modifyParametersFromDict(p,
0726                                                   value,errorRaiser,
0727                                                   ("%s.%s" if isinstance(key, str) else "%s[%s]")%(keyDepth,key))
0728                         for k,v in p.items():
0729                             setattr(pset,k,v)
0730                             oldkeys.discard(k)
0731                         for k in oldkeys:
0732                             delattr(pset,k)
0733                     elif isinstance(params[key],_ValidatingParameterListBase):
0734                         if any(not isinstance(k, int) for k in value.keys()):
0735                             raise TypeError("Attempted to change a list using a dict whose keys are not integers")
0736                         plist = params[key]
0737                         if any((k < 0 or k >= len(plist)) for k in value.keys()):
0738                             raise IndexError("Attempted to set an index which is not in the list")
0739                         p = dict(enumerate(plist))
0740                         _modifyParametersFromDict(p,
0741                                                   value,errorRaiser,
0742                                                   ("%s.%s" if isinstance(key, str) else "%s[%s]")%(keyDepth,key))
0743                         for k,v in p.items():
0744                             plist[k] = v
0745                     else:
0746                         raise ValueError("Attempted to change non PSet value "+keyDepth+" using a dictionary")
0747                 elif isinstance(value,_ParameterTypeBase) or (isinstance(key, int)) or isinstance(value, _Parameterizable):
0748                     params[key] = value
0749                 else:
0750                     params[key].setValue(value)
0751             else:
0752                 if isinstance(value,_ParameterTypeBase) or isinstance(value, _Parameterizable):
0753                     params[key]=value
0754                 else:
0755                     errorRaiser(key)
0756 
0757 
0758 if __name__ == "__main__":
0759 
0760     import unittest
0761     class TestList(_ValidatingParameterListBase):
0762         @classmethod
0763         def _itemIsValid(cls,item):
0764             return True
0765     class testMixins(unittest.TestCase):
0766         def testListConstruction(self):
0767             t = TestList(1)
0768             self.assertEqual(t,[1])
0769             t = TestList((1,))
0770             self.assertEqual(t,[1])
0771             t = TestList("one")
0772             self.assertEqual(t,["one"])
0773             t = TestList( [1,])
0774             self.assertEqual(t,[1])
0775             t = TestList( (x for x in [1]) )
0776             self.assertEqual(t,[1])
0777 
0778             t = TestList(1,2)
0779             self.assertEqual(t,[1,2])
0780             t = TestList((1,2))
0781             self.assertEqual(t,[1,2])
0782             t = TestList("one","two")
0783             self.assertEqual(t,["one","two"])
0784             t = TestList(("one","two"))
0785             self.assertEqual(t,["one","two"])
0786             t = TestList( [1,2])
0787             self.assertEqual(t,[1,2])
0788             t = TestList( (x for x in [1,2]) )
0789             self.assertEqual(t,[1,2])
0790             t = TestList( iter((1,2)) )
0791             self.assertEqual(t,[1,2])
0792             
0793             
0794         def testLargeList(self):
0795             #lists larger than 255 entries can not be initialized
0796             #using the constructor
0797             args = [i for i in range(0,300)]
0798             
0799             t = TestList(*args)
0800             pdump= t.dumpPython()
0801             class cms(object):
0802                 def __init__(self):
0803                     self.TestList = TestList
0804             pythonized = eval( pdump, globals(),{'cms':cms()} )
0805             self.assertEqual(t,pythonized)
0806         def testUsingBlock(self):
0807             a = UsingBlock("a")
0808             self.assertTrue(isinstance(a, _ParameterTypeBase))
0809         def testConstruction(self):
0810             class __Test(_TypedParameterizable):
0811                 pass
0812             class __TestType(_SimpleParameterTypeBase):
0813                 def _isValid(self,value):
0814                     return True
0815             class __PSet(_ParameterTypeBase,_Parameterizable):
0816                 def __init__(self,*arg,**args):
0817                     #need to call the inits separately
0818                     _ParameterTypeBase.__init__(self)
0819                     _Parameterizable.__init__(self,*arg,**args)
0820 
0821             a = __Test("MyType", __PSet(a=__TestType(1)))
0822             self.assertEqual(a.a.value(), 1)
0823             b = __Test("MyType", __PSet(a=__TestType(1)), __PSet(b=__TestType(2)))
0824             self.assertEqual(b.a.value(), 1)
0825             self.assertEqual(b.b.value(), 2)
0826             self.assertRaises(ValueError, lambda: __Test("MyType", __PSet(a=__TestType(1)), __PSet(a=__TestType(2))))
0827 
0828         def testCopy(self):
0829             class __Test(_TypedParameterizable):
0830                 pass
0831             class __TestType(_SimpleParameterTypeBase):
0832                 def _isValid(self,value):
0833                     return True
0834             a = __Test("MyType",t=__TestType(1), u=__TestType(2))
0835             b = a.copy()
0836             self.assertEqual(b.t.value(),1)
0837             self.assertEqual(b.u.value(),2)
0838 
0839             c = __Test("MyType")
0840             self.assertEqual(len(c.parameterNames_()), 0)
0841             d = c.copy()
0842             self.assertEqual(len(d.parameterNames_()), 0)
0843         def testClone(self):
0844             class __Test(_TypedParameterizable):
0845                 pass
0846             class __TestType(_SimpleParameterTypeBase):
0847                 def _isValid(self,value):
0848                     return True
0849             class __PSet(_ParameterTypeBase,_Parameterizable):
0850                 def __init__(self,*arg,**args):
0851                     #need to call the inits separately
0852                     _ParameterTypeBase.__init__(self)
0853                     _Parameterizable.__init__(self,*arg,**args)
0854                 def dumpPython(self,options=PrintOptions()):
0855                     return "__PSet(\n"+_Parameterizable.dumpPython(self, options)+options.indentation()+")"
0856 
0857             a = __Test("MyType",
0858                        t=__TestType(1),
0859                        u=__TestType(2),
0860                        w = __TestType(3),
0861                        x = __PSet(a = __TestType(4),
0862                                   b = __TestType(6),
0863                                   c = __PSet(gamma = __TestType(5))))
0864             b = a.clone(t=3,
0865                         v=__TestType(4),
0866                         w= None,
0867                         x = dict(a = 7,
0868                                  c = dict(gamma = 8),
0869                                  d = __TestType(9)))
0870             c = a.clone(x = dict(a=None, c=None))
0871             self.assertEqual(a.t.value(),1)
0872             self.assertEqual(a.u.value(),2)
0873             self.assertEqual(b.t.value(),3)
0874             self.assertEqual(b.u.value(),2)
0875             self.assertEqual(b.v.value(),4)
0876             self.assertEqual(b.x.a.value(),7)
0877             self.assertEqual(b.x.b.value(),6)
0878             self.assertEqual(b.x.c.gamma.value(),8)
0879             self.assertEqual(b.x.d.value(),9)
0880             self.assertEqual(hasattr(b,"w"), False)
0881             self.assertEqual(hasattr(c.x,"a"), False)
0882             self.assertEqual(hasattr(c.x,"c"), False)
0883             self.assertRaises(TypeError,a.clone,**{"v":1})
0884             d = a.clone(__PSet(k=__TestType(42)))
0885             self.assertEqual(d.t.value(), 1)
0886             self.assertEqual(d.k.value(), 42)
0887             d2 = a.clone(__PSet(t=__TestType(42)))
0888             self.assertEqual(d2.t.value(), 42)
0889             d3 = a.clone(__PSet(t=__TestType(42)),
0890                          __PSet(u=__TestType(56)))
0891             self.assertEqual(d3.t.value(), 42)
0892             self.assertEqual(d3.u.value(), 56)
0893             self.assertRaises(ValueError,a.clone,
0894                               __PSet(t=__TestType(42)),
0895                               __PSet(t=__TestType(56)))
0896             d4 = a.clone(__PSet(t=__TestType(43)), u = 57)
0897             self.assertEqual(d4.t.value(), 43)
0898             self.assertEqual(d4.u.value(), 57)
0899             self.assertRaises(TypeError,a.clone,t=__TestType(43),**{"doesNotExist":57})
0900 
0901             e = __Test("MyType")
0902             self.assertEqual(len(e.parameterNames_()), 0)
0903             f = e.clone(__PSet(a = __TestType(1)), b = __TestType(2))
0904             self.assertEqual(f.a.value(), 1)
0905             self.assertEqual(f.b.value(), 2)
0906             g = e.clone()
0907             self.assertEqual(len(g.parameterNames_()), 0)
0908 
0909         def testModified(self):
0910             class __TestType(_SimpleParameterTypeBase):
0911                 def _isValid(self,value):
0912                     return True
0913             a = __TestType(1)
0914             self.assertEqual(a.isModified(),False)
0915             a.setValue(1)
0916             self.assertEqual(a.isModified(),False)
0917             a.setValue(2)
0918             self.assertEqual(a.isModified(),True)
0919             a.resetModified()
0920             self.assertEqual(a.isModified(),False)
0921         def testLargeParameterizable(self):
0922             class tLPTest(_TypedParameterizable):
0923                 pass
0924             class tLPTestType(_SimpleParameterTypeBase):
0925                 def _isValid(self,value):
0926                     return True
0927             class __DummyModule(object):
0928                 def __init__(self):
0929                     self.tLPTest = tLPTest
0930                     self.tLPTestType = tLPTestType
0931             p = tLPTest("MyType",** dict( [ ("a"+str(x), tLPTestType(x)) for x in range(0,300) ] ) )
0932             #check they are the same
0933             self.assertEqual(p.dumpPython(), eval(p.dumpPython(),{"cms": __DummyModule()}).dumpPython())
0934         def testSpecialImportRegistry(self):
0935             reg = _SpecialImportRegistry()
0936             reg.registerSpecialImportForType(int, "import foo")
0937             self.assertRaises(RuntimeError, lambda: reg.registerSpecialImportForType(int, "import bar"))
0938             reg.registerSpecialImportForType(str, "import bar")
0939             self.assertEqual(reg.getSpecialImports(), [])
0940             reg.registerUse([1])
0941             self.assertEqual(reg.getSpecialImports(), [])
0942             reg.registerUse(1)
0943             self.assertEqual(reg.getSpecialImports(), ["import foo"])
0944             reg.registerUse(1)
0945             self.assertEqual(reg.getSpecialImports(), ["import foo"])
0946             reg.registerUse("a")
0947             self.assertEqual(reg.getSpecialImports(), ["import bar", "import foo"])
0948         def testInvalidTypeChange(self):
0949             class __Test(_TypedParameterizable):
0950                 pass
0951             class __TestTypeA(_SimpleParameterTypeBase):
0952                 def _isValid(self,value):
0953                     return True
0954             class __TestTypeB(_SimpleParameterTypeBase):
0955                 def _isValid(self,value):
0956                     return True
0957                 pass
0958             a = __Test("MyType",
0959                        t=__TestTypeA(1))
0960             self.assertRaises(TypeError, lambda : setattr(a,'t',__TestTypeB(2)))
0961 
0962 
0963     unittest.main()