Skip to content

Commit

Permalink
Merge pull request #6296 from Dr15Jones/haveModifierApplyImmediately
Browse files Browse the repository at this point in the history
Have cms.Modifier apply immediately
  • Loading branch information
cmsbuild committed Nov 9, 2014
2 parents dfd4d39 + d8d8c48 commit 7fdab00
Showing 1 changed file with 89 additions and 46 deletions.
135 changes: 89 additions & 46 deletions FWCore/ParameterSet/python/Config.py
Expand Up @@ -99,8 +99,11 @@ class Temp(object):

class Process(object):
"""Root class for a CMS configuration process"""
def __init__(self,name):
"""The argument 'name' will be the name applied to this Process"""
def __init__(self,name,*Mods):
"""The argument 'name' will be the name applied to this Process
Can optionally pass as additional arguments cms.Modifier instances
which will be used ot modify the Process as it is built
"""
self.__dict__['_Process__name'] = name
if not name.isalnum():
raise RuntimeError("Error: The process name is an empty string or contains non-alphanumeric characters")
Expand All @@ -127,6 +130,9 @@ def __init__(self,name):
self.__dict__['_Process__InExtendCall'] = False
self.__dict__['_Process__partialschedules'] = {}
self.__isStrict = False
self.__dict__['_Process__modifiers'] = Mods
for m in self.__modifiers:
m._setChosen()

def setStrict(self, value):
self.__isStrict = value
Expand Down Expand Up @@ -545,6 +551,10 @@ def extend(self,other,items=()):
#now put in proper bucket
newSeq._place(name,self)
self.__dict__['_Process__InExtendCall'] = False
# apply any newly acquired process modifiers
for m in self.__modifiers:
m._applyNewProcessModifiers(self)

