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 if name is not None: 115 if isinstance(name, basestring): 116 if name[0] == '_': 117 raise ValueError, \ 118 "Collectable attribute name must not start " \ 119 "with _. Got %s" % name 120 else: 121 raise ValueError, \ 122 "Collectable attribute name must be a string. " \ 123 "Got %s" % `name` 124 self.__name = name
125 126 127 # XXX should become vproperty? 128 # YYY yoh: not sure... someone has to do performance testing 129 # to see which is more effective. My wild guess is that 130 # _[gs]etVirtual would be faster 131 value = property(_getVirtual, _setVirtual) 132 name = property(_getName, _setName)
133
134 135 136 # XXX think that may be discard hasunique and just devise top 137 # class DatasetAttribute 138 -class AttributeWithUnique(CollectableAttribute):
139 """Container which also takes care about recomputing unique values 140 141 XXX may be we could better link original attribute to additional 142 attribute which actually stores the values (and do reverse there 143 as well). 144 145 Pros: 146 * don't need to mess with getattr since it would become just another 147 attribute 148 149 Cons: 150 * might be worse design in terms of comprehension 151 * take care about _set, since we shouldn't allow 152 change it externally 153 154 For now lets do it within a single class and tune up getattr 155 """ 156
157 - def __init__(self, name=None, hasunique=True, doc="Attribute with unique"):
158 CollectableAttribute.__init__(self, name, doc) 159 self._hasunique = hasunique 160 self._resetUnique() 161 if __debug__: 162 debug("UATTR", 163 "Initialized new AttributeWithUnique %s " % name + `self`)
164 165
166 - def reset(self):
167 super(AttributeWithUnique, self).reset() 168 self._resetUnique()
169 170
171 - def _resetUnique(self):
172 self._uniqueValues = None
173 174
175 - def _set(self, *args, **kwargs):
176 self._resetUnique() 177 CollectableAttribute._set(self, *args, **kwargs)
178 179
180 - def _getUniqueValues(self):
181 if self.value is None: 182 return None 183 if self._uniqueValues is None: 184 # XXX we might better use Set, but yoh recalls that 185 # N.unique was more efficient. May be we should check 186 # on the the class and use Set only if we are not 187 # dealing with ndarray (or lists/tuples) 188 self._uniqueValues = N.unique(N.asanyarray(self.value)) 189 return self._uniqueValues
190 191 uniqueValues = property(fget=_getUniqueValues) 192 hasunique = property(fget=lambda self:self._hasunique)
193
194 195 196 # Hooks for comprehendable semantics and automatic collection generation 197 -class SampleAttribute(AttributeWithUnique):
198 pass
199
200 201 202 -class FeatureAttribute(AttributeWithUnique):
203 pass
204
205 206 207 -class DatasetAttribute(AttributeWithUnique):
208 pass
209
210 211 212 -class StateVariable(CollectableAttribute):
213 """Simple container intended to conditionally store the value 214 """ 215
216 - def __init__(self, name=None, enabled=True, doc="State variable"):
217 CollectableAttribute.__init__(self, name, doc) 218 self._isenabled = enabled 219 self._defaultenabled = enabled 220 if __debug__: 221 debug("STV", 222 "Initialized new state variable %s " % name + `self`)
223 224
225 - def _get(self):
226 if not self.isSet: 227 raise UnknownStateError("Unknown yet value of %s" % (self.name)) 228 return CollectableAttribute._get(self)
229 230
231 - def _set(self, val):
232 if self.isEnabled: 233 # XXX may be should have left simple assignment 234 # self._value = val 235 CollectableAttribute._set(self, val) 236 elif __debug__: 237 debug("COL", 238 "Not setting disabled %(self)s to %(val)s ", 239 msgargs={'self':self, 'val':val})
240 241
242 - def reset(self):
243 """Simply detach the value, and reset the flag""" 244 CollectableAttribute.reset(self) 245 self._value = None
246 247 248 @property
249 - def isEnabled(self):
250 return self._isenabled
251 252
253 - def enable(self, value=False):
254 if self._isenabled == value: 255 # Do nothing since it is already in proper state 256 return 257 if __debug__: 258 debug("STV", "%s %s" % 259 ({True: 'Enabling', False: 'Disabling'}[value], str(self))) 260 self._isenabled = value
261 262
263 - def __str__(self):
264 res = CollectableAttribute.__str__(self) 265 if self.isEnabled: 266 res += '+' # it is enabled but no value is assigned yet 267 return res
268