Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:53

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