1 """
2 Code used to support old snapshots, and update scripts.
3
4 $Id: legacy.py 11323 2010-07-28 17:10:13Z ceball $
5 """
6 __version__='$Revision: 8021 $'
7
8 import imp
9 import sys
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 -def _setstate(inst,state):
31
34 """
35 Allow processing of state with state_mod_fn before
36 class_.__setstate__(instance,state) is called.
37
38 state_mod_fn must accept two arguments: instance and state.
39 """
40 if not hasattr(class_,'__setstate__'):
41
42 class_.__setstate__ = _setstate
43
44 old_setstate = class_.__setstate__
45 def new_setstate(instance,state):
46
47
48
49 state_mod_fn(instance,state)
50 old_setstate(instance,state)
51 class_.__setstate__ = new_setstate
52
53
54
55
56 -def select_setstate(class_,selector,pre_super=False,post_super=True):
57 """
58 Select appropriate function to call as a replacement
59 for class.__setstate__ at runtime.
60
61 selector must return None if the class_'s original method is
62 to be used; otherwise, it should return a function that takes
63 an instance of the class and the state.
64
65 pre_super and post_super determine if super(class_)'s
66 __setstate__ should be invoked before or after (respectively)
67 calling the function returned by selector. If selector returns
68 None, super(class_)'s __setstate__ is never called.
69 """
70 if pre_super is True and post_super is True:
71 raise ValueError("Cannot call super method before and after.")
72
73 old_setstate = class_.__setstate__
74 def new_setstate(instance,state):
75 setstate = selector(state) or old_setstate
76
77 if pre_super and setstate is not old_setstate:
78 super(class_,instance).__setstate__
79
80 setstate(instance,state)
81
82 if post_super and setstate is not old_setstate:
83 super(class_,instance).__setstate__(state)
84
85
86 class_.__setstate__ = new_setstate
87
88
89
90
91
92
93 -def fake_a_class(module,old_name,new_class,new_class_args=()):
94 """
95 Install a class named 'old_name' in 'module'; when created,
96 the class actually returns an instance of 'new_class'.
97
98 new_class_args allow any arguments to be supplied to new_class
99 before other arguments are passed at creation time.
100
101 For use when module.old_name=new_class is not possible.
102 """
103 class_code = """
104 class %s(object):
105 def __new__(cls,*args,**kw):
106 all_args = new_class_args+args
107 return new_class(*all_args,**kw)"""
108 exec class_code%old_name in locals()
109 fake_old_class = eval(old_name,locals())
110
111 setattr(module,old_name,fake_old_class)
112
115 """return module y from: 'from x import y'"""
116 return __import__(x+'.'+y,fromlist=[y])
117
119 """
120 For use when module parent.name is now actual_module.
121
122 Use parent_name to override parent.name if necessary (e.g. when
123 parent is already redirected).
124 """
125 if parent_name is None:
126 parent_name=parent.__name__
127
128 sys.modules[parent_name+'.'+name]=actual_module
129 setattr(sys.modules[parent_name],name,actual_module)
130
131 return getattr(parent,name)
132
135 """
136 For use when package parent.name is now actual_package.
137
138 All .py files found in actual_package's path are added to newly
139 created parent.name package.
140 """
141 new_package = module_redirect(name,parent,actual_package)
142
143 import os,fnmatch
144 mod_names = [f.split('.py')[0] for f in os.listdir(actual_package.__path__[0]) if fnmatch.fnmatch(f,'[!._]*.py')]
145
146 for mod_name in mod_names:
147 m=_import(actual_package.__name__,mod_name)
148 module_redirect(mod_name,new_package,m,parent_name=parent.__name__+'.'+name)
149
150
151
152 -def fake_a_module(name,source_code,parent=None,parent_name=None):
153 """
154 Create the module parent.name using source_code.
155
156 Installs to sys.modules[name] unless parent is not None,
157 in which case see module_redirect().
158 """
159
160 module = imp.new_module(name)
161 exec source_code in module.__dict__
162
163 if parent is None:
164 sys.modules[name]=module
165 else:
166 module_redirect(name,parent,module,parent_name)
167
173
174
175
176 import param
177 param.parameterized.PicklableClassAttributes.do_not_restore+=[
178 'topo.base.boundingregion.BoundingRegion',
179 'topo.base.boundingregion.BoundingBox',
180 'topo.base.boundingregion.BoundingCircle',
181 'topo.base.boundingregion.BoundingEllipse',
182 'topo.base.cf.ConnectionField',
183 'topo.projection.basic.SharedWeightCF']
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 -def LegacySupport():
216 """
217 Support for running old scripts. Use in conjunction with
218 SnapshotSupport.install() to avoid duplication.
219 """
220
221 import topo.base.cf
222 cfp = topo.base.cf.CFProjection
223 type.__setattr__(cfp,'weights_shape',cfp.__dict__['cf_shape'])
224
230
231
232
233
234
235
236
237
238
239
240 S=supporters=DuplicateCheckingList()
241
242
243
244
245
246 import param.parameterized
247 param.parameterized.PicklableClassAttributes.do_not_restore+=[
248 'param.normalize_path',
249 'param.resolve_path']
250
251
252
253 import topo.misc.fixedpoint as fixedpoint
254 from topo.misc.util import ModuleImporter,ModuleFaker
257
259 if fullname == 'fixedpoint' or fullname.startswith('fixedpoint.'):
260 f = FixedPointFaker()
261 f.path = path
262 return f
263 return None
264
268
269 import sys
270 sys.meta_path.append(FixedPointImporter())
275
276 import param
277
278 class Enumeration(object):
279 """
280 Provide support for existing code that uses Enumeration.
281 """
282 @staticmethod
283 def _transform(kw):
284 if 'available' in kw:
285 kw['objects']=kw['available']
286 del kw['available']
287 kw['check_on_set']=True
288
289 def __new__(cls,*args,**kw):
290 print "no way!"
291 Enumeration._transform(kw)
292 n = param.ObjectSelector(*args,**kw)
293 return n
294
295 def __init__(self,*args,**kw):
296 Enumeration._transform(kw)
297 super(param.ObjectSelector,self).__init__(self,*args,**kw)
298
299 param.Enumeration = Enumeration
300
301 S.append(removed_Enumeration)
308
309 S.append(bye_bye_param)
313
314
315 def _changed_output_fn(instance,state):
316 for x in 'output_fn','weights_output_fn':
317 if x in state:
318 fn = state[x]
319 state['%ss'%x] = [fn]
320
321
322 del state[x]
323
324 if 'apply_%s'%x in state:
325 state['apply_%ss'%x]=state['apply_%s'%x]
326 del state['apply_%s'%x]
327
328 if 'apply_%s_init'%x in state:
329 state['apply_%ss_init'%x]=state['apply_%s_init'%x]
330 del state['apply_%s_init'%x]
331
332
333
334 from topo.param.parameterized import Parameterized
335 preprocess_state(Parameterized,_changed_output_fn)
336
337
338 def _post_initialization_weights_output_fn(instance,state):
339 if 'post_initialization_weights_output_fn' in state:
340 state['post_initialization_weights_output_fns']=[state['post_initialization_weights_output_fn']]
341 del state['post_initialization_weights_output_fn']
342 from topo.sheet.lissom import LISSOM
343
344
345
346
347
348
349
350
351
352
353
354 S.append(renamed_output_fn_to_output_fns)
368
369 topo.base.functionfamily.PipelineOF = PipelineTF
370 topo.base.functionfamily.PipelineTF = PipelineTF
371
372 topo.transferfn.basic.PipelineTF = PipelineTF
373 topo.transferfn.basic.Pipeline = PipelineTF
374 topo.transferfn.basic.PipelineOF = PipelineTF
375
376 S.append(removed_pipeline)
381
382 import topo,topo.transferfn
383 package_redirect('outputfn',topo,topo.transferfn)
384
385
386 import topo.base.functionfamily
387 import topo.transferfn.basic
388
389 def _rename(mod):
390 for name,obj in mod.__dict__.items():
391 if isinstance(obj,type) and issubclass(obj,mod.TransferFn):
392 if name.endswith('TF'):
393 old_name = name[0:-2]+'OF'
394 new_class = obj
395 setattr(mod,old_name,obj)
396 elif 'TransferFn' in name:
397 old_name=name.replace('Transfer','Output')
398 setattr(mod,old_name,obj)
399
400 _rename(topo.base.functionfamily)
401 _rename(topo.transferfn.basic)
402
403 S.append(rename_outputfn_to_transferfn)
407
408 class InstanceMethodWrapper(object):
409 """
410 Wrapper for pickling instance methods.
411
412 The constructor takes an instance method (e.g. for an object
413 'sim', method sim.time) as its only argument. The wrapper
414 instance is callable, picklable, etc.
415 """
416 def __repr__(self):
417 return repr(self.im.im_func)
418
419
420 def _fname(self):
421 return self.im.im_func.func_name
422 __name__ = property(_fname)
423
424 def __init__(self,im):
425 self.im = im
426
427 def __getstate__(self):
428 return (self.im.im_self,
429 self.im.im_func.func_name)
430
431 def __setstate__(self,state):
432 obj,func_name = state
433 self.im = getattr(obj,func_name)
434
435 def __call__(self,*args,**kw):
436 return self.im(*args,**kw)
437
438 import topo.param
439 topo.param.InstanceMethodWrapper = InstanceMethodWrapper
440
441 S.append(removed_InstanceMethodWrapper)
445
446 from topo import param
447 def _param_remove_hidden(instance,state):
448 if 'hidden' in state:
449 if state['hidden'] is True:
450 state['precedence']=-1
451 del state['hidden']
452 preprocess_state(param.Parameter,_param_remove_hidden)
453
454 S.append(param_remove_hidden)
457
458 from topo import param
459 def _param_add_readonly(instance,state):
460 if 'readonly' not in state:
461 state['readonly']=False
462 preprocess_state(param.Parameter,_param_add_readonly)
463
464 S.append(param_add_readonly)
468
469 from topo import param
470 def _class_selector_remove_suffixtolose(instance,state):
471 if 'suffix_to_lose' in state:
472 del state['suffix_to_lose']
473 preprocess_state(param.ClassSelector,_class_selector_remove_suffixtolose)
474
475 S.append(class_selector_remove_suffixtolose)
485
486 from topo.base.cf import ConnectionField
487 preprocess_state(ConnectionField,_cf_rename_slice_array)
488
489 S.append(cf_rename_slice_array)
492
493
494 def _sim_remove_time_type_attr(instance,state):
495 if '_time_type' in state:
496
497
498 state['_time_type_param_value']=state['_time_type']
499 del state['_time_type']
500
501 from topo.base.simulation import Simulation
502 preprocess_state(Simulation,_sim_remove_time_type_attr)
503 S.append(sim_remove_time_type_attr)
508
509
510
511
512
513
514
515 def _slice_setstate_selector(state):
516
517 if isinstance(state,dict):
518 return None
519 else:
520 import numpy
521 return numpy.ndarray.__setstate__
522
523 from topo.base.sheetcoords import Slice
524 select_setstate(Slice,_slice_setstate_selector,post_super=False)
525
526 S.append(slice_setstate_selector)
530
531
532
533 from topo.base.sheetcoords import Slice
534 def _sheet_set_shape(instance,state):
535
536 if '_SheetCoordinateSystem__shape' not in state:
537 m = '_SheetCoordinateSystem__'
538
539
540 setattr(instance,'bounds',state['bounds'])
541 setattr(instance,'lbrt',state['lbrt'])
542 setattr(instance,m+'xdensity',state[m+'xdensity'])
543 setattr(instance,m+'xstep',state[m+'xstep'])
544 setattr(instance,m+'ydensity',state[m+'ydensity'])
545 setattr(instance,m+'ystep',state[m+'ystep'])
546 shape = Slice(instance.bounds,instance).shape_on_sheet()
547 setattr(instance,m+'shape',shape)
548 state[m+'shape']=shape
549
550 from topo.base.sheet import Sheet
551 preprocess_state(Sheet,_sheet_set_shape)
552 S.append(sheet_set_shape)
556
557
558
559
560 from topo import param
561 from topo.base.functionfamily import OutputFn,ResponseFn,LearningFn,\
562 CoordinateMapperFn
563 d = {"OutputFnParameter":OutputFn,
564 "ResponseFnParameter":ResponseFn,
565 "LearningFnParameter":LearningFn,
566 "CoordinateMapperFnParameter":CoordinateMapperFn}
567
568 import topo.base.functionfamily
569 for name,arg in d.items():
570 fake_a_class(topo.base.functionfamily,name,
571 param.ClassSelector,(arg,))
572
573 from topo.base.cf import CFPOutputFn,CFPResponseFn,CFPLearningFn
574 d = {"CFPOutputFnParameter":CFPOutputFn,
575 "CFPResponseFnParameter":CFPResponseFn,
576 "CFPLearningFnParameter":CFPLearningFn}
577
578 import topo.base.cf
579 for name,arg in d.items():
580 fake_a_class(topo.base.cf,name,
581 param.ClassSelector,(arg,))
582
583 import topo.base.patterngenerator
584 from topo.base.patterngenerator import PatternGenerator
585 fake_a_class(topo.base.patterngenerator,"PatternGeneratorParameter",
586 param.ClassSelector,(PatternGenerator,))
587
588 S.append(removed_function_family_parameters)
600
601 import topo.base.simulation
602 topo.base.simulation.SimSingleton=SimSingleton
603
604 S.append(added_dynamic_time_fn)
611
612 S.append(moved_parameterized)
620 S.append(renamed_parameterizedobject)
623
624
625 import topo.param
626 module_redirect('parameterclasses',topo.base,topo.param)
627
628 new_names = ['Boolean','String','Callable','Composite','Selector',
629 'ObjectSelector','ClassSelector','List','Dict']
630
631 for name in new_names:
632 setattr(topo.base.parameterclasses,name+'Parameter',
633 getattr(topo.base.parameterclasses,name))
634 S.append(removed_parameterclasses)
637
638 class DynamicNumber(object):
639 """
640 Provide support for existing code that uses DynamicNumber:
641 see __new__().
642 """
643 warnedA = False
644 warnedB = False
645
646 def __new__(cls,default=None,**params):
647 """
648 If bounds or softbounds or any params are supplied, assume
649 we're dealing with DynamicNumber declared as a parameter
650 of a ParameterizedObject class. In this case, return a
651 new *Number* parameter instead.
652
653 Otherwise, assume we're dealing with DynamicNumber
654 supplied as the value of a Number Parameter. In this case,
655 return a DynamicNumber (but one which is not a Parameter,
656 just a simple wrapper).
657
658 * Of course, this is not 100% reliable: if someone defines
659 * a class with a DynamicNumber but doesn't pass any doc or
660 * bounds or whatever. But in such cases, they'll get the
661 * ParameterizedObject warning about being unable to set a
662 * class attribute.
663
664 Most of the code is to generate warning messages.
665
666 """
667 if len(params)>0:
668
669 m = "\n------------------------------------------------------------\nPlease update your code - instead of using the 'DynamicNumber' Parameter in the code for your class, please use the 'Number' Parameter; the Number Parameter now supports dynamic values automatically.\n\nE.g. change\n\nclass X(Parameterized):\n y=DynamicNumber(NumberGenerator())\n\nto\n\n\nclass X(Parameterized):\n y=Number(NumberGenerator())\n------------------------------------------------------------\n"
670 if not cls.warnedA:
671 param.Parameterized().warning(m)
672 cls.warnedA=True
673
674
675 n = Number(default,**params)
676 return n
677 else:
678
679 m = "\n------------------------------------------------------------\nPlease update your code - instead of using DynamicNumber to contain a number generator, pass the number generator straight to the Number parameter:\n\nE.g. in code using the class below...\n\nclass X(Parameterized):\n y=Number(0.0)\n\n\nchange\n\nx = X(y=DynamicNumber(NumberGenerator()))\n\nto\n\nx = X(y=NumberGenerator())\n------------------------------------------------------------\n"
680 if not cls.warnedB:
681 param.Parameterized().warning(m)
682 cls.warnedB=True
683
684 return object.__new__(cls,default)
685
686
687 def __init__(self,default=0.0,bounds=None,softbounds=None,**params):
688 self.val = default
689 def __call__(self):
690 return self.val()
691
692 import topo.base.parameterclasses
693 topo.base.parameterclasses.DynamicNumber = DynamicNumber
694 import topo.param
695 topo.param.DynamicNumber = DynamicNumber
696
697 S.append(removed_DynamicNumber)
701
702 from topo.base.cf import CFProjection
703 from numpy import array
704 def _cfproj_add_cfs(instance,state):
705 if 'cfs' not in state:
706 cflist = state['_cfs']
707 state['cfs'] = array(cflist)
708 preprocess_state(CFProjection,_cfproj_add_cfs)
709
710 S.append(cfproj_add_cfs)
713
714 import topo.outputfn,topo.responsefn,\
715 topo.learningfn,topo.coordmapper
716 package_redirect('outputfns',topo,topo.outputfn)
717 package_redirect('responsefns',topo,topo.responsefn)
718 package_redirect('learningfns',topo,topo.learningfn)
719 package_redirect('coordmapperfns',topo,topo.coordmapper)
720
721 S.append(renamed_component_libraries)
727
728 S.append(removed_generator)
733
734 S.append(renamed_sheets)
739
740 S.append(renamed_eps)
746
747 S.append(renamed_patterns)
752
753 S.append(renamed_commands)
765
766 S.append(renamed_projections)
773
774 S.append(renamed_generatorsheet)
780
781 S.append(renamed_functionfamilies)
784
785 import topo.outputfn.projfn,topo.responsefn.projfn,topo.learningfn.projfn
786 for mod in ['outputfn','responsefn','learningfn']:
787 existing_mod = _import('topo.%s'%mod,'projfn')
788 module_redirect('projfns',_import('topo',mod),existing_mod,parent_name='topo.%s'%mod)
789 module_redirect('projfns',_import('topo',mod+'s'),existing_mod,parent_name='topo.%ss'%mod)
790
791 S.append(renamed_projfns)
798
799 S.append(removed_numbergenerator)
806
807 S.append(renamed_numbergenerators)
813
814 S.append(renamed_patternfns)
817 import topo.misc.util
818
819 class ExtraPicklerSkipper(object):
820 def __setstate__(self,state):
821
822 pass
823 topo.misc.util.ExtraPickler=ExtraPicklerSkipper
824
825 S.append(removed_ExtraPickler)
831
832 S.append(renamed_utils)
838
839 S.append(renamed_traces)
851 topo.pattern.basic.SineGratingDisk = SineGratingDisk
852 S.append(duplicate_SineGratingDisk)
858
859 import topo.pattern
860 code = \
861 """
862 from topo.pattern.basic import SineGrating,Disk,Rectangle,Ring
863 from topo import param
864 class SineGratingDisk(SineGrating):
865 mask_shape = param.Parameter(default=Disk(smoothing=0,size=1.0))
866
867 class SineGratingRectangle(SineGrating):
868 mask_shape = param.Parameter(default=Rectangle(smoothing=0,size=1.0))
869
870 class SineGratingRing(SineGrating):
871 mask_shape = param.Parameter(default=Ring(smoothing=0,size=1.0))
872 """
873 fake_a_module('teststimuli',code,parent=topo.pattern)
874
875 S.append(teststimuli_removed)
883
884 S.append(moved_homeostatic)
890
891 S.append(renamed_cfproj_weights_shape)
894
895
896
897
898 def cf_bounds_property(instance,state):
899 try:
900 del state['bounds']
901 except KeyError:
902 pass
903
904 from topo.base.cf import ConnectionField
905 preprocess_state(ConnectionField,cf_bounds_property)
906
907 S.append(cf_bounds_readonly)
918
919 from topo import param
920 def _param_add_allow_None(instance,state):
921 if 'allow_None' not in state and hasattr(instance.__class__,'allow_None'):
922
923
924 state['allow_None']=False
925 preprocess_state(param.Parameter,_param_add_allow_None)
926
927 S.append(param_add_allow_None)
930
931 from topo import param
932 def _number_add_inclusive_bounds(instance,state):
933 if 'inclusive_bounds' not in state:
934 state['inclusive_bounds']=(True,True)
935 preprocess_state(param.Number,_number_add_inclusive_bounds)
936
937 S.append(number_add_inclusive_bounds)
946 S.append(onedpowerspectrum_was_in_basic)
950 import topo.base.boundingregion
951
952 def _boundingregion_not_parameterized(instance,state):
953 for a in ['initialized', '_name_param_value', 'nopickle']:
954 if a in state:
955 del state[a]
956
957 preprocess_state(topo.base.boundingregion.BoundingRegion,
958 _boundingregion_not_parameterized)
959
960 S.append(boundingregion_not_parameterized)
961
962
963 cf_xy_warned=False
995
996
997 preprocess_state(ConnectionField,_cf_not_parameterized)
998
999 S.append(cf_not_parameterized)
1012
1013 preprocess_state(CFProjection,_cfproj_add_flatcfs)
1014
1015 S.append(cfproj_add_flatcfs)
1019
1020
1021 from topo.base.cf import CFProjection
1022
1023 def get_n_units(self):
1024 try:
1025 return self.__dict__['n_units']
1026 except KeyError:
1027 n = self._calc_n_units()
1028 self.__dict__['n_units'] = n
1029
1030 def set_n_units(self,n):
1031 self.__dict__['n_units'] = n
1032
1033 type.__setattr__(CFProjection,'n_units',property(get_n_units,set_n_units))
1034
1035
1036 S.append(cfproj_add_n_units)
1046
1047 S.append(transferfn_misc)
1053
1054 S.append(renamed_pylabplots)
1055