Sunday, December 21, 2008

Preference class (beta)

===BETA VERSION===

I made a generic preference (or config) data class. It is designed to hold system wide preference data. It has a flag "isPrefValueChanged" flag which is set when a preference is added/deleted/modified, and reset when it is saved/loaded. All the property data must be picklable.



You can set/get/delete preference attributes directly.
Direct data setting to a property will set isPrefValueChanged flag.

In addition there are four method.

isPrefValueChanged(self):
Return true if preference has been changed or not saved.

savePreference(self, filename):
Save preferences to a file. isPrefValueChanged flag will be reset.

loadPreference(self, filename):
Load preferences from a file. isPrefValueChanged flag will be reset.

getPreferences(self):
Get preference data in a {preference name : value} dictionary.
It returns a deep copy of the preference data. Changing a value will not modify
the preference value held in this object.




import copy
import cPickle as pickle

class PreferenceHolder(object):
"""System wide preference holder class.
"""

def __init__(self, *args, **kwargs):
self.__dict__['_pa'] = pa = type("", (), {})() #Private attributes
pa.hcls = hcls = type("", (), {})
pa.hobj = hcls()
pa.isPrefValueChanged = True
pa.filename = ''
for name, value in kwargs.items():
setattr(self, name, value)

def __setattr__(self, name, value):
pa = self._pa
if not hasattr(pa.hcls, name):
privatename = '__' + name
def getvalue(self):
return getattr(self, privatename)
def setvalue(self, value):
setattr(self, privatename, value)
def delvalue(self):
delattr(self, privatename)
p = property(getvalue, setvalue, delvalue)
setattr(pa.hcls, name, p)

setattr(pa.hobj, name, value)
pa.isPrefValueChanged = True

def __getattr__(self, name):
return getattr(self._pa.hobj, name)

def __delattr__(self, name):
pa = self._pa
delattr(pa.hobj, name)
delattr(pa.hcls, name)
pa.isPrefValueChanged = True

def isPrefValueChanged(self):
"""Return true if preference has been changed or not saved.
"""
return self._pa.isPrefValueChanged

def getPreferences(self):
"""Get preference data in a {preference name : value} dictionary.
It returns a deep copy of the preference data. Changing a value will not modify
the preference value held in this object.
"""
result = {}
for name in [n for n in dir(self._pa.hcls) if n[0] != '_']:
result[name] = getattr(self, copy.deepcopy(name))
return result

def savePreference(self, filename):
"""Save preferences to a file. isPrefValueChanged flag will be reset.
"""
pa = self._pa
if filename == pa.filename and not self.isPrefValueChanged():
return

try:
fileobject = open(filename, 'w')
pickle.dump(self.getPreferences(), fileobject)
pa.isPrefValueChanged = False
pa.filename = filename
finally:
fileobject.close()

def loadPreference(self, filename):
"""Load preferences from a file. isPrefValueChanged flag will be reset.
"""
pa = self._pa
try:
fileobject = open(filename, 'U')

for name in self.getPreferences().keys():
delattr(self, name)

savedprefholder = pickle.load(fileobject)
for name, value in savedprefholder.items():
setattr(self, name, value)
pa.isPrefValueChanged = False
pa.filename = filename
finally:
fileobject.close()

if __name__ == '__main__':
def test():
"""
>>> ph = PreferenceHolder(pref1=1.0, pref2=100, pref3='tamtam')
>>> ph.getPreferences().items()
[('pref1', 1.0), ('pref2', 100), ('pref3', 'tamtam')]
>>> ph.pref1
1.0
>>> ph._pa.isPrefValueChanged = False #Do not do it!
>>> ph.pref4 = 'new pref'
>>> ph.pref4
'new pref'
>>> ph.isPrefValueChanged()
True
>>> ph._pa.isPrefValueChanged = False #Do not do it!
>>> del ph.pref1
>>> ph.pref1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "preferenceholder.py", line 34, in __getattr__
return getattr(self._pa.hobj, name)
AttributeError: '' object has no attribute 'pref1'
>>> ph.isPrefValueChanged()
True
>>> #Tests that create files on disk
...
>>> #ph.pref1 = 1.0
>>> #ph.pref1
1.0
>>> #ph.savePreference('preffile')
>>> #ph.isPrefValueChanged()
False
>>> #ph.pref1
1.0
>>> #ph.isPrefValueChanged()
False
>>> #ph.loadPreference('preffile')
>>> #ph.isPrefValueChanged()
False
>>> #ph.pref1
1.0
"""

import doctest
doctest.run_docstring_examples(test, globals(), False, __name__)

No comments: