Module SettingsManager
[hide private]
[frames] | no frames]

Source Code for Module SettingsManager

  1  ''' 
  2  Defines a class responsible for managing the saving and loading of settings 
  3  from disk. 
  4   
  5  @var PROFILES_PATH: Path to all persisted setting for user profiles 
  6  @type PROFILES_PATH: string 
  7   
  8  @author: Peter Parente 
  9  @organization: IBM Corporation 
 10  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 11  @license: The BSD License 
 12   
 13  All rights reserved. This program and the accompanying materials are made 
 14  available under the terms of the BSD license which accompanies 
 15  this distribution, and is available at 
 16  U{http://www.opensource.org/licenses/bsd-license.php} 
 17  ''' 
 18  from AEConstants import HOME_USER, BUILTIN_PROFILES, initUserPath 
 19  from i18n import _ 
 20  import shelve, os, shutil, whichdb 
 21   
 22  # paths to parts of the settings repository 
 23  PROFILES_PATH = os.path.join(HOME_USER, 'profiles') 
 24  # make sure the profile folder is available 
 25  if initUserPath(PROFILES_PATH): 
 26    print 'created ~/.lsr/profiles' 
 27   
28 -class SettingsManager(object):
29 ''' 30 Manages the persistence of Python objects. Has methods for loading and 31 saving state under a given name in the profile under which LSR is running or 32 the profile named when the manager is instantiated. Maintains an in-memory 33 cache of some objects loaded from disk to ensure multiple calls to L{load} 34 return the same reference. 35 36 @ivar name: Name of the profile 37 @type name: string 38 @ivar profile: Path to the profile database 39 @type profile: string 40 @ivar cache: Cache of previously loaded state objects. Used to ensure all 41 references returned by L{loadState} point to the same state object. All 42 objects in this cache are persisted to disk when the manager is closed. 43 @type cache: dictionary of string : L{AEState} 44 '''
45 - def __init__(self, profile):
46 ''' 47 Stores the reference to the L{AccessEngine}. Opens the shelved data on disk 48 in the profile currently used by the L{AccessEngine}. 49 50 @param profile: Name of the profile to access using this manager. Can be 51 used to access a profile other than the one returned by 52 L{AccessEngine.AccessEngine.getProfile}. 53 @type profile: string 54 ''' 55 self.cache = {} 56 # at least one of profile or acc_eng must be specified 57 self.name = profile 58 self.profile = os.path.join(PROFILES_PATH, self.name+'.profile')
59
60 - def init(self, **kwargs):
61 '''Does nothing.''' 62 pass
63
64 - def close(self):
65 ''' 66 Persists all state in the L{cache}. 67 ''' 68 for name, state in self.cache.items(): 69 self.saveState(name, state)
70
71 - def loadStyles(self, device, default_style, style_cls):
72 ''' 73 Loads a collection of L{AEOutput.Style} objects from disk. The loaded 74 styles are not stored in the L{cache} as the singleton requirement does 75 not hold for output device styles. As a result, the styles loaded here will 76 not be automatically persisted when this object is destroyed. L{saveStyles} 77 should be invoked directly. 78 79 @param device: Output device whose style objects we're loading 80 @type device: L{AEOutput} 81 @param default_style: Instance of a default style object to be populated 82 with data 83 @type default_style: L{AEOutput.Style.Style} 84 @param style_cls: Class for constructing new styles to populate 85 @type style_cls: L{AEOutput.Style.Style} class 86 @raise KeyError: When the name is not a valid key 87 @raise OSError: When the profile file cannot be opened or read 88 ''' 89 default_data, styles_data = self.load(device.getClassName()) 90 # get the default style first 91 default_style.unserialize(default_data) 92 flyweight_styles = {} 93 for key, data in styles_data: 94 # build flyweights ontop of the default style 95 st = style_cls(default_style) 96 st.init(device) 97 st.unserialize(data) 98 flyweight_styles[key] = st 99 return flyweight_styles
100
101 - def saveStyles(self, device, default_style, other_styles):
102 ''' 103 Saves the internal data of a collection L{AEOutput.Style} objects to disk. 104 105 @param device: Output device whose style objects we're persisting 106 @type device: L{AEOutput} 107 @param default_style: Instance of a default style object to have its data 108 persisted 109 @type default_style: L{AEOutput.Style.Style} 110 @param other_styles: Dictionary of other styles to have their data 111 persisted under the keys used in the dictionary 112 @type other_styles: dictionary of immutable : 113 L{AEOutput.Style.Style} 114 @raise OSError: When the profile file cannot be opened or saved 115 ''' 116 flyweight_data = [(key, style.serialize()) for key, style in 117 other_styles.items()] 118 self.save(device.getClassName(), 119 (default_style.serialize(), flyweight_data))
120
121 - def loadState(self, name, state):
122 ''' 123 Loads an L{AEState} object from disk. If cached is True, stores a copy of 124 the state to be returned in memory such that future calls to load return 125 the same instance with the same state. 126 127 @param name: Name under which the object was previously stored 128 @type name: string 129 @param state: LSR state object to initialize with the loaded data 130 @type state: L{AEState} 131 @return: Singleton instance of the L{AEState} object for the given name 132 @rtype: L{AEState} 133 @raise KeyError: When the name is not a valid key 134 @raise OSError: When the profile file cannot be opened or read 135 ''' 136 # check the cache first 137 try: 138 return self.cache[name] 139 except KeyError: 140 pass 141 # cache the instance to ensure shared references to state 142 self.cache[name] = state 143 # try to load data for the state object 144 data = self.load(name) 145 # wrap the data in the state object 146 state.unserialize(data) 147 return state
148
149 - def saveState(self, name, state):
150 ''' 151 Saves the internal data of an L{AEState} object to disk. Does not Pickle 152 the state object directly, but rather calls its serialize method to get a 153 simple dictionary. This is done to avoid the problems caused by trying to 154 persist state objects in modules that have been reloaded at runtime. Also 155 does not Pickle states that are not dirty according to 156 L{AEState.Base.AEState.isDirty}. 157 158 @param name: Name under which to save the object 159 @type name: string 160 @param state: LSR state object whose data should be stored 161 @type state: L{AEState} 162 @raise OSError: When the profile file cannot be opened or saved 163 ''' 164 if state.isDirty(): 165 self.save(name, state.serialize())
166
167 - def save(self, name, data):
168 ''' 169 Saves the given object under the given name in the profile used to 170 initialize this manager. Pickles the given object without any further 171 processing on the part of this manager. 172 173 @param name: Name under which to save the object 174 @type name: string 175 @param data: Object to store 176 @type data: object 177 @raise OSError: When the profile file cannot be opened or saved 178 ''' 179 db = shelve.open(self.profile, protocol=-1) 180 db[name] = data 181 db.close()
182
183 - def load(self, name):
184 ''' 185 Loads the object from the profile used to initialize the manager. Unpickles 186 the object under the given name without any additional processing on the 187 part of this mananger. 188 189 @param name: Name under which the object was previously stored 190 @type name: string 191 @return: Object loaded 192 @rtype: object 193 @raise KeyError: When the name is not a valid key 194 @raise OSError: When the profile file cannot be opened or read 195 ''' 196 db = shelve.open(self.profile, protocol=-1) 197 try: 198 data = db[name] 199 finally: 200 db.close() 201 return data
202
203 - def createProfile(self):
204 ''' 205 Initializes a new profile on disk. 206 207 @raise ValueError: When the profile already exists 208 @raise OSError: When the profile file cannot be created 209 ''' 210 if self.existsProfile(): 211 raise ValueError(_('Profile %s already exists' % self.name)) 212 db = shelve.open(self.profile, protocol=-1) 213 db.close()
214
215 - def ensureProfile(self):
216 ''' 217 @raise ValueError: When the profile does not exist 218 ''' 219 if not self.existsProfile(): 220 raise ValueError(_('Profile %s does not exist') % self.name)
221
222 - def existsProfile(self):
223 ''' 224 @return: Does the managed profile exist on disk? 225 @rtype: boolean 226 ''' 227 return whichdb.whichdb(self.profile) is not None
228
229 - def deleteProfile(self):
230 ''' 231 Deletes the managed profile from disk. 232 233 @raise ValueError: When the profile is built-in and cannot be deleted or 234 the profile does not exist 235 @raise OSError: When the profile database cannot be deleted 236 ''' 237 if self.name in BUILTIN_PROFILES: 238 raise ValueError(_('Cannot remove built-in %s profile') % self.name) 239 if not self.existsProfile(): 240 raise ValueError(_('Profile %s does not exist' % self.name)) 241 os.unlink(self.profile)
242
243 - def copyProfile(self, name):
244 ''' 245 Copies this profile to another name on disk. This method overwrites the 246 destination if it already exists. 247 248 @param name: Destination profile 249 @type name: string 250 @raise ValueError: When the profile does not exist 251 @raise OSError: When the profile file cannot be copied to the destination 252 ''' 253 if not self.existsProfile(): 254 raise ValueError(_('Profile %s does not exist' % profile_name)) 255 shutil.copy(self.profile, os.path.join(PROFILES_PATH, name+'.profile'))
256 257 @classmethod
258 - def listProfiles(cls):
259 ''' 260 Gets a list of existing profile names. 261 262 @return: List of all profiles stored on disk 263 @rtype: list of string 264 ''' 265 return [name.split(os.extsep)[0] for name in os.listdir(PROFILES_PATH)]
266 267 @classmethod
268 - def hasDefaultProfiles(cls):
269 ''' 270 Gets if the L{BUILTIN_PROFILES} exist. 271 272 @return: Do the default profiles exist? 273 @rtype: boolean 274 ''' 275 profiles = cls.listProfiles() 276 for name in BUILTIN_PROFILES: 277 if name not in profiles: 278 return False 279 return True
280