1
2
3
4
5
6
7
8
9 """Classes to control and store state information.
10
11 It was devised to provide conditional storage
12 """
13
14 __docformat__ = 'restructuredtext'
15
16 import operator, copy
17 from sets import Set
18 from textwrap import TextWrapper
19
20 from mvpa.misc.vproperty import VProperty
21 from mvpa.misc.exceptions import UnknownStateError
22 from mvpa.misc import warning
23 from mvpa.base.dochelpers import enhancedClassDocString, enhancedDocString
24
25 if __debug__:
26 from mvpa.misc import debug
29 """Base class for any custom behaving attribute intended to become part of a collection
30
31 Derived classes will have specific semantics:
32 * StateVariable: conditional storage
33 * Parameter: attribute with validity ranges.
34 - ClassifierParameter: specialization to become a part of
35 Classifier's params collection
36 - KernelParameter: --//-- to become a part of Kernel Classifier's
37 kernel_params collection
38
39 Those CollectableAttributes are to be groupped into corresponding groups for each class
40 by statecollector metaclass
41 """
42
43 - def __init__(self, name=None, doc=None):
44 self.__doc__ = doc
45 self.__name = name
46 self._value = None
47 self.reset()
48 if __debug__:
49 debug("COL",
50 "Initialized new collectable %s " % name + `self`)
51
52
55
58
59 - def _set(self, val):
60 if __debug__:
61
62
63
64 debug("COL",
65 "Setting %(self)s to %(val)s ",
66 msgargs={'self':self, 'val':val})
67 self._value = val
68 self._isset = True
69
70 @property
73
75 """Simply reset the flag"""
76 if __debug__:
77 debug("COL", "Reset %s to being non-modified" % self.name)
78 self._isset = False
79
80
82 res = "%s" % (self.name)
83 if self.isSet:
84 res += '*'
85 return res
86
89
91 if name is not None:
92 if isinstance(name, basestring):
93 if name[0] == '_':
94 raise ValueError, \
95 "Collectable attribute name must not start with _. Got %s" % name
96 else:
97 raise ValueError, \
98 "Collectable attribute name must be a string. Got %s" % `name`
99 self.__name = name
100
101
102 value = property(_getVirtual, _setVirtual)
103 name = property(_getName, _setName)
104
107 """Simple container intended to conditionally store the value
108
109 Statefull class provides easy interfact to access the variable
110 (simply through an attribute), or modifying internal state
111 (enable/disable) via .states attribute of type StateCollection.
112 """
113
114 - def __init__(self, name=None, enabled=True, doc="State variable"):
121
122
127
128 - def _set(self, val):
129 if __debug__:
130
131
132
133 debug("COL",
134 "Setting %(self)s to %(val)s ",
135 msgargs={'self':self, 'val':val})
136 if self.isEnabled:
137
138
139 CollectableAttribute._set(self, val)
140
145
146 @property
148 return self._isenabled
149
150 - def enable(self, value=False):
151 if self._isenabled == value:
152
153 return
154 if __debug__:
155 debug("STV", "%s %s" %
156 ({True: 'Enabling', False: 'Disabling'}[value], str(self)))
157 self._isenabled = value
158
159
165
168 """Container of some CollectableAttributes.
169
170 :Groups:
171 - `Public Access Functions`: `isKnown`
172 - `Access Implementors`: `_getListing`, `_getNames`
173 - `Mutators`: `__init__`
174 - `R/O Properties`: `listing`, `names`, `items`
175
176 XXX Seems to be not used and duplicating functionality: `_getListing` (thus `listing` property)
177 """
178
179 - def __init__(self, items=None, owner=None):
180 """Initialize the Collection
181
182 :Parameters:
183 items : dict of CollectableAttribute's
184 items to initialize with
185 enable_states : list
186 list of states to enable. If it contains 'all' (in any casing),
187 then all states (besides the ones in disable_states) will be enabled
188 disable_states : list
189 list of states to disable
190 """
191
192 self.__owner = owner
193
194 if items == None:
195 items = {}
196 self._items = items
197 """Dictionary to contain registered states as keys and
198 values signal either they are enabled
199 """
200
201
203 num = len(self._items)
204 res = "{"
205 for i in xrange(min(num, 4)):
206 if i>0: res += " "
207 res += "%s" % str(self._items.values()[i])
208 if len(self._items) > 4:
209 res += "..."
210 res += "}"
211 if __debug__:
212 if "ST" in debug.active:
213 res += " owner:%s" % `self.owner`
214 return res
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
251 """Returns `True` if state `index` is known at all"""
252 return self._items.has_key(index)
253
255 """Returns `True` if state `index` has value set"""
256 self._checkIndex(index)
257 return self._items[index].isSet
258
260 """Verify that given `index` is a known/registered state.
261
262 :Raise `KeyError`: if given `index` is not known
263 """
264 if not self.isKnown(index):
265 raise KeyError, \
266 "%s of %s has no key '%s' registered" \
267 % (self.__class__.__name__,
268 self.__owner.__class__.__name__,
269 index)
270
271 - def add(self, item):
272 """Add a new CollectableAttribute to the collection
273
274 :Parameters:
275 item : CollectableAttribute
276 or of derived class. Must have 'name' assigned
277
278 TODO: we should make it stricter to don't add smth of
279 wrong type into Collection since it might lead to problems
280
281 Also we might convert to __setitem__
282 """
283 if not isinstance(item, CollectableAttribute):
284 raise ValueError, \
285 "Collection can add only instances of " + \
286 "CollectableAttribute-derived classes. Got %s" % `item`
287 if item.name is None:
288 raise ValueError, \
289 "CollectableAttribute to be added %s must have 'name' set" % \
290 item
291 self._items[item.name] = item
292
293 if not self.owner is None:
294 self._updateOwner(item.name)
295
297 """Remove item from the collection
298 """
299 self._checkIndex(index)
300 self._updateOwner(index, register=False)
301 discard = self._items.pop(index)
302
303
305 """
306 """
307
308
309 if index[0] == '_':
310 return object.__getattribute__(self, index)
311 if self._items.has_key(index):
312 return self._items[index].value
313 return object.__getattribute__(self, index)
314
315
323
324
326 if self._items.has_key(index):
327 self._checkIndex(index)
328 return self._items[index]
329 else:
330 raise AttributeError("State collection %s has no %s attribute" % (self, index))
331
332
333
334
335
336
337
338
339
340
341
342
344 """Returns the value by index"""
345 self._checkIndex(index)
346 return self._items[index].value
347
352
353
354 - def _action(self, index, func, missingok=False, **kwargs):
355 """Run specific func either on a single item or on all of them
356
357 :Parameters:
358 index : basestr
359 Name of the state variable
360 func
361 Function (not bound) to call given an item, and **kwargs
362 missingok : bool
363 If True - do not complain about wrong index
364 """
365 if isinstance(index, basestring):
366 if index.upper() == 'ALL':
367 for index_ in self._items:
368 self._action(index_, func, missingok=missingok, **kwargs)
369 else:
370 try:
371 self._checkIndex(index)
372 func(self._items[index], **kwargs)
373 except:
374 if missingok:
375 return
376 raise
377 elif operator.isSequenceType(index):
378 for item in index:
379 self._action(item, func, missingok=missingok, **kwargs)
380 else:
381 raise ValueError, \
382 "Don't know how to handle variable given by %s" % index
383
384 - def reset(self, index=None):
385 """Reset the state variable defined by `index`"""
386
387 if not index is None:
388 indexes = [ index ]
389 else:
390 indexes = self.names
391
392 if len(self.items):
393 for index in indexes:
394
395 self._action(index, self._items.values()[0].__class__.reset,
396 missingok=False)
397
398
400 """Return a list of registered states along with the documentation"""
401
402
403 items = self._items.items()
404 items.sort()
405 return [ "%s: %s" % (str(x[1]), x[1].__doc__) for x in items ]
406
407
409 """Return ids for all registered state variables"""
410 return self._items.keys()
411
412
415
417 if not isinstance(owner, Stateful):
418 raise ValueError, \
419 "Owner of the StateCollection must be Stateful object"
420 if __debug__:
421 try: strowner = str(owner)
422 except: strowner = "UNDEF: <%s#%s>" % (owner.__class__, id(owner))
423 debug("ST", "Setting owner for %s to be %s" % (self, strowner))
424 if not self.__owner is None:
425
426 self._updateOwner(register=False)
427 self.__owner = owner
428 if not self.__owner is None:
429 self._updateOwner(register=True)
430
431
433 """Define an entry within owner's __dict__
434 so ipython could easily complete it
435
436 :Parameters:
437 index : basestring or list of basestring
438 Name of the attribute. If None -- all known get registered
439 register : bool
440 Register if True or unregister if False
441
442 XXX Needs refactoring since we duplicate the logic of expansion of index value
443 """
444 if not index is None:
445 if not index in self._items:
446 raise ValueError, \
447 "Attribute %s is not known to %s" % (index, self)
448 indexes = [ index ]
449 else:
450 indexes = self.names
451
452 ownerdict = self.owner.__dict__
453 selfdict = self.__dict__
454
455 for index_ in indexes:
456 if register:
457 if index_ in ownerdict:
458 raise RuntimeError, \
459 "Cannot register attribute %s within %s " % \
460 (index_, self.owner) + "since it has one already"
461 ownerdict[index_] = self._items[index_]
462 if index_ in selfdict:
463 raise RuntimeError, \
464 "Cannot register attribute %s within %s " % \
465 (index_, self) + "since it has one already"
466 selfdict[index_] = self._items[index_]
467 else:
468 if index_ in ownerdict:
469
470 ownerdict.pop(index_)
471 if index_ in selfdict:
472 selfdict.pop(index_)
473
474
475
476 names = property(fget=_getNames)
477 items = property(fget=lambda x:x._items)
478 owner = property(fget=_getOwner, fset=_setOwner)
479
480
481 listing = VProperty(fget=_getListing)
482
485 """Container of Parameters for a stateful object.
486 """
487
488
489
490
491
492
493
494
495
496
497
502
503
504 - def isSet(self, index=None):
505 if not index is None:
506 return Collection.isSet(self, index)
507
508 for index in self._items:
509 if Collection.isSet(self, index):
510 return True
511 return False
512
514 """Return list of indexes which were set"""
515 result = []
516
517 for index in self._items:
518 if Collection.isSet(self, index):
519 result.append(index)
520 return result
521
524 """Container of StateVariables for a stateful object.
525
526 :Groups:
527 - `Public Access Functions`: `isKnown`, `isEnabled`, `isActive`
528 - `Access Implementors`: `_getListing`, `_getNames`, `_getEnabled`
529 - `Mutators`: `__init__`, `enable`, `disable`, `_setEnabled`
530 - `R/O Properties`: `listing`, `names`, `items`
531 - `R/W Properties`: `enabled`
532 """
533
534 - def __init__(self, items=None, owner=None):
535 """Initialize the state variables of a derived class
536
537 :Parameters:
538 items : dict
539 dictionary of states
540 owner : Stateful
541 object which owns the collection
542 name : basestring
543 literal description. Usually just attribute name for the
544 collection, e.g. 'states'
545 """
546 Collection.__init__(self, items=items, owner=owner)
547
548 self.__storedTemporarily = []
549 """List to contain sets of enabled states which were enabled
550 temporarily.
551 """
552
553
554
555
556
557
558
559
561 """Copy known here states from `fromstate` object into current object
562
563 Crafted to overcome a problem mentioned above in the comment
564 and is to be called from __copy__ of derived classes
565
566 Probably sooner than later will get proper __getstate__,
567 __setstate__
568 """
569
570
571
572
573
574
575
576 operation = { True: copy.deepcopy,
577 False: copy.copy }[deep]
578
579 if isinstance(fromstate, Stateful):
580 fromstate = fromstate.states
581
582 self.enabled = fromstate.enabled
583 for name in self.names:
584 if fromstate.isKnown(name):
585 self._items[name] = operation(fromstate._items[name])
586
587
589 """Returns `True` if state `index` is enabled"""
590 self._checkIndex(index)
591 return self._items[index].isEnabled
592
594 """Returns `True` if state `index` is known and is enabled"""
595 return self.isKnown(index) and self.isEnabled(index)
596
597
598 - def enable(self, index, value=True, missingok=False):
602
606
607
608
609
612 """Temporarily enable/disable needed states for computation
613
614 Enable or disable states which are enabled in `other` and listed in
615 `enable _states`. Use `resetEnabledTemporarily` to reset
616 to previous state of enabled.
617
618 `other` can be a Stateful object or StateCollection
619 """
620 if enable_states == None:
621 enable_states = []
622 if disable_states == None:
623 disable_states = []
624 self.__storedTemporarily.append(self.enabled)
625 other_ = other
626 if isinstance(other, Stateful):
627 other = other.states
628
629 if not other is None:
630
631
632 add_enable_states = list(Set(other.enabled).difference(
633 Set(enable_states)).intersection(self.names))
634 if len(add_enable_states)>0:
635 if __debug__:
636 debug("ST",
637 "Adding states %s from %s to be enabled temporarily" %
638 (add_enable_states, other_) +
639 " since they are not enabled in %s" %
640 (self))
641 enable_states += add_enable_states
642
643
644
645 self.enable(enable_states)
646 self.disable(disable_states)
647
648
650 """Reset to previousely stored set of enabled states"""
651 if __debug__:
652 debug("ST", "Resetting to previous set of enabled states")
653 if len(self.enabled)>0:
654 self.enabled = self.__storedTemporarily.pop()
655 else:
656 raise ValueError("Trying to restore not-stored list of enabled " \
657 "states")
658
659
661 """Return list of enabled states
662
663 :Parameters:
664 nondefault : bool
665 Either to return also states which are enabled simply by default
666 invert : bool
667 Would invert the meaning, ie would return disabled states
668 """
669 if invert:
670 fmatch = lambda y: not self.isEnabled(y)
671 else:
672 fmatch = lambda y: self.isEnabled(y)
673
674 if nondefault:
675 ffunc = fmatch
676 else:
677 ffunc = lambda y: fmatch(y) and self._items[y]._defaultenabled != self.isEnabled(y)
678 return filter(ffunc, self.names)
679
680
682 """Given `indexlist` make only those in the list enabled
683
684 It might be handy to store set of enabled states and then to restore
685 it later on. It can be easily accomplished now::
686
687 >>> states_enabled = stateful.enabled
688 >>> stateful.enabled = ['blah']
689 >>> stateful.enabled = states_enabled
690
691 """
692 for index in self._items.keys():
693 self.enable(index, index in indexlist)
694
695
696
697 enabled = property(fget=_getEnabled, fset=_setEnabled)
698
699
700
701
702
703 _known_collections = {
704 'StateVariable': ("states", StateCollection),
705 'Parameter': ("params", ParameterCollection),
706 'KernelParameter': ("kernel_params", ParameterCollection)}
707
708 _col2class = dict(_known_collections.values())
709 """Mapping from collection name into Collection class"""
710
711 _collections_order = ['params', 'kernel_params', 'states']
714 """Intended to collect and compose StateCollection for any child
715 class of this metaclass
716 """
717
718
720
721 if __debug__:
722 debug("COLR",
723 "Collector call for %s.%s, where bases=%s, dict=%s " \
724 % (cls, name, bases, dict))
725
726 super(collector, cls).__init__(name, bases, dict)
727
728 collections = {}
729 for name, value in dict.iteritems():
730 if isinstance(value, CollectableAttribute):
731 baseclassname = value.__class__.__name__
732 col = _known_collections[baseclassname][0]
733
734 if not collections.has_key(col):
735 collections[col] = {}
736 collections[col][name] = value
737
738 if value.name is None:
739 value.name = name
740
741
742
743 for base in bases:
744 if hasattr(base, "__metaclass__") and \
745 base.__metaclass__ == collector:
746
747
748
749 newcollections = base._collections_template
750 if len(newcollections) == 0:
751 continue
752 if __debug__:
753 debug("COLR",
754 "Collect collections %s for %s from %s" %
755 (newcollections, cls, base))
756 for col, collection in newcollections.iteritems():
757 newitems = collection.items
758 if collections.has_key(col):
759 collections[col].update(newitems)
760 else:
761 collections[col] = newitems
762
763
764 if __debug__:
765 debug("COLR",
766 "Creating StateCollection template %s" % cls)
767
768
769 if hasattr(cls, "_ATTRIBUTE_COLLECTIONS"):
770 for col in cls._ATTRIBUTE_COLLECTIONS:
771 if not col in _col2class:
772 raise ValueError, \
773 "Requested collection %s is unknown to collector" % \
774 col
775 if not col in collections:
776 collections[col] = None
777
778
779
780
781
782 for col, colitems in collections.iteritems():
783 collections[col] = _col2class[col](colitems)
784
785 setattr(cls, "_collections_template", collections)
786
787
788
789
790
791
792 paramsdoc = ""
793 textwrapper = TextWrapper(subsequent_indent=" ",
794 initial_indent=" ",
795 width=70)
796
797 for col in ('params', 'kernel_params'):
798 if collections.has_key(col):
799 for param, parameter in collections[col].items.iteritems():
800 paramsdoc += " %s" % param
801 try:
802 paramsdoc += " : %s" % parameter.allowedtype
803 except:
804 pass
805 paramsdoc += "\n"
806 try:
807 doc = parameter.__doc__
808 try:
809 doc += " (Default: %s)" % parameter.default
810 except:
811 pass
812 paramsdoc += '\n'.join(textwrapper.wrap(doc))+'\n'
813 except Exception, e:
814 pass
815
816 if paramsdoc != "":
817 if __debug__:
818 debug("COLR", "Assigning __paramsdoc to be %s" % paramsdoc)
819 setattr(cls, "_paramsdoc", paramsdoc)
820
821 cls.__doc__ = enhancedClassDocString(cls, *bases)
822
825 """Base class for stateful objects.
826
827 Classes inherited from this class gain ability to provide state
828 variables, accessed as simple properties. Access to state variables
829 "internals" is done via states property and interface of
830 `StateCollection`.
831
832 NB This one is to replace old State base class
833 TODO: rename 'descr'? -- it should simply
834 be 'doc' -- no need to drag classes docstring imho.
835 """
836
837 __metaclass__ = collector
838
839 _initargs = [ 'enable_states', 'disable_states', 'descr' ]
840 """Initialization parameters which should be passed to Statefull"""
841
842 - def __init__(self,
843 enable_states=None,
844 disable_states=None,
845 descr=None):
846 """Initialize Stateful object
847
848 :Parameters:
849 enable_states : None or list of basestring
850 Names of the state variables which should be enabled additionally
851 to default ones
852 disable_states : None or list of basestring
853 Names of the state variables which should be disabled
854 descr : basestring
855 Description of the instance
856 """
857 if not hasattr(self, '_collections'):
858
859
860 object.__setattr__(self, '_collections',
861 copy.deepcopy( \
862 object.__getattribute__(self,
863 '_collections_template')))
864
865
866 for col, collection in self._collections.iteritems():
867 if col in self.__dict__:
868 raise ValueError, \
869 "Stateful object %s has already attribute %s" % \
870 (self, col)
871 self.__dict__[col] = collection
872 collection.owner = self
873
874 if self._collections.has_key('states'):
875 if enable_states == None:
876 enable_states = []
877 if disable_states == None:
878 disable_states = []
879
880 states = self._collections['states']
881 states.enable(enable_states, missingok=True)
882 states.disable(disable_states)
883 elif not (enable_states is None and disable_states is None):
884 warning("Provided enable_states and disable_states are " + \
885 "ignored since object %s has no states" % `self`)
886
887 self.__descr = descr
888
889 if __debug__:
890 debug("ST", "Stateful.__init__ was done for %s id %s with descr=%s" \
891 % (self.__class__, id(self), descr))
892
893
894
895
896
898
899
900 if index[0] == '_':
901 return object.__getattribute__(self, index)
902 for col, collection in object.__getattribute__(self, '_collections').iteritems():
903 if index in [col]:
904 return collection
905 if collection.items.has_key(index):
906 return collection.getvalue(index)
907 return object.__getattribute__(self, index)
908
917
918
920 for collection in self._collections.values():
921 collection.reset()
922
924 s = "%s:" % (self.__class__.__name__)
925 if hasattr(self, "_collections"):
926 for col, collection in self._collections.iteritems():
927 s += " %d %s:%s" %(len(collection.items), col, str(collection))
928 return s
929
931 return "<%s.%s#%d>" % (self.__class__.__module__, self.__class__.__name__, id(self))
932
933 descr = property(lambda self: self.__descr,
934 doc="Description of the object if any")
935
939 """Classes inherited from this class intend to collect attributes
940 within internal processing.
941
942 Subclassing Harvestable we gain ability to collect any internal
943 data from the processing which is especially important if an
944 object performs something in loop and discards some intermidiate
945 possibly interesting results (like in case of
946 CrossValidatedTransferError and states of the trained classifier
947 or TransferError).
948
949 """
950
951 harvested = StateVariable(enabled=False, doc=
952 """Store specified attributes of classifiers at each split""")
953
954 _KNOWN_COPY_METHODS = [ None, 'copy', 'deepcopy' ]
955
956 - def __init__(self, attribs=None, copy_attribs='copy', **kwargs):
957 """Initialize state of harvestable
958
959 :Parameters:
960 attribs : list of basestr or dicts
961 What attributes of call to store and return within
962 harvested state variable. If an item is a dictionary,
963 following keys are used ['name', 'copy']
964 copy_attribs : None or basestr
965 Default copying. If None -- no copying, 'copy'
966 - shallow copying, 'deepcopy' -- deepcopying
967
968 """
969 Stateful.__init__(self, **kwargs)
970
971 self.__atribs = attribs
972 self.__copy_attribs = copy_attribs
973
974 self._setAttribs(attribs)
975
977 """Set attributes to harvest
978
979 Each attribute in self.__attribs must have following fields
980 - name : functional (or arbitrary if 'obj' or 'attr' is set)
981 description of the thing to harvest,
982 e.g. 'transerror.clf.training_time'
983 - obj : name of the object to harvest from (if empty,
984 'self' is assumed),
985 e.g 'transerror'
986 - attr : attribute of 'obj' to harvest,
987 e.g. 'clf.training_time'
988 - copy : None, 'copy' or 'deepcopy' - way to copy attribute
989 """
990 if attribs:
991
992 self.states.enable('harvested')
993 self.__attribs = []
994 for i, attrib in enumerate(attribs):
995 if isinstance(attrib, dict):
996 if not 'name' in attrib:
997 raise ValueError, \
998 "Harvestable: attribute must be a string or " + \
999 "a dictionary with 'name'"
1000 else:
1001 attrib = {'name': attrib}
1002
1003
1004 if not 'copy' in attrib:
1005 attrib['copy'] = self.__copy_attribs
1006
1007
1008 if not attrib['copy'] in self._KNOWN_COPY_METHODS:
1009 raise ValueError, "Unknown method %s. Known are %s" % \
1010 (attrib['copy'], self._KNOWN_COPY_METHODS)
1011
1012 if not ('obj' in attrib or 'attr' in attrib):
1013
1014
1015 split = attrib['name'].split('.', 1)
1016 if len(split)==1:
1017 obj, attr = split[0], None
1018 else:
1019 obj, attr = split
1020 attrib.update({'obj':obj, 'attr':attr})
1021
1022 if attrib['obj'] == '':
1023 attrib['obj'] = 'self'
1024
1025
1026
1027 self.__attribs.append(attrib)
1028 else:
1029
1030 self.__attribs = []
1031
1032
1034 """The harvesting function: must obtain dictionary of variables from the caller.
1035
1036 :Parameters:
1037 vars : dict
1038 Dictionary of available data. Most often locals() could be
1039 passed as `vars`. Mention that desired to be harvested
1040 private attributes better be bound locally to some variable
1041
1042 :Returns:
1043 nothing
1044 """
1045
1046 if not self.states.isEnabled('harvested') or len(self.__attribs)==0:
1047 return
1048
1049 if not self.states.isSet('harvested'):
1050 self.harvested = dict([(a['name'], []) for a in self.__attribs])
1051
1052 for attrib in self.__attribs:
1053 attrv = vars[attrib['obj']]
1054
1055
1056 if not attrib['attr'] is None:
1057 attrv = eval('attrv.%s' % attrib['attr'])
1058
1059
1060 attrv = {'copy':copy.copy,
1061 'deepcopy':copy.deepcopy,
1062 None:lambda x:x}[attrib['copy']](attrv)
1063
1064 self.harvested[attrib['name']].append(attrv)
1065
1066
1067 harvest_attribs = property(fget=lambda self:self.__attribs,
1068 fset=_setAttribs)
1069
1072 """Base class for all classes which have collected parameters
1073 """
1074
1075 - def __init__(self, init_classes=None, **kwargs):
1076 """Initialize Parametrized class instance
1077
1078 :Parameters:
1079 init_classes : list of class
1080 List of classes which should be called with arguments which
1081 were not handled by Parametrized
1082 """
1083
1084 kwargs_stateful = {}
1085 for arg in Stateful._initargs:
1086 if kwargs.has_key(arg):
1087 kwargs_stateful[arg] = kwargs.pop(arg)
1088
1089
1090 Stateful.__init__(self, **kwargs_stateful)
1091
1092
1093 collections = filter(lambda x:isinstance(x, ParameterCollection),
1094 self._collections.values())
1095
1096
1097 for arg, argument in kwargs.items():
1098 set = False
1099 for collection in collections:
1100 if collection.items.has_key(arg):
1101 collection.setvalue(arg, argument)
1102 set = True
1103 break
1104 if set:
1105 trash = kwargs.pop(arg)
1106
1107
1108
1109
1110
1111
1112
1113 if init_classes is not None:
1114
1115
1116 kwargs.update(kwargs_stateful)
1117 for cls in init_classes:
1118 cls.__init__(self, **kwargs)
1119 else:
1120 if len(kwargs)>0:
1121 known_params = reduce(lambda x,y:x+y, [x.items.keys() for x in collections], [])
1122 raise TypeError, \
1123 "Unknown parameters %s for %s." % (kwargs.keys(), self) \
1124 + " Valid parameters are %s" % known_params
1125
1126
1128 """Definition of the object summary over Parametrized object
1129 """
1130
1131 res = ""
1132 if fullname:
1133 modulename = '%s' % self.__class__.__module__
1134 if modulename != "__main__":
1135 res = "%s." % modulename
1136 res += "%s(" % (self.__class__.__name__)
1137
1138 sep = ""
1139 collections = self._collections
1140
1141 for col in _collections_order:
1142 if not collections.has_key(col):
1143 continue
1144 collection = collections[col]
1145 if isinstance(collection, ParameterCollection):
1146 for k in collection.names:
1147
1148 if collection[k].isDefault: continue
1149 res += "%s%s=%s" % (sep, k, collection[k].value)
1150 sep = ', '
1151 elif isinstance(collection, StateCollection):
1152 for name, invert in ( ('enable', False), ('disable', True) ):
1153 states = collection._getEnabled(nondefault=False, invert=invert)
1154 if len(states):
1155 res += sep + "%s_states=%s" % (name, str(states))
1156 else:
1157 raise RuntimeError, "Unknown type of collection %s" % col
1158 res += ")"
1159 return res
1160
1162 return self.__repr__(fullname=False)
1163