On Sun, 12 Jun 2005, James Graham wrote:
Right, there's a patch attached that should make settings use QSettings.
It might not be ideal (the design principle was "touch as few files as
possible" rather than "create the best interface possible"). There is
probably more goodness to squeeze out of QSettings (the existing interface
does have the nice property of being quite pythonic though). Safer
serialization
might also be nice... (though I guess not actually that important).
Thanks James. I've implemented a patch based on your code.
I've taken the opportunity to do some code clean ups. There didn't seem
any point having two objects. settingdb['foo'] is now used instead of
settingdb.database['foo']. I've gone round and changed all the references.
I also read the settings into a dict at startup, and write them out on
exit (removing those removed). The QSettings docs give warnings about not
writing from two apps at once, so I think this change helps. There are
still potential corruption issues here - goodness why Qt can't do locking
- maybe this is fixed in Qt 4.
I think I remember why I used my own code the first time around. I could
implement having settings which overrode master settings (in /etc). The
new code writes out all the settings to the user's dot file, and so you
can't later change the default setting in /etc if the user has run the
program.
I can't see any way around this using QSettings (unless I manually read in
each file, if the system is unix). It's probably not that important as I
doubt sysadmins want to change default settings.
Jamie - can you try out the new code in cvs on Windows??
Thanks
Jeremy
--
Jeremy Sanders <[EMAIL PROTECTED]>
http://www.jeremysanders.net/ Cambridge, UK
Public Key Server PGP Key ID: E1AAE053
# Copyright (C) 2005 Jeremy S. Sanders
# Email: Jeremy Sanders <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
###############################################################################
# $Id: settingdb.py,v 1.4 2005/06/12 17:12:45 jeremysanders Exp $
"""A database for default values of settings."""
import sys
import os
import os.path
import atexit
import qt
class _SettingDB(object):
"""A class which provides access to a persistant settings database.
Items are accesses as a dict, with items as key=value
"""
def __init__(self):
"""Initialise the object, reading the settings."""
# This domain name is fictional!
self.domain = 'veusz.org'
self.product = 'veusz'
self.database = {}
self.removedsettings = []
# read settings using QSettings
self.readSettings()
# Import old settings
if 'importPerformed' not in self.database:
self.database['importPerformed'] = True
oldsettings = _OldSettingDB()
if oldsettings.filefound:
self.database.update( oldsettings.database )
print ("Imported settings from $HOME/.veusz.def "
"and /etc/veusz.conf")
def readSettings(self):
"""Read the settings using QSettings."""
s = qt.QSettings()
s.setPath(self.domain, self.product)
path = '/%s/%s' % (self.domain, self.product)
# read each entry, keeping track of what has been read
for key in s.entryList(path):
key = unicode(key)
val, ok = s.readEntry( '%s/%s' % (path, key) )
assert ok
try:
self.database[key] = eval(unicode(val))
except:
print >>sys.stderr, ('Error interpreting item "%s" in '
'settings file' % key)
def writeSettings(self):
"""Write the settings using QSettings.
This is called by the atexit handler below
"""
s = qt.QSettings()
s.setPath(self.domain, self.product)
path = '/%s/%s' % (self.domain, self.product)
# write each entry, keeping track of which ones haven't been written
for key, value in self.database.iteritems():
if not s.writeEntry('%s/%s' % (path, key), repr(value)):
print >>sys.stderr, 'Error writing setting "%s"' % key
# now remove all the values which have been removed
for key in self.removedsettings:
if not s.removeEntry( '%s/%s' % (path, key) ):
print >>sys.stderr, 'Error removing setting "%s"' % key
def __getitem__(self, key):
"""Get the item from the database."""
return self.database[key]
def __setitem__(self, key, value):
"""Set the value in the database."""
self.database[key] = value
def __delitem__(self, key):
"""Remove the key from the database."""
del self.database[key]
self.removedsettings.append(key)
def __contains__(self, key):
"""Is the key in the database."""
return key in self.database
class _OldSettingDB:
"""A singleton class to handle the settings file.
Reads the settings file on activation, and updates the settings
file on destruction.
"""
def __init__(self):
"""Read the default settings.
This reads the settings from a global configuration file,
and then from a user configuration file.
FIXME: Unix specific, fix for other OS."""
self.systemdefaultfile = '/etc/veusz.conf'
try:
self.userdefaultfile = os.path.join(os.environ['HOME'],
'.veusz.def')
except KeyError:
self.userdefaultfile = ''
self.database = {}
# Unix specific (this is why we moved to QSettings)
defaults = self.importFile(self.systemdefaultfile)
self.sysdefaults = self.database.copy()
user = self.importFile(self.userdefaultfile)
# Did we manage to find either settings file?
self.filefound = (defaults or user)
def importFile(self, filename):
"""Read in a configuration file made up of a=b strings."""
try:
f = open(filename, 'r')
except IOError:
# no error if the file does not exist
return False
for l in f:
l = l.strip()
# ignore comment and blank lines
if len(l) == 0 or l[0] == '#':
continue
# lines should be A=B
pos = l.find('=')
# in case of error
if pos == -1:
sys.stderr.write('Error in configuration file "%s", '
'line is:\n>>>%s<<<\n' % (filename, l))
continue
key = l[:pos].strip()
val = l[pos+1:].strip()
self.database[key] = eval(val)
return True
# create the SettingDB singleton
settingdb = _SettingDB()
# write out settings at exit
atexit.register(settingdb.writeSettings)