added ParamSet & ParamObj

This commit is contained in:
Darren Ranalli 2005-04-22 01:50:42 +00:00
parent 0988a2c484
commit c748fb4fee

View File

@ -731,6 +731,177 @@ class Functor:
_kargs.update(kargs) _kargs.update(kargs)
return apply(self._function,_args,_kargs) return apply(self._function,_args,_kargs)
class ParamSet:
# abstract base class for container of parameter values for a ParamObj
# (see below)
# specifies default values for every parameter
# dict of params and their default values
# derived classes should define their own additional params and default
# values in the same way
Params = {
# base class does not define any parameters, but they would appear as
# 'name': value,
}
def __init__(self, *args, **kwArgs):
ParamSet._compileDefaultParams()
if len(args) == 1 and len(kwArgs) == 0:
# extract our params from an existing ParamObj instance
obj = args[0]
self.paramVals = {}
for param in self.getParams():
self.paramVals[param] = getSetter(obj, param, 'get')()
else:
assert len(args) == 0
if __debug__:
for arg in kwArgs.keys():
assert arg in self.getParams()
self.paramVals = dict(kwArgs)
def getValue(self, param):
if param in self.paramVals:
return self.paramVals[param]
return self._Params[param]
def applyTo(self, obj):
# Apply our entire set of params to a ParamObj
obj.lockParams()
for param in self.getParams():
getSetter(obj, param)(self.getValue(param))
obj.unlockParams()
# CLASS METHODS
def getParams(cls):
# returns safely-mutable list of param names
cls._compileDefaultParams()
return cls._Params.keys()
getParams = classmethod(getParams)
def getDefaultValue(cls, param):
cls._compileDefaultParams()
return cls._Params[param]
getDefaultValue = classmethod(getDefaultValue)
def _compileDefaultParams(cls):
if cls.__dict__.has_key('_Params'):
# we've already compiled the defaults for this class
return
bases = list(cls.__bases__)
# bring less-derived classes to the front
mostDerivedLast(bases)
cls._Params = {}
for c in (bases + [cls]):
# make sure this base has its dict of param defaults
c._compileDefaultParams()
if c.__dict__.has_key('Params'):
# apply this class' default param values to our dict
cls._Params.update(c.Params)
_compileDefaultParams = classmethod(_compileDefaultParams)
class ParamObj:
# abstract base for classes that want to support a formal parameter
# set whose values may be queried, changed, 'bulk' changed, and
# extracted/stored/applied all at once (see ParamSet above)
# for each param, ParamObj must define getter, setter, and applyer
# for each parameter
# (replace 'Param' with the name of the parameter):
#
# getParam() returns current value,
# setParam(value) sets current value,
# applyParam() (OPTIONAL) tells object to react to newly-set value
# inside applyParam, previous value of param is avaliable
# as self.getPriorValue()
# to do a bulk change:
# obj.lockParams()
# obj.setX('foo')
# obj.setY(34)
# ...
# obj.unlockParams()
# derived class must override this to be the appropriate ParamSet subclass
ParamClass = ParamSet
def __init__(self):
self._paramLockRefCount = 0
def setterStub(param, value, self=self):
# should we apply the value now or should we wait?
# if this obj's params are locked, we track which values have
# been set, and on unlock, we'll call the applyers for those
# values
if self._paramLockRefCount > 0:
# set the new value; make sure we're not calling ourselves
# recursively
getSetter(self.__class__, param)(self, value)
if param not in self._priorValues:
try:
priorValue = getSetter(self, param, 'get')()
except:
priorValue = None
self._priorValues[param] = priorValue
self._paramsSet[param] = None
else:
# prepare for call to getPriorValue
self._oneShotPriorVal = getSetter(self, param, 'get')()
# set the new value; make sure we're not calling ourselves
# recursively
getSetter(self.__class__, param)(self, value)
# call the applier, if there is one
applier = getattr(self, getSetterName(param, 'apply'), None)
if applier is not None:
applier()
del self._oneShotPriorVal
# insert stub funcs for param setters
for param in self.ParamClass.getParams():
# if the setter is a direct member of self, move the setter
# aside
setterName = getSetterName(param)
if setterName in self.__dict__:
self.__dict__[setterName + '_MOVED'] = self.__dict__[setterName]
# and replace it with a stub that will a) call the setter and
# then the applier, or b) call the setter and queue the applier,
# depending on whether our params are locked
self.__dict__[setterName] = Functor(setterStub, param)
def setDefaultParams(self):
# set all the default parameters on ourself
self.ParamClass().applyTo(self)
def lockParams(self):
self._paramLockRefCount += 1
if self._paramLockRefCount == 1:
self._handleLockParams()
def unlockParams(self):
if self._paramLockRefCount > 0:
self._paramLockRefCount -= 1
if self._paramLockRefCount == 0:
self._handleUnlockParams()
def _handleLockParams(self):
# this will store the names of the parameters that are modified
self._paramsSet = {}
# this will store the values of modified params (from prior to
# the lock).
self._priorValues = {}
def _handleUnlockParams(self):
self.__curParam = None
for param in self._paramsSet:
# call the applier, if there is one
applier = getattr(self, getSetterName(param, 'apply'), None)
if applier is not None:
self.__curParam = param
applier()
del self.__curParam
del self._priorValues
del self._paramsSet
def paramsLocked(self):
return self._paramLockRefCount > 0
def getPriorValue(self):
# call this within an apply function to find out what the prior value
# of a param was before the set call(s) corresponding to the call
# to apply
if hasattr(self, '_oneShotPriorVal'):
return self._oneShotPriorVal
return self._priorValues[self.__curParam]
def bound(value, bound1, bound2): def bound(value, bound1, bound2):
""" """
returns value if value is between bound1 and bound2 returns value if value is between bound1 and bound2