Package AccessEngine :: Package AEState :: Module Base
[hide private]
[frames] | no frames]

Source Code for Module AccessEngine.AEState.Base

  1  ''' 
  2  Defines an abstract base class for all persistent and/or configurable setting 
  3  classes. 
  4   
  5  @author: Peter Parente 
  6  @organization: IBM Corporation 
  7  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
  8   
  9  @license: I{The BSD License} 
 10  All rights reserved. This program and the accompanying materials are made 
 11  available under the terms of the BSD license which accompanies 
 12  this distribution, and is available at 
 13  U{http://www.opensource.org/licenses/bsd-license.php} 
 14  ''' 
 15   
 16  from Setting import * 
 17   
18 -def _uuid():
19 ''' 20 Generate a new unique identifier to help in comparison of L{AEState} copies. 21 22 @return: Unique ID 23 @rtype: integer 24 ''' 25 i = 0 26 while 1: 27 yield i 28 i += 1
29 uuid = _uuid() 30
31 -class AEState(object):
32 ''' 33 Abstract base class for objects containing data that will have their data 34 serialized to disk or configured by the user. All new* methods construct 35 L{Setting} objects which contain metadata describing setting values for the 36 purpose of checking bounds, generating configuration dialogs, etc. 37 38 All subclasses of L{AEState} should override L{init} and L{getGroups}. The 39 init method should be used to create new settings and initialize non-setting 40 instance variables. The overriden init does not need to invoke any base class 41 init methods to create inherited settings. All baser class settings are 42 created in the __init__ constructor instead. The getGroups method should 43 call L{newGroup} to create group objects containing the names of related 44 settings to aid the generation of configuration dialogs. Group objects 45 themselves also have newGroup methods to support nested groupings. 46 47 Two attribute names are reserved by L{AEState} objects. L{settings} is the 48 dictionary containing all L{Setting} instances. L{dirty} is a set that 49 stores the names of settings that have been modified in the current instance. 50 The list is automatically reset when the instance is persisted. The 51 L{isDirty}, L{makeClean}, L{iterDirty} methods may be used to check if any 52 part of the state is dirty, clear the list of dirty attributes, and iterate 53 over the names and values of the dirty attributes to enable optimization at 54 higher levels. 55 56 Note that the L{AEState} object itself is not designed to be persisted to 57 disk, but rather to act as a delegate for settings to be persisted. The 58 reason for this is that not all persistence mechanisms can support the 59 serialization of Python objects. 60 61 @ivar dirty: Set of dirty attribute names in this state object 62 @type dirty: set 63 @ivar settings: Dictionary of named L{Setting} objects 64 @type settings: dictionary 65 @ivar ident: Unique ID for this state object which is given to all copies 66 @type ident: integer 67 '''
68 - def __init__(self):
69 ''' 70 Initialize the dirty set and settings dict. 71 ''' 72 # special init to avoid call to __setattr__ 73 self.__dict__['settings'] = {} 74 self.__dict__['dirty'] = set() 75 self.__dict__['ident'] = uuid.next()
76
77 - def init(self):
78 ''' 79 Does nothing by default. Use to create settings after instantiation. 80 ''' 81 pass
82
83 - def getGroups(self):
84 ''' 85 Gets the root L{Setting.Group} object and all of its child L{Setting} names 86 and nested groups. 87 88 @raise NotImplementedError: When not overridden in a subclass, indicating 89 configuration is not supported 90 ''' 91 raise NotImplementedError
92
93 - def __eq__(self, other):
94 ''' 95 Compares two state objects for equality based on their attributes. 96 97 @param other: Another state object 98 @type other: L{AEState} 99 ''' 100 try: 101 return self.ident == other.ident 102 except Exception: 103 return False
104
105 - def __ne__(self, other):
106 ''' 107 Compares two state objects for inequality based on their attributes. 108 109 @param other: Another state object 110 @type other: L{AEState} 111 ''' 112 return not self.__eq__(other)
113
114 - def copy(self):
115 ''' 116 Makes a copy of this state object and all of its L{Setting}s. 117 ''' 118 c = self.__class__() 119 c.dirty = self.dirty 120 c.ident = self.ident 121 for name, val in self.settings.items(): 122 c.settings[name] = val.copy() 123 return c
124
125 - def addSetting(self, setting):
126 ''' 127 Adds a copy of an existing setting to this state object under the same 128 name. 129 130 @param setting: Existing setting to copy and store 131 @type setting: L{Setting} 132 ''' 133 self.settings[setting.name] = setting.copy()
134
135 - def newGroup(self, label=None):
136 ''' 137 Builds a new L{Group} object relating settings. The group is not stored 138 internally, just returned for temporary use by another object. 139 140 @param label: Label for the new L{Group} 141 @type label: string 142 ''' 143 return Group(self, label)
144
145 - def newString(self, name, default, label, description='', persist=True):
146 ''' 147 Adds a new L{StringSetting} to this group. 148 149 @param name: New name of the setting 150 @type name: string 151 @param default: Default value of the setting 152 @type default: string 153 @param label: Label for the new L{Setting} 154 @type label: string 155 @param description: Extended description of the L{Setting} 156 @type description: string 157 @param persist: Persist the setting value to disk? 158 @type persist: boolean 159 @return: New setting object 160 @rtype: L{StringSetting} 161 ''' 162 s = StringSetting(self, name, default, label, description, persist) 163 self.settings[name] = s 164 return s
165
166 - def newFilename(self, name, default, label, relative_path, description='', 167 persist=True):
168 ''' 169 Adds a new L{FilenameSetting} to this group. 170 171 @param name: New name of the setting 172 @type name: string 173 @param default: Default value of the setting 174 @type default: string 175 @param label: Label for the new L{Setting} 176 @type label: string 177 @param relative_path: Absolute path to which '.' or a filename with no 178 path refers 179 @type relative_path: string 180 @param description: Extended description of the L{Setting} 181 @type description: string 182 @param persist: Persist the setting value to disk? 183 @type persist: boolean 184 @return: New setting object 185 @rtype: L{FilenameSetting} 186 ''' 187 relative_path = os.path.realpath(relative_path) 188 if os.path.isfile(relative_path): 189 relative_path = os.path.dirname(relative_path) 190 s = FilenameSetting(self, name, default, label, description, persist, 191 relative_path) 192 self.settings[name] = s 193 return s
194
195 - def newBool(self, name, default, label, description='', persist=True):
196 ''' 197 Adds a new L{BoolSetting} to this group. 198 199 @param name: New name of the setting 200 @type name: string 201 @param default: Default value of the setting 202 @type default: boolean 203 @param label: Label for the new L{Setting} 204 @type label: string 205 @param description: Extended description of the L{Setting} 206 @type description: string 207 @param persist: Persist the setting value to disk? 208 @type persist: boolean 209 @return: New setting object 210 @rtype: L{BoolSetting} 211 ''' 212 s = BoolSetting(self, name, default, label, description, persist) 213 self.settings[name] = s 214 return s
215
216 - def newNumeric(self, name, default, label, min, max, precision, 217 description='', persist=True):
218 ''' 219 Adds a new L{NumericSetting} to this group. 220 221 @param name: New name of the setting 222 @type name: string 223 @param default: Default value of the setting 224 @type default: float 225 @param label: Label for the new L{Setting} 226 @type label: string 227 @param min: Minimum value in the range 228 @type min: number 229 @param max: Maximum value in the range 230 @type max: number 231 @param precision: Number of decimal places 232 @type precision: integer 233 @param description: Extended description of the L{Setting} 234 @type description: string 235 @param persist: Persist the setting value to disk? 236 @type persist: boolean 237 @return: New setting object 238 @rtype: L{NumericSetting} 239 ''' 240 s = NumericSetting(self, name, default, label, description, persist, min, 241 max, precision) 242 self.settings[name] = s 243 return s
244
245 - def newRange(self, name, default, label, min, max, precision, description='', 246 persist=True):
247 ''' 248 Adds a new L{RangeSetting} to this group. 249 250 @param name: New name of the setting 251 @type name: string 252 @param default: Default value of the setting 253 @type default: float 254 @param label: Label for the new L{Setting} 255 @type label: string 256 @param min: Minimum value in the range 257 @type min: number 258 @param max: Maximum value in the range 259 @type max: number 260 @param precision: Number of decimal places 261 @type precision: integer 262 @param description: Extended description of the L{Setting} 263 @type description: string 264 @param persist: Persist the setting value to disk? 265 @type persist: boolean 266 @return: New setting object 267 @rtype: L{RangeSetting} 268 ''' 269 s = RangeSetting(self, name, default, label, description, persist, min, 270 max, precision) 271 self.settings[name] = s 272 return s
273
274 - def newPercent(self, name, default, label, min, max, precision, 275 description='', persist=True):
276 ''' 277 Adds a new L{PercentRangeSetting} to this group. 278 279 @param name: New name of the setting 280 @type name: string 281 @param default: Default value of the setting 282 @type default: float 283 @param label: Label for the new L{Setting} 284 @type label: string 285 @param min: Minimum value in the range to be shown as 0% 286 @type min: number 287 @param max: Maximum value in the range to be shown as 100% 288 @type max: number 289 @param precision: Number of decimal places 290 @type precision: integer 291 @param description: Extended description of the L{Setting} 292 @type description: string 293 @param persist: Persist the setting value to disk? 294 @type persist: boolean 295 @return: New setting object 296 @rtype: L{PercentRangeSetting} 297 ''' 298 s = PercentRangeSetting(self, name, default, label, description, persist, 299 min, max, precision) 300 self.settings[name] = s 301 return s
302
303 - def newChoice(self, name, default, label, choices, description='', 304 persist=True):
305 ''' 306 Adds a new L{ChoiceSetting} to this group. 307 308 @param name: New name of the setting 309 @type name: string 310 @param default: Default value of the setting 311 @type default: string 312 @param label: Label for the new L{Setting} 313 @type label: string 314 @param choices: Collection of choices 315 @type choices: list 316 @param description: Extended description of the L{Setting} 317 @type description: string 318 @param persist: Persist the setting value to disk? 319 @type persist: boolean 320 @return: New setting object 321 @rtype: L{ChoiceSetting} 322 ''' 323 s = ChoiceSetting(self, name, default, label, description, persist, 324 choices) 325 self.settings[name] = s 326 return s
327
328 - def newColor(self, name, default, label, description='', persist=True):
329 ''' 330 Adds a new L{ColorSetting} to this group. 331 332 @param name: New name of the setting 333 @type name: string 334 @param default: Default value of the setting 335 @type default: 3 or 4-tuple of integer 336 @param label: Label for the new L{Setting} 337 @type label: string 338 @param description: Extended description of the L{Setting} 339 @type description: string 340 @param persist: Persist the setting value to disk? 341 @type persist: boolean 342 @return: New setting object 343 @rtype: L{ColorSetting} 344 ''' 345 s = ColorSetting(self, name, default, label, description, persist) 346 self.settings[name] = s 347 return s
348
349 - def newEnum(self, name, default, label, choices, description='', 350 persist=True):
351 ''' 352 Adds a new L{EnumSetting} to this group. 353 354 @param name: New name of the setting 355 @type name: string 356 @param default: Default value of the setting 357 @type default: integer 358 @param label: Label for the new L{Setting} 359 @type label: string 360 @param choices: Collection of choices mapped to the values they represent 361 @type choices: dictionary 362 @param description: Extended description of the L{Setting} 363 @type description: string 364 @param persist: Persist the setting value to disk? 365 @type persist: boolean 366 @return: New setting object 367 @rtype: L{EnumSetting} 368 ''' 369 s = EnumSetting(self, name, default, label, description, persist, choices) 370 self.settings[name] = s 371 return s
372
373 - def __setattr__(self, name, val):
374 ''' 375 Stores a setting value if the setting is already defined by the give name 376 or an instance attribute if the name doesn't not define a setting. 377 Provided for convenience over using L{setSettingVal}. 378 379 @param name: Name of the setting or instance attribute 380 @type name: string 381 @param val: Arbitrary value to store 382 @type val: object 383 ''' 384 try: 385 self.__dict__['settings'][name].value = val 386 except KeyError: 387 self.__dict__[name] = val
388
389 - def __getattr__(self, name):
390 ''' 391 Gets a setting value if the setting is already defined by the give name 392 or an instance attribute if the name doesn't not define a setting. 393 Provided for convenience over using L{getSettingVal}. 394 395 @param name: Name of the setting or instance attribute 396 @type name: string 397 @return: Arbitrary value to get 398 @rtype: object 399 @raise AttributeError: When the name does not define a setting or instance 400 attribute 401 ''' 402 try: 403 # try to fetch a setting first 404 return self.__dict__['settings'][name].value 405 except KeyError: 406 pass 407 try: 408 # then try to fetch an instance attribute 409 return self.__dict__[name] 410 except KeyError: 411 raise AttributeError("'%s' object has no attribute '%s'" % 412 (self.__class__.__name__, name))
413
414 - def save(self):
415 '''Invokes L{Setting.Setting.save} on all settings in the state.''' 416 for sett in self.settings.values(): 417 sett.save()
418
419 - def restore(self):
420 '''Invokes L{Setting.Setting.restore} on all settings in the state.''' 421 for sett in self.settings.values(): 422 sett.restore()
423
424 - def hasSetting(self, name):
425 ''' 426 Gets if this object has a setting with the given name. 427 428 @param name: Name of the setting 429 @type name: string 430 @return: Has the setting or not? 431 @rtype: boolean 432 ''' 433 return self.settings.has_key(name)
434
435 - def getSettingObj(self, name):
436 ''' 437 Retrieves the L{Setting} object with the given name. 438 439 @param name: Name of the setting 440 @type name: string 441 @return: The named setting object 442 @rtype: L{Setting} 443 @raise KeyError: When a L{Setting} with the given name is not defined 444 ''' 445 return self.settings[name]
446
447 - def getSettingVal(self, name):
448 ''' 449 Convenience method for getting the value of a L{Setting} object. 450 451 @param name: Name of the setting 452 @type name: string 453 @return: Current value of a setting 454 @rtype: object 455 @raise KeyError: When a L{Setting} with the given name is not defined 456 ''' 457 return self.settings[name].value
458
459 - def setSettingVal(self, name, val):
460 ''' 461 Convenience method for setting the value of a L{Setting} object. 462 463 @param name: Name of the setting 464 @type name: string 465 @param val: Value to store 466 @type val: object 467 @raise KeyError: When a L{Setting} with the given name is not defined 468 ''' 469 self.settings[name].value = val
470
471 - def serialize(self):
472 ''' 473 Grabs all L{Setting} values and stores them in a dictionary keyed by 474 setting name. Invokes L{restore} first to ensure only user accepted values 475 are persisted. 476 477 @return: Mapping from setting names to values 478 @rtype: dictionary 479 ''' 480 self.restore() 481 return dict([(name, sett.serialize()) for name, sett in 482 self.settings.items() if sett.persist])
483
484 - def unserialize(self, data):
485 ''' 486 Stores all L{Setting} values given a dictionary mapping setting names to 487 values. Ignores names in the dictionary that do not exist in L{settings}. 488 489 @param data: Mapping from setting names to values 490 @type data: dictionary 491 ''' 492 for name, value in data.items(): 493 try: 494 self.settings[name].unserialize(value) 495 except KeyError: 496 # nice! filters out old settings that are no longer defined 497 pass
498
499 - def isDirty(self):
500 ''' 501 Gets if values in L{settings} have changed since the last call to 502 L{makeClean}. 503 504 @return: Dirty or not? 505 @rtype: boolean 506 ''' 507 return len(self.dirty) > 0
508
509 - def makeClean(self):
510 ''' 511 Resets the dirty set to empty. 512 ''' 513 self.dirty = set()
514
515 - def _makeDirty(self, state, setting):
516 ''' 517 Adds the given setting name to the dirty set. 518 519 @param state: State object to which the setting is attached 520 @type state: weakref.proxy to L{AEState} 521 @param setting: Setting that changed value 522 @type setting: L{Setting} 523 ''' 524 self.dirty.add(setting.name)
525
526 - def iterDirty(self):
527 ''' 528 Iterates over all of the names in L{dirty} in no particular order. 529 530 @return: Name of a dirty setting 531 @rtype: string 532 ''' 533 for name in self.dirty: 534 yield name
535
536 - def __iter__(self):
537 ''' 538 Iterates over all of the setting objects in L{settings} 539 in no particular order. 540 541 @return: A setting 542 @rtype: L{Setting} 543 ''' 544 for setting in self.settings.values(): 545 yield setting
546