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: