Package mvpa :: Package misc :: Module attributes
[hide private]
[frames] | no frames]

Source Code for Module mvpa.misc.attributes

  1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- 
  2  # vi: set ft=python sts=4 ts=4 sw=4 et: 
  3  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 
  4  # 
  5  #   See COPYING file distributed along with the PyMVPA package for the 
  6  #   copyright and license terms. 
  7  # 
  8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 
  9  """Module with some special objects to be used as magic attributes with 
 10  dedicated containers aka. `Collections`. 
 11  """ 
 12   
 13  __docformat__ = 'restructuredtext' 
 14   
 15   
 16  from mvpa.misc.exceptions import UnknownStateError 
 17   
 18  if __debug__: 
 19      from mvpa.base import debug 
20 21 22 23 ################################################################## 24 # Various attributes which will be collected into collections 25 # 26 -class CollectableAttribute(object):
27 """Base class for any custom behaving attribute intended to become 28 part of a collection. 29 30 Derived classes will have specific semantics: 31 32 * StateVariable: conditional storage 33 * AttributeWithUnique: easy access to a set of unique values 34 within a container 35 * Parameter: attribute with validity ranges. 36 37 - ClassifierParameter: specialization to become a part of 38 Classifier's params collection 39 - KernelParameter: --//-- to become a part of Kernel Classifier's 40 kernel_params collection 41 42 Those CollectableAttributes are to be groupped into corresponding 43 collections for each class by statecollector metaclass, ie it 44 would be done on a class creation (ie not per each object) 45 """ 46 47 _instance_index = 0 48
49 - def __init__(self, name=None, doc=None, index=None):
50 if index is None: 51 CollectableAttribute._instance_index += 1 52 index = CollectableAttribute._instance_index 53 self._instance_index = index 54 self.__doc__ = doc 55 self.__name = name 56 self._value = None 57 self._isset = False 58 self.reset() 59 if __debug__: 60 debug("COL", 61 "Initialized new collectable #%d:%s" % (index,name) + `self`)
62 63 64 # Instead of going for VProperty lets make use of virtual method
65 - def _getVirtual(self):
66 return self._get()
67 68
69 - def _setVirtual(self, value):
70 return self._set(value)
71 72
73 - def _get(self):
74 return self._value
75 76
77 - def _set(self, val):
78 if __debug__: 79 # Since this call is quite often, don't convert 80 # values to strings here, rely on passing them 81 # withing msgargs 82 debug("COL", 83 "Setting %(self)s to %(val)s ", 84 msgargs={'self':self, 'val':val}) 85 self._value = val 86 self._isset = True
87 88 89 @property
90 - def isSet(self):
91 return self._isset
92 93
94 - def reset(self):
95 """Simply reset the flag""" 96 if __debug__ and self._isset: 97 debug("COL", "Reset %s to being non-modified" % self.name) 98 self._isset = False
99 100 101 # TODO XXX unify all bloody __str__
102 - def __str__(self):
103 res = "%s" % (self.name) 104 if self.isSet: 105 res += '*' # so we have the value already 106 return res
107 108
109 - def _getName(self):
110 return self.__name
111 112
113 - def _setName(self, name):
114 """Set the name of parameter 115 116 .. note:: 117 Should not be called for an attribute which is already assigned 118 to a collection 119 """ 120 if name is not None: 121 if isinstance(name, basestring): 122 if name[0] == '_': 123 raise ValueError, \ 124 "Collectable attribute name must not start " \ 125 "with _. Got %s" % name 126 else: 127 raise ValueError, \ 128 "Collectable attribute name must be a string. " \ 129 "Got %s" % `name` 130 self.__name = name
131 132 133 # XXX should become vproperty? 134 # YYY yoh: not sure... someone has to do performance testing 135 # to see which is more effective. My wild guess is that 136 # _[gs]etVirtual would be faster 137 value = property(_getVirtual, _setVirtual) 138 name = property(_getName) #, _setName)
139
140 141 142 # XXX think that may be discard hasunique and just devise top 143 # class DatasetAttribute 144 -class AttributeWithUnique(CollectableAttribute):
145 """Container which also takes care about recomputing unique values 146 147 XXX may be we could better link original attribute to additional 148 attribute which actually stores the values (and do reverse there 149 as well). 150 151 Pros: 152 * don't need to mess with getattr since it would become just another 153 attribute 154 155 Cons: 156 * might be worse design in terms of comprehension 157 * take care about _set, since we shouldn't allow 158 change it externally 159 160 For now lets do it within a single class and tune up getattr 161 """ 162
163 - def __init__(self, name=None, hasunique=True, doc="Attribute with unique"):
164 CollectableAttribute.__init__(self, name, doc) 165 self._hasunique = hasunique 166 self._resetUnique() 167 if __debug__: 168 debug("UATTR", 169 "Initialized new AttributeWithUnique %s " % name + `self`)
170 171
172 - def reset(self):
173 super(AttributeWithUnique, self).reset() 174 self._resetUnique()
175 176
177 - def _resetUnique(self):
178 self._uniqueValues = None
179 180
181 - def _set(self, *args, **kwargs):
182 self._resetUnique() 183 CollectableAttribute._set(self, *args, **kwargs)
184 185
186 - def _getUniqueValues(self):
187 if self.value is None: 188 return None 189 if self._uniqueValues is None: 190 # XXX we might better use Set, but yoh recalls that 191 # N.unique was more efficient. May be we should check 192 # on the the class and use Set only if we are not 193 # dealing with ndarray (or lists/tuples) 194 self._uniqueValues = N.unique(N.asanyarray(self.value)) 195 return self._uniqueValues
196 197 uniqueValues = property(fget=_getUniqueValues) 198 hasunique = property(fget=lambda self:self._hasunique)
199
200 201 202 # Hooks for comprehendable semantics and automatic collection generation 203 -class SampleAttribute(AttributeWithUnique):
204 pass
205
206 207 208 -class FeatureAttribute(AttributeWithUnique):
209 pass
210
211 212 213 -class DatasetAttribute(AttributeWithUnique):
214 pass
215
216 217 218 -class StateVariable(CollectableAttribute):
219 """Simple container intended to conditionally store the value 220 """ 221
222 - def __init__(self, name=None, enabled=True, doc="State variable"):
223 # Force enabled state regardless of the input 224 # to facilitate testing 225 if __debug__ and 'ENFORCE_STATES_ENABLED' in debug.active: 226 enabled = True 227 CollectableAttribute.__init__(self, name, doc) 228 self._isenabled = enabled 229 self._defaultenabled = enabled 230 if __debug__: 231 debug("STV", 232 "Initialized new state variable %s " % name + `self`)
233 234
235 - def _get(self):
236 if not self.isSet: 237 raise UnknownStateError("Unknown yet value of %s" % (self.name)) 238 return CollectableAttribute._get(self)
239 240
241 - def _set(self, val):
242 if self.isEnabled: 243 # XXX may be should have left simple assignment 244 # self._value = val 245 CollectableAttribute._set(self, val) 246 elif __debug__: 247 debug("COL", 248 "Not setting disabled %(self)s to %(val)s ", 249 msgargs={'self':self, 'val':val})
250 251
252 - def reset(self):
253 """Simply detach the value, and reset the flag""" 254 CollectableAttribute.reset(self) 255 self._value = None
256 257 258 @property
259 - def isEnabled(self):
260 return self._isenabled
261 262
263 - def enable(self, value=False):
264 if self._isenabled == value: 265 # Do nothing since it is already in proper state 266 return 267 if __debug__: 268 debug("STV", "%s %s" % 269 ({True: 'Enabling', False: 'Disabling'}[value], str(self))) 270 self._isenabled = value
271 272
273 - def __str__(self):
274 res = CollectableAttribute.__str__(self) 275 if self.isEnabled: 276 res += '+' # it is enabled but no value is assigned yet 277 return res
278