def _dumpConfigNamedList(self,items,typeName,options):
returnValue = ''
for name,item in items:
Expand Down Expand Up @@ -1046,11 +1056,12 @@ class Modifier(object):
reconfigure items in a process to match our expectation of running in 2017. Once declared,
these Modifier instances are imported into a configuration and items which need to be modified
are then associated with the Modifier and with the action to do the modification.
The registered modifications will only occur if the modify() method is called.
The registered modifications will only occur if the Modifier was passed to
the cms.Process' constructor.
"""
def __init__(self):
self.__objectToModifiers = []
self.__processModifiers = []
self.__chosen = False
def toModifyProcess(self,func):
"""This is used to register actions to be performed on the process as a whole.
This takes as argument a callable object (e.g. function) which takes as its sole argument an instance of Process"""
Expand All @@ -1064,30 +1075,45 @@ def toModify(self,obj, func=None,**kw):
"""
if func is not None and len(kw) != 0:
raise TypeError("toModify takes either two arguments or one argument and key/value pairs")
if not self.isChosen():
return
if func is not None:
self.__objectToModifiers.append( (obj,func))
func(obj)
else:
self.__objectToModifiers.append( (obj, _ParameterModifier(kw)))
def modify(self,process):
"""This applies all the registered modifiers to the passed in process"""
temp =_ParameterModifier(kw)
temp(obj)
def _applyNewProcessModifiers(self,process):
"""Should only be called by cms.Process instances
applies list of accumulated changes to the process"""
for m in self.__processModifiers:
m(process)
for o,m in self.__objectToModifiers:
if isinstance(o,_Labelable):
if o.hasLabel_():
m(o)
else:
m(o)
return process
def __call__(self,process):
"""Forwards to modify call. The presence of a __call__ allows Modifiers to be chained together.
E.g. Have bar inherit all modifiers of foo
foo = Modifier()
bar = Modifier()
foo.toModifyProcess(bar)
m(process)
self.__processModifiers = list()
def _setChosen(self):
"""Should only be called by cms.Process instances"""
self.__chosen = True
def isChosen(self):
return self.__chosen

class ModifierChain(object):
"""A Modifier made up of a list of Modifiers
"""
self.modify(process)

def __init__(self, *chainedModifiers):
self.__chosen = False
self.__chain = chainedModifiers
def _applyNewProcessModifiers(self,process):
"""Should only be called by cms.Process instances
applies list of accumulated changes to the process"""
for m in self.__chain:
m._applyNewProcessModifiers(process)
def _setChosen(self):
"""Should only be called by cms.Process instances"""
self.__chosen = True
for m in self.__chain:
m._setChosen()
def isChosen(self):
return self.__chosen


if __name__=="__main__":
import unittest
import copy
Expand Down Expand Up @@ -1797,42 +1823,59 @@ def testPrune(self):
self.assert_(hasattr(p, 'pth'))
def testModifier(self):
m1 = Modifier()
p = Process("test")
p = Process("test",m1)
p.a = EDAnalyzer("MyAnalyzer", fred = int32(1))
def _mod_fred(obj):
obj.fred = 2
m1.toModify(p.a,_mod_fred)
self.assertEqual(p.a.fred.value(),2)
p.b = EDAnalyzer("YourAnalyzer", wilma = int32(1))
m1.toModify(p.b, wilma = 2)
self.assertEqual(p.a.fred.value(),1)
self.assertEqual(p.b.wilma.value(),1)
m1.modify(p)
self.assertEqual(p.a.fred.value(),2)
self.assertEqual(p.b.wilma.value(),2)
#check that items not attached to process are unchanged
#check that Modifier not attached to a process doesn't run
m1 = Modifier()
p = Process("test")
p.a = EDAnalyzer("MyAnalyzer", fred = int32(1))
m1.toModify(p.a,_mod_fred)
b = EDAnalyzer("YourAnalyzer", wilma = int32(1))
m1.toModify(b, wilma = 2)
self.assertEqual(p.a.fred.value(),1)
self.assertEqual(b.wilma.value(),1)
m1.modify(p)
self.assertEqual(p.a.fred.value(),2)
self.assertEqual(b.wilma.value(),1)
#make sure chains of modifiers work
m1 = Modifier()
m2 = Modifier()
m2.toModifyProcess(m1)
p = Process("test")
p.a = EDAnalyzer("MyAnalyzer", fred = int32(1))
m1.toModify(p.a,_mod_fred)
p.b = EDAnalyzer("YourAnalyzer", wilma = int32(1))
m1.toModify(p.b, wilma = 2)
m2.toModify(p.b, wilma = 3)
m2.modify(p)
self.assertEqual(p.a.fred.value(),1)
self.assertEqual(p.b.wilma.value(),1)
#make sure clones get the changes
m1 = Modifier()
p = Process("test",m1)
p.a = EDAnalyzer("MyAnalyzer", fred = int32(1), wilma = int32(1))
m1.toModify(p.a, fred = int32(2))
p.b = p.a.clone(wilma = int32(3))
self.assertEqual(p.a.fred.value(),2)
self.assertEqual(p.a.wilma.value(),1)
self.assertEqual(p.b.fred.value(),2)
self.assertEqual(p.b.wilma.value(),3)
#test that load causes process wide methods to run
def _rem_a(proc):
del proc.a
class DummyMod(object):
def __init__(self):
self.a = EDAnalyzer("Dummy")
testMod = DummyMod()
p.extend(testMod)
self.assert_(hasattr(p,"a"))
m1 = Modifier()
p = Process("test",m1)
m1.toModifyProcess(_rem_a)
p.extend(testMod)
self.assert_(not hasattr(p,"a"))
#test ModifierChain
m1 = Modifier()
mc = ModifierChain(m1)
p = Process("test",mc)
testMod = DummyMod()
m1.toModifyProcess(_rem_a)
p.b = EDAnalyzer("Dummy2", fred = int32(1))
m1.toModify(p.b, fred = int32(3))
p.extend(testMod)
self.assert_(not hasattr(p,"a"))
self.assertEqual(p.b.fred.value(),3)


unittest.main()

0 comments on commit 7fdab00

Please sign in to comment.