Package sfc :: Package common :: Module ParameterDict
[hide private]
[frames] | no frames]

Source Code for Module sfc.common.ParameterDict

  1  #!/usr/bin/env python 
  2  """Contains the ParameterDict class, useful for defining 
  3  recursive dictionaries of parameters and using attribute 
  4  syntax for later access. 
  5   
  6  Some useful features: 
  7  - Recursive copy function of parameter subsets 
  8  - Recursive update function including parameter subsets 
  9  - Recursive indented pretty-print 
 10  - Valid parameters are declared as keyword arguments to the constructor, 
 11    and assigning to indeclared variables is not allowed. 
 12   
 13  See help(ParameterDict) for an interactive example. 
 14  """ 
 15   
 16  # Copyright (C) 2008 Martin Sandve Alnes and Simula Resarch Laboratory 
 17  # 
 18  # This file is part of SyFi. 
 19  # 
 20  # SyFi is free software: you can redistribute it and/or modify 
 21  # it under the terms of the GNU General Public License as published by 
 22  # the Free Software Foundation, either version 2 of the License, or 
 23  # (at your option) any later version. 
 24  # 
 25  # SyFi is distributed in the hope that it will be useful, 
 26  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 27  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 28  # GNU General Public License for more details. 
 29  # 
 30  # You should have received a copy of the GNU General Public License 
 31  # along with SyFi. If not, see <http://www.gnu.org/licenses/>. 
 32  # 
 33  # First added:  2008-06-22 
 34  # Last changed: 2008-06-23 
 35   
36 -class ParameterDict(dict):
37 """A dictionary with attribute-style access, 38 that maps attribute access to the real dictionary. 39 40 Interactive example: 41 >>> m = ParameterDict(Re = 1.0, f = "sin(x)") 42 >>> print m 43 Re = 1.0 44 f = 'sin(x)' 45 >>> s = ParameterDict(max_iterations = 10, tolerance = 1e-8) 46 >>> print s 47 max_iterations = 10 48 tolerance = 1e-08 49 >>> p = ParameterDict(model = m, solver = s) 50 >>> print p 51 model = { 52 Re = 1.0 53 f = 'sin(x)' 54 } 55 solver = { 56 max_iterations = 10 57 tolerance = 1e-08 58 } 59 >>> q = p.copy() 60 >>> q.model.Re = 2.3e6 61 >>> q.solver.max_iterations = 100 62 >>> print q 63 model = { 64 Re = 2300000.0 65 f = 'sin(x)' 66 } 67 solver = { 68 max_iterations = 100 69 tolerance = 1e-08 70 } 71 >>> print p 72 model = { 73 Re = 1.0 74 f = 'sin(x)' 75 } 76 solver = { 77 max_iterations = 10 78 tolerance = 1e-08 79 } 80 >>> p.update(q) 81 >>> print p 82 model = { 83 Re = 2300000.0 84 f = 'sin(x)' 85 } 86 solver = { 87 max_iterations = 100 88 tolerance = 1e-08 89 } 90 >>> s.nothere = 123 91 Traceback (most recent call last): 92 File "doctest.py", line 1212, in __run 93 compileflags, 1) in test.globs 94 File "<doctest __main__.ParameterDict[13]>", line 1, in <module> 95 s.nothere = 123 96 File "ParameterDict.py", line 107, in __setattr__ 97 raise AttributeError("%s is not an item in this parameter dict." % key) 98 AttributeError: nothere is not an item in this parameter dict. 99 """
100 - def __init__(self, **params):
101 dict.__init__(self, **params) 102 for k,v in params.iteritems(): 103 self.__setattr__(k, v)
104
105 - def __getstate__(self):
106 return self.__dict__.items()
107
108 - def __setstate__(self, items):
109 for key, val in items: 110 self.__dict__[key] = val
111
112 - def __str__(self):
113 return self.format()
114
115 - def __repr__(self):
116 return "%s(%s)" % (self.__class__.__name__, ", ".join("%s = %s" % (k,repr(dict.__getitem__(self, k))) for k in sorted(dict.iterkeys(self))))
117
118 - def __delitem__(self, key):
119 return dict.__delitem__(self, key)
120
121 - def __setattr__(self, key, value):
122 assert isinstance(key, str) 123 if dict.__contains__(self, key): 124 dict.__setitem__(self, key, value) 125 else: # TODO: Keep or drop this? 126 raise AttributeError("%s is not an item in this parameter dict." % key) 127 return dict.__setattr__(self, key, value)
128
129 - def __getattr__(self, key):
130 if not dict.__contains__(self, key): 131 raise AttributeError("%s is not an item in this parameter dict." % key) 132 return dict.__getitem__(self, key)
133
134 - def format(self, indent=None):
135 "Make a recursive indented pretty-print string of self and parameter subsets." 136 value_formatter = repr 137 if indent is None: 138 indent = 0 139 s = "" 140 for k in sorted(dict.iterkeys(self)): 141 v = getattr(self, k) 142 if isinstance(v, self.__class__): 143 s += " "*indent + "%s = {\n" % k 144 s += v.format(indent+1) 145 s += "\n" + " "*indent + "}\n" 146 else: 147 s += " "*indent + "%s = %s\n" % (k, value_formatter(v)) 148 return s[:-1]
149
150 - def copy(self):
151 """Make a copy of self, including recursive copying of parameter subsets. 152 Parameter values themselves are not copied.""" 153 # TODO: Make this an external function to handle recursive dicts... 154 items = {} 155 for k in dict.iterkeys(self): 156 v = getattr(self, k) 157 if isinstance(v, dict): #self.__class__): 158 items[k] = v.copy() 159 else: 160 items[k] = v 161 ch = ParameterDict(**items) 162 return ch
163
164 - def update(self, other):
165 "A recursive update that handles parameter subsets correctly unlike dict.update." 166 # TODO: Make this an external function to handle recursive dicts... 167 for k in dict.iterkeys(other): 168 sv = getattr(self, k) 169 ov = getattr(other, k) 170 if isinstance(sv, dict): #self.__class__): 171 # Update my own subdict with others subdict 172 sv.update(ov) 173 else: 174 # Set my own value to others value 175 setattr(self, k, ov)
176 177 178 # Test code 179 if __name__ == "__main__": 180
181 - def default_a():
182 p = ParameterDict(abla=123, abli="sin") 183 return p
184
185 - def default_b():
186 p = ParameterDict(bblal=987, bling="akjh") 187 return p
188
189 - def default_params():
190 p = ParameterDict(something = 3, 191 other = .1239, 192 a = default_a(), 193 b = default_b() 194 ) 195 return p
196 197 # Get a defined set of parameters 198 p = default_params() 199 200 # Test parameter setting 201 p.something = 9 202 p.other = "8134" 203 204 # Test parameter setting exceptions 205 try: 206 p.blatti = 7 207 raise RuntimeError("Failed to throw exception on erroneous parameter assignment.") 208 except: 209 pass 210 211 # Test iteration: 212 for k in p.keys(): 213 print k 214 for k in p.iterkeys(): 215 print k 216 for v in p.values(): 217 print v 218 for v in p.itervalues(): 219 print v 220 for k,v in p.items(): 221 print k,v 222 for k,v in p.iteritems(): 223 print k,v 224 225 # Test random access: 226 ap1 = p.a 227 ap2 = p["a"] 228 assert ap1 is ap2 229 230 # Test printing of parameter set 231 print 232 print "str(p):" 233 print str(p) 234 print 235 print "repr(p):" 236 print repr(p) 237 print 238 239 # Test copy 240 q = p.copy() 241 q.something = "q specific!" 242 q.a.abla = "q.a specific!" 243 print 244 print "Should be different:" 245 print repr(p) 246 print repr(q) 247 248 # Test update 249 p.update(q) 250 print 251 print "Should be equal:" 252 print repr(q) 253 print repr(p) 254 255 # Test indented formatting: 256 print 257 print q.format() 258 259 print p 260 261 # Run doctest
262 -def _test():
263 import doctest 264 doctest.testmod()
265 if __name__ == "__main__": 266 _test() 267