1 """
2 Generic support for objects with full-featured Parameters and
3 messaging.
4
5 $Id: parameterized.py 9417 2008-10-08 20:23:33Z ceball $
6 """
7 __version__='$Revision: 9417 $'
8
9 import sys
10 import copy
11 import re
12
13 from operator import itemgetter,attrgetter
14 from types import FunctionType
15
16
17 SILENT = 0
18 WARNING = 50
19 NORMAL = 100
20 MESSAGE = NORMAL
21 VERBOSE = 200
22 DEBUG = 300
23
24 min_print_level = NORMAL
25
26
27
28 warnings_as_exceptions = False
29
30 object_count = 0
31
32
33 import inspect
35 """
36 Return a list of the class hierarchy above (and including) the given class.
37
38 Same as inspect.getmro(class_)[::-1]
39 """
40 return inspect.getmro(class_)[::-1]
41
44 """
45 Return a list of the class hierarchy below (and including) the given class.
46
47 The list is ordered from least- to most-specific. Can be useful for
48 printing the contents of an entire class hierarchy.
49 """
50 assert isinstance(class_,type)
51 q = [class_]
52 out = []
53 while len(q):
54 x = q.pop(0)
55 out.insert(0,x)
56 for b in x.__subclasses__():
57 if b not in q and b not in out:
58 q.append(b)
59 return out[::-1]
60
64 """
65 Return a list of slot names for slots defined in this class and
66 its superclasses.
67 """
68
69
70
71 all_slots = []
72 parent_param_classes = [class_ for class_ in classlist(class_)[1::]]
73 for class_ in parent_param_classes:
74 if hasattr(class_,'__slots__'):
75 all_slots+=class_.__slots__
76 return all_slots
77
78
79
80
81
82
83
84
85
86
87 from functools import partial
89 """
90 'optional @classmethod'
91
92 A decorator that allows a method to receive either the class
93 object (if called on the class) or the instance object
94 (if called on the instance) as its first argument.
95
96 Code (but not documentation) copied from:
97 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/523033.
98 """
99
100
103
104
105 - def __get__(self, obj, type_=None):
106 if obj is None:
107 return partial(self.func, type_)
108 else:
109 return partial(self.func, obj)
110
132
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 -class Parameter(object):
157 """
158 An attribute descriptor for declaring parameters.
159
160 Parameters are a special kind of class attribute. Setting a
161 Parameterized class attribute to be a Parameter instance causes
162 that attribute of the class (and the class's instances) to be
163 treated as a Parameter. This allows special behavior, including
164 dynamically generated parameter values, documentation strings,
165 constant and read-only parameters, and type or range checking at
166 assignment time.
167
168 For example, suppose someone wants to define two new kinds of
169 objects Foo and Bar, such that Bar has a parameter delta, Foo is a
170 subclass of Bar, and Foo has parameters alpha, sigma, and gamma
171 (and delta inherited from Bar). She would begin her class
172 definitions with something like this:
173
174 class Bar(Parameterized):
175 delta = Parameter(default=0.6, doc='The difference between steps.')
176 ...
177
178 class Foo(Bar):
179 alpha = Parameter(default=0.1, doc='The starting value.')
180 sigma = Parameter(default=0.5, doc='The standard deviation.',
181 constant=True)
182 gamma = Parameter(default=1.0, doc='The ending value.')
183 ...
184
185 Class Foo would then have four parameters, with delta defaulting
186 to 0.6.
187
188 Parameters have several advantages over plain attributes:
189
190 1. Parameters can be set automatically when an instance is
191 constructed: The default constructor for Foo (and Bar) will
192 accept arbitrary keyword arguments, each of which can be used
193 to specify the value of a Parameter of Foo (or any of Foo's
194 superclasses). E.g., if a script does this:
195
196 myfoo = Foo(alpha=0.5)
197
198 myfoo.alpha will return 0.5, without the Foo constructor
199 needing special code to set alpha.
200
201 If Foo implements its own constructor, keyword arguments will
202 still be accepted if the constructor accepts a dictionary of
203 keyword arguments (as in ``def __init__(self,**params):``), and
204 then each class calls its superclass (as in
205 ``super(Foo,self).__init__(**params)``) so that the
206 Parameterized constructor will process the keywords.
207
208 2. A Parameterized class need specify only the attributes of a
209 Parameter whose values differ from those declared in
210 superclasses; the other values will be inherited. E.g. if Foo
211 declares
212
213 delta = Parameter(default=0.2)
214
215 the default value of 0.2 will override the 0.6 inherited from
216 Bar, but the doc will be inherited from Bar.
217
218 3. The Parameter descriptor class can be subclassed to provide
219 more complex behavior, allowing special types of parameters
220 that, for example, require their values to be numbers in
221 certain ranges, generate their values dynamically from a random
222 distribution, or read their values from a file or other
223 external source.
224
225 4. The attributes associated with Parameters provide enough
226 information for automatically generating property sheets in
227 graphical user interfaces, allowing Parameterized instances to
228 be edited by users.
229
230 Note that Parameters can only be used when set as class attributes
231 of Parameterized classes. Parameters used as standalone objects,
232 or as class attributes of non-Parameterized classes, will not have
233 the behavior described here.
234 """
235 __metaclass__ = ParameterMetaclass
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 __slots__ = ['_attrib_name','_internal_name','default','doc',
292 'precedence','instantiate','constant','readonly']
293
294
295
296
297
298
299 - def __init__(self,default=None,doc=None,precedence=None,
300 instantiate=False,constant=False,readonly=False):
301 """
302 Initialize a new Parameter object: store the supplied attributes.
303
304 default: the owning class's value for the attribute
305 represented by this Parameter.
306
307 precedence is a value, usually in the range 0.0 to 1.0, that
308 allows the order of Parameters in a class to be defined (for
309 e.g. in GUI menus). A negative precedence indicates a
310 parameter that should be hidden in e.g. GUI menus.
311
312 default, doc, and precedence default to None. This is to allow
313 inheritance of Parameter slots (attributes) from the owning-class'
314 class hierarchy (see ParameterizedMetaclass).
315 """
316 self._attrib_name = None
317 self._internal_name = None
318 self.precedence = precedence
319 self.default = default
320 self.doc = doc
321 self.constant = constant or readonly
322 self.readonly = readonly
323 self._set_instantiate(instantiate)
324
325
335
336
338 """
339 Return the value for this Parameter.
340
341 If called for a Parameterized class, produce that
342 class's value (i.e. this Parameter object's 'default'
343 attribute).
344
345 If called for a Parameterized instance, produce that
346 instance's value, if one has been set - otherwise produce the
347 class's value (default).
348 """
349
350
351
352 if not obj:
353 result = self.default
354 else:
355 result = obj.__dict__.get(self._internal_name,self.default)
356 return result
357
358
360 """
361 Set the value for this Parameter.
362
363 If called for a Parameterized class, set that class's
364 value (i.e. set this Parameter object's 'default' attribute).
365
366 If called for a Parameterized instance, set the value of
367 this Parameter on that instance (i.e. in the instance's
368 __dict__, under the parameter's internal_name).
369
370
371 If the Parameter's constant attribute is True, only allows
372 the value to be set for a Parameterized class or on
373 uninitialized Parameterized instances.
374
375 If the Parameter's readonly attribute is True, only allows the
376 value to be specified in the Parameter declaration inside the
377 Parameterized source code. A read-only parameter also
378 cannot be set on a Parameterized class.
379
380 Note that until we support some form of read-only
381 object, it is still possible to change the attributes of the
382 object stored in a constant or read-only Parameter (e.g. the
383 left bound of a BoundingBox).
384 """
385
386
387 if self.constant or self.readonly:
388 if self.readonly:
389 raise TypeError("Read-only parameter '%s' cannot be modified"%self._attrib_name)
390 elif not obj:
391 self.default = val
392 elif not obj.initialized:
393 obj.__dict__[self._internal_name] = val
394 else:
395 raise TypeError("Constant parameter '%s' cannot be modified"%self._attrib_name)
396
397 else:
398 if not obj:
399 self.default = val
400 else:
401 obj.__dict__[self._internal_name] = val
402
403
405 raise TypeError("Cannot delete '%s': Parameters deletion not allowed."%self._attrib_name)
406
407
409 self._attrib_name = attrib_name
410 self._internal_name = "_%s_param_value"%attrib_name
411
412
414 """
415 All Parameters have slots, not a dict, so we have to support
416 pickle and deepcopy ourselves.
417 """
418 state = {}
419 for slot in get_all_slots(type(self)):
420 state[slot] = getattr(self,slot)
421
422 return state
423
428
617
632 """
633 Variant of repr() designed for generating a runnable script.
634
635 Types that require special handling can use the script_repr_reg
636 dictionary. Using the type as a key, add a function that returns a
637 suitable representation of instances of that type, and adds the
638 required import statement.
639 """
640
641
642 if type(val) in script_repr_reg:
643 rep = script_repr_reg[type(val)](val,imports,prefix,settings)
644
645 elif hasattr(val,'script_repr'):
646 rep=val.script_repr(imports=imports,prefix=prefix+" ")
647
648 else:
649 rep=repr(val)
650
651 return rep
652
660 result=[]
661 for i in container:
662 result.append(script_repr(i,imports,prefix,settings))
663
664
665 if isinstance(container,list):
666 d1,d2='[',']'
667 elif isinstance(container,tuple):
668 d1,d2='(',')'
669 else:
670 raise NotImplementedError
671 rep=d1+','.join(result)+d2
672
673
674
675 return rep
676
679 name = fn.func_name
680 module = fn.__module__
681 imports.append('import %s'%module)
682 return module+'.'+name
683
684
685 script_repr_reg[list]=container_script_repr
686 script_repr_reg[tuple]=container_script_repr
687 script_repr_reg[FunctionType]=function_script_repr
688
689
690
691
692
693
694 dbprint_prefix=None
695
696
697 -def as_uninitialized(fn):
698 """
699 Decorator: call fn with the parameterized_instance's
700 initialization flag set to False, then revert the flag.
701
702 (Used to decorate Parameterized methods that must alter
703 a constant Parameter.)
704 """
705 def override_initialization(parameterized_instance,*args,**kw):
706 original_initialized=parameterized_instance.initialized
707 parameterized_instance.initialized=False
708 fn(parameterized_instance,*args,**kw)
709 parameterized_instance.initialized=original_initialized
710 return override_initialization
711
715 """
716 Base class for named objects that support Parameters and message
717 formatting.
718
719 Automatic object naming: Every Parameterized instance has a name
720 parameter. If the user doesn't designate a name=<str> argument
721 when constructing the object, the object will be given a name
722 consisting of its class name followed by a unique 5-digit number.
723
724 Automatic parameter setting: The Parameterized __init__ method
725 will automatically read the list of keyword parameters. If any
726 keyword matches the name of a Parameter (see Parameter class)
727 defined in the object's class or any of its superclasses, that
728 parameter in the instance will get the value given as a keyword
729 argument. For example:
730
731 class Foo(Parameterized):
732 xx = Parameter(default=1)
733
734 foo = Foo(xx=20)
735
736 in this case foo.xx gets the value 20.
737
738 Message formatting: Each Parameterized instance has several methods
739 for optionally printing output according to the current 'print
740 level', such as SILENT, WARNING, MESSAGE, VERBOSE, or DEBUG. Each
741 successive level allows more messages to be printed. For example,
742 when the level is VERBOSE, all warning, message, and verbose
743 output will be printed. When it is WARNING, only warnings will be
744 printed. When it is SILENT, no output will be printed.
745
746 For each level (except SILENT) there's an associated print method:
747 Parameterized.warning(), .message(), .verbose(), and .debug().
748
749 Each line printed this way is prepended with the name of the
750 object that printed it. The Parameterized.print_level parameter
751 and the module global variable min_print_level combine to
752 determine what gets printed. For example, if foo is a
753 Parameterized:
754
755 foo.message('The answer is',42)
756
757 is equivalent to:
758
759 if max(foo.print_level,parameterized.min_print_level) >= MESSAGE:
760 print foo.name+':', 'The answer is', 42
761 """
762
763 __metaclass__ = ParameterizedMetaclass
764
765
766 name = Parameter(default=None,constant=True,doc="""
767 String identifier for this object.""")
768
769
770 print_level = Parameter(default=MESSAGE,precedence=-1)
771
772
774 """
775 Initialize this Parameterized instance.
776
777 The values of parameters can be supplied as keyword arguments
778 to the constructor (using parametername=parametervalue); these
779 values will override the class default values for this one
780 instance.
781
782 If no 'name' parameter is supplied, self.name defaults to the
783 object's class name with a unique number appended to it.
784 """
785 global object_count
786
787
788
789 self.initialized=False
790
791 self.__generate_name()
792
793 self._setup_params(**params)
794 object_count += 1
795
796 self.nopickle = []
797 self.debug('Initialized',self)
798
799 self.initialized=True
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
819 """
820 Save this instance's state.
821
822 For Parameterized instances, this includes the state of
823 dynamically generated values.
824
825 Subclasses that maintain short-term state should additionally
826 save and restore that state using state_push() and
827 state_pop().
828
829 Generally, this method is used by operations that need to test
830 something without permanently altering the objects' state.
831 """
832 for pname,p in self.params().items():
833 g = self.get_value_generator(pname)
834 if hasattr(g,'_Dynamic_last'):
835 g._saved_Dynamic_last.append(g._Dynamic_last)
836 g._saved_Dynamic_time.append(g._Dynamic_time)
837
838
839 elif hasattr(g,'state_push') and isinstance(g,Parameterized):
840 g.state_push()
841
843 """
844 Restore the most recently saved state.
845
846 See state_push() for more details.
847 """
848 for pname,p in self.params().items():
849 g = self.get_value_generator(pname)
850 if hasattr(g,'_Dynamic_last'):
851 g._Dynamic_last = g._saved_Dynamic_last.pop()
852 g._Dynamic_time = g._saved_Dynamic_time.pop()
853 elif hasattr(g,'state_pop') and isinstance(g,Parameterized):
854 g.state_pop()
855
856
857
858
859 @bothmethod
861 """
862 Set time_fn for all Dynamic Parameters of this class or
863 instance object that are currently being dynamically
864 generated.
865
866 Additionally, sets _Dynamic_time_fn=time_fn on this class or
867 instance object, so that any future changes to Dynamic
868 Parmeters can inherit time_fn (e.g. if a Number is changed
869 from a float to a number generator, the number generator will
870 inherit time_fn).
871
872 If specified, sublistattr is the name of an attribute of this
873 class or instance that contains an iterable collection of
874 subobjects on which set_dynamic_time_fn should be called. If
875 the attribute sublistattr is present on any of the subobjects,
876 set_dynamic_time_fn() will be called for those, too.
877 """
878 self_or_cls._Dynamic_time_fn = time_fn
879
880 if isinstance(self_or_cls,type):
881 a = (None,self_or_cls)
882 else:
883 a = (self_or_cls,)
884
885 for n,p in self_or_cls.params().items():
886 if hasattr(p,'_value_is_dynamic'):
887 if p._value_is_dynamic(*a):
888 g = self_or_cls.get_value_generator(n)
889 g._Dynamic_time_fn = time_fn
890
891 if sublistattr:
892 try:
893 sublist = getattr(self_or_cls,sublistattr)
894 except AttributeError:
895 sublist = []
896
897 for obj in sublist:
898 obj.set_dynamic_time_fn(time_fn,sublistattr)
899
900
901 @as_uninitialized
904
905
906 @as_uninitialized
908 """
909 Set name to a gensym formed from the object's type name and
910 the object_count.
911 """
912 self._set_name('%s%05d' % (self.__class__.__name__ ,object_count))
913
914
916 """
917 Provide a nearly valid Python representation that could be used to recreate
918 the item with its parameters, if executed in the appropriate environment.
919
920 Returns 'classname(parameter1=x,parameter2=y,...)', listing
921 all the parameters of this object.
922 """
923 settings = ['%s=%s' % (name,repr(val))
924 for name,val in self.get_param_values()]
925 return self.__class__.__name__ + "(" + ", ".join(settings) + ")"
926
927
928
929
931 """
932 Variant of __repr__ designed for generating a runnable script.
933 """
934
935 settings=[]
936 for name,val in self.get_param_values(onlychanged=script_repr_suppress_defaults):
937
938 if name == 'name' and re.match('^'+self.__class__.__name__+'[0-9]+$',str(val)):
939 rep=None
940 elif name == 'print_level':
941 rep=None
942 else:
943 rep=script_repr(val,imports,prefix,settings)
944
945 if rep is not None:
946 settings.append('%s=%s' % (name,rep))
947
948
949
950 cls = self.__class__.__name__
951 mod = self.__module__
952
953 bits = mod.split('.')
954
955 imports.append("import %s"%mod)
956 imports.append("import %s"%bits[0])
957
958
959
960
961 return mod+'.'+self.__class__.__name__ + "(" + (",\n"+prefix).join(settings) + ")"
962
963
965 """Return a short representation of the name and class of this object."""
966 return "<%s %s>" % (self.__class__.__name__,self.name)
967
968
969
970
971
972
974 """
975 Print each of the given args iff print_level or
976 self.db_print_level is greater than or equal to the given
977 level.
978
979 Any of args may be functions, in which case they will be
980 called. This allows delayed execution, preventing
981 time-consuming code from being called unless the print level
982 requires it.
983 """
984 if level <= max(min_print_level,self.print_level):
985
986
987 args = list(args)
988 for a in args:
989 if isinstance(a,FunctionType): args[args.index(a)]=a()
990
991 s = ' '.join([str(x) for x in args])
992
993 if dbprint_prefix and callable(dbprint_prefix):
994 prefix=dbprint_prefix()
995 else:
996 prefix=""
997
998 print "%s%s: %s" % (prefix,self.name,s)
999
1000 sys.stdout.flush()
1001
1002
1004 """
1005 Print the arguments as a warning, unless module variable
1006 warnings_as_exceptions is True, then raise an Exception
1007 containing the arguments.
1008 """
1009 if not warnings_as_exceptions:
1010 self.__db_print(WARNING,"Warning:",*args)
1011 else:
1012 raise Exception, ' '.join(["Warning:",]+[str(x) for x in args])
1013
1014
1018
1020 """Print the arguments as a verbose message."""
1021 self.__db_print(VERBOSE,*args)
1022
1024 """Print the arguments as a debugging statement."""
1025 self.__db_print(DEBUG,*args)
1026
1027
1042
1043
1044 @as_uninitialized
1046 """
1047 Initialize default and keyword parameter values.
1048
1049 First, ensures that all Parameters with 'instantiate=True'
1050 (typically used for mutable Parameters) are copied directly
1051 into each object, to ensure that there is an independent copy
1052 (to avoid suprising aliasing errors). Then sets each of the
1053 keyword arguments, warning when any of them are not defined as
1054 parameters.
1055
1056 Constant Parameters can be set during calls to this method.
1057 """
1058
1059 for class_ in classlist(type(self)):
1060 for (k,v) in class_.__dict__.items():
1061
1062 if isinstance(v,Parameter) and v.instantiate and k!="name":
1063 self._instantiate_param(v)
1064
1065 for name,val in params.items():
1066 desc = self.__class__.get_param_descriptor(name)[0]
1067 if desc:
1068 self.debug("Setting param %s=%s"% (name, val))
1069 else:
1070 self.warning("Setting non-parameter attribute %s=%s using a mechanism intended only for parameters" % (name, val))
1071
1072 setattr(self,name,val)
1073
1074
1076 """
1077 Print a warning if params contains something that is
1078 not a Parameter of this object.
1079
1080 Typically invoked by a __call__() method that accepts keyword
1081 arguments for parameter setting.
1082 """
1083 self_params = self.params()
1084 for item in params:
1085 if item not in self_params:
1086 self.warning("'%s' will be ignored (not a Parameter)."%item)
1087
1088
1090 """Return a list of name,value pairs for all Parameters of this object"""
1091 vals = []
1092 for name,val in self.params().items():
1093 value = self.get_value_generator(name)
1094 if (not onlychanged or value != val.default):
1095 vals.append((name,value))
1096
1097 vals.sort(key=itemgetter(0))
1098 return vals
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108 @bothmethod
1110 """
1111 Force a new value to be generated for the dynamic attribute
1112 name, and return it.
1113
1114 If name is not dynamic, its current value is returned
1115 (i.e. equivalent to getattr(name).
1116 """
1117 param_obj = cls_or_slf.params().get(name)
1118
1119 if not param_obj:
1120 return getattr(cls_or_slf,name)
1121
1122 cls,slf=None,None
1123 if isinstance(cls_or_slf,type):
1124 cls = cls_or_slf
1125 else:
1126 slf = cls_or_slf
1127
1128 if not hasattr(param_obj,'_force'):
1129 return param_obj.__get__(slf,cls)
1130 else:
1131 return param_obj._force(slf,cls)
1132
1133
1134 @bothmethod
1136 """
1137 Return the value or value-generating object of the named
1138 attribute.
1139
1140 For most parameters, this is simply the parameter's value
1141 (i.e. the same as getattr()), but Dynamic parameters have
1142 their value-generating object returned.
1143 """
1144 param_obj = cls_or_slf.params().get(name)
1145
1146 if not param_obj:
1147 value = getattr(cls_or_slf,name)
1148
1149
1150 elif hasattr(param_obj,'attribs'):
1151 value = [cls_or_slf.get_value_generator(a) for a in param_obj.attribs]
1152
1153
1154 elif not hasattr(param_obj,'_value_is_dynamic'):
1155 value = getattr(cls_or_slf,name)
1156
1157
1158 else:
1159 internal_name = "_%s_param_value"%name
1160 if hasattr(cls_or_slf,internal_name):
1161
1162 value = getattr(cls_or_slf,internal_name)
1163 else:
1164
1165 value = param_obj.default
1166
1167 return value
1168
1169
1170 @bothmethod
1172 """
1173 Return the current value of the named attribute without modifying it.
1174
1175 Same as getattr() except for Dynamic parameters, which have their
1176 last generated value returned.
1177 """
1178 param_obj = cls_or_slf.params().get(name)
1179
1180 if not param_obj:
1181 value = getattr(cls_or_slf,name)
1182 elif hasattr(param_obj,'attribs'):
1183 value = [cls_or_slf.inspect_value(a) for a in param_obj.attribs]
1184 elif not hasattr(param_obj,'_inspect'):
1185 value = getattr(cls_or_slf,name)
1186 else:
1187 if isinstance(cls_or_slf,type):
1188 value = param_obj._inspect(None,cls_or_slf)
1189 else:
1190 value = param_obj._inspect(cls_or_slf,None)
1191
1192 return value
1193
1194
1195
1197 """Print the values of all this object's Parameters."""
1198 for name,val in self.get_param_values():
1199 print '%s.%s = %s' % (self.name,name,val)
1200
1201
1203 """
1204 Save the object's state: return a dictionary that is a shallow
1205 copy of the object's __dict__ and that also includes the
1206 object's __slots__ (if it has any).
1207 """
1208
1209 state = self.__dict__.copy()
1210
1211 for slot in get_all_slots(type(self)):
1212 state[slot] = getattr(self,slot)
1213
1214
1215
1216
1217
1218
1219
1220
1221 return state
1222
1223
1225 """
1226 Restore objects from the state dictionary to this object.
1227
1228 During this process the object is considered uninitialized.
1229 """
1230 self.initialized=False
1231 for name,value in state.items():
1232 setattr(self,name,value)
1233 self.initialized=True
1234
1235
1236 @classmethod
1238 """
1239 Return the Parameters of this class as the
1240 dictionary {name: parameter_object}
1241
1242 Includes Parameters from this class and its
1243 superclasses.
1244 """
1245
1246
1247 try:
1248 return getattr(cls,'_%s__params'%cls.__name__)
1249 except AttributeError:
1250 paramdict = {}
1251 for class_ in classlist(cls):
1252 for name,val in class_.__dict__.items():
1253 if isinstance(val,Parameter):
1254 paramdict[name] = val
1255
1256
1257
1258
1259
1260 setattr(cls,'_%s__params'%cls.__name__,paramdict)
1261 return paramdict
1262
1263
1264
1265 @classmethod
1267 """Print the default values of all cls's Parameters."""
1268 for key,val in cls.__dict__.items():
1269 if isinstance(val,Parameter):
1270 print cls.__name__+'.'+key, '=', repr(val.default)
1271
1272
1274 """
1275 Return {parameter_name:parameter.default} for all non-constant
1276 Parameters.
1277
1278 Note that a Parameter for which instantiate==True has its default
1279 instantiated.
1280 """
1281 d = {}
1282 for param_name,param in self.params().items():
1283 if param.constant:
1284 pass
1285 elif param.instantiate:
1286 self._instantiate_param(param,dict_=d,key=param_name)
1287 else:
1288 d[param_name]=param.default
1289 return d
1290
1295 """Print the default values for all imported Parameters."""
1296 print "_______________________________________________________________________________"
1297 print ""
1298 print " Parameter Default Values"
1299 print ""
1300 classes = descendents(Parameterized)
1301 classes.sort(key=lambda x:x.__name__)
1302 for c in classes:
1303 c.print_param_defaults()
1304 print "_______________________________________________________________________________"
1305
1323 """
1324 Supports pickling of Parameterized class attributes for a given module.
1325
1326 When requested to be pickled, stores a module's PO classes' attributes,
1327 and any given startup_commands. On unpickling, executes the startup
1328 commands and sets the class attributes.
1329 """
1330
1331
1332
1333 - def __init__(self,module,exclusions=(),startup_commands=()):
1334 """
1335 module: a module object, such as topo
1336
1337 Any submodules listed by name in exclusions will not have their
1338 classes' attributes saved.
1339 """
1340 self.module=module
1341 self.exclude=exclusions
1342 self.startup_commands=startup_commands
1343
1345 """
1346 Return a dictionary of self.module's PO classes' attributes, plus
1347 self.startup_commands.
1348 """
1349
1350 import types
1351 for k,v in __main__.__dict__.items():
1352
1353 if isinstance(v,type) or isinstance(v,types.FunctionType):
1354 if v.__module__ == "__main__":
1355 Parameterized().warning("%s (type %s) has source in __main__; it will only be found on unpickling if the class is explicitly defined (e.g. by running the same script first) before unpickling."%(k,type(v)))
1356
1357
1358 class_attributes = {}
1359 self.get_PO_class_attributes(self.module,class_attributes,[],exclude=self.exclude)
1360
1361
1362
1363 return {'class_attributes':class_attributes,
1364 'startup_commands':self.startup_commands}
1365
1366
1368 """
1369 Execute the startup commands and set class attributes.
1370 """
1371 self.startup_commands = state['startup_commands']
1372
1373 for cmd in self.startup_commands:
1374 exec cmd in __main__.__dict__
1375
1376 for class_name,state in state['class_attributes'].items():
1377
1378 module_path = class_name[0:class_name.rindex('.')]
1379
1380
1381
1382
1383 exec 'import '+module_path in __main__.__dict__
1384
1385 try:
1386 class_ = eval(class_name,__main__.__dict__)
1387 except:
1388 Parameterized().warning("Could not find class %s to restore its parameter values (class might have been removed or renamed)."%class_name)
1389 break
1390
1391
1392 for p_name,p in state.items():
1393
1394 if class_name in _param_name_changes:
1395 if p_name in _param_name_changes[class_name]:
1396 new_p_name = _param_name_changes[class_name][p_name]
1397 Parameterized().message("%s's %s parameter has been renamed to %s."%(class_name,p_name,new_p_name))
1398 p_name = new_p_name
1399
1400 try:
1401 setattr(class_,p_name,p)
1402 except:
1403 Parameterized().warning('Problem restoring parameter %s=%s for class %s (Parameter object representing %s may have changed since the snapshot was created).' % (p_name,repr(p),class_name,p_name))
1404
1405
1406
1407
1409 """
1410 Recursively search module and get attributes of Parameterized classes within it.
1411
1412 class_attributes is a dictionary {module.path.and.Classname: state}, where state
1413 is the dictionary {attribute: value}.
1414
1415 Something is considered a module for our purposes if inspect says it's a module,
1416 and it defines __all__. We only search through modules listed in __all__.
1417
1418 Keeps a list of processed modules to avoid looking at the same one
1419 more than once (since e.g. __main__ contains __main__ contains
1420 __main__...)
1421
1422 Modules can be specifically excluded if listed in exclude.
1423 """
1424 dict_ = module.__dict__
1425 for (k,v) in dict_.items():
1426 if '__all__' in dict_ and inspect.ismodule(v) and k not in exclude:
1427 if k in dict_['__all__'] and v not in processed_modules:
1428 self.get_PO_class_attributes(v,class_attributes,processed_modules,exclude)
1429 processed_modules.append(v)
1430
1431 else:
1432 if isinstance(v,type) and issubclass(v,Parameterized):
1433
1434
1435
1436
1437
1438
1439
1440
1441 full_class_path = v.__module__+'.'+v.__name__
1442 class_attributes[full_class_path] = {}
1443
1444 for (name,obj) in v.__dict__.items():
1445 if isinstance(obj,Parameter):
1446 class_attributes[full_class_path][name] = obj
1447
1454 """
1455 A dictionary that returns the attribute of an object if that attribute is not
1456 present in itself.
1457
1458 Used to override the parameters of an object.
1459 """
1461
1462
1463
1464
1465
1466
1467
1468 self.overridden = overridden
1469 dict.__init__(self,dict_)
1470
1472 """Return the attribute from overridden object."""
1473 return getattr(self.overridden,attr)
1474
1476 """As dict.__repr__, but indicate the overridden object."""
1477
1478 return dict.__repr__(self)+" overriding params from %s"%repr(self.overridden)
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493