Moved configmanager code to gen/utils so other parts of gramps can use configman
svn: r13874
This commit is contained in:
parent
1fdb6c4b2c
commit
7558a4b8de
386
src/config.py
386
src/config.py
@ -29,31 +29,19 @@ This package implements access to GRAMPS configuration.
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# System imports
|
||||
# Gramps imports
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import ConfigParser
|
||||
import errno
|
||||
from gettext import gettext as _
|
||||
|
||||
try:
|
||||
from ast import literal_eval as safe_eval
|
||||
except:
|
||||
# PYTHON2.5 COMPATIBILITY: no ast present
|
||||
# not as safe as literal_eval, but works for python2.5:
|
||||
def safe_eval(exp):
|
||||
# restrict eval to empty environment
|
||||
return eval(exp, {})
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# Gramps imports
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
import const
|
||||
from gen.utils import ConfigManager
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
@ -64,377 +52,9 @@ INIFILE = os.path.join(const.HOME_DIR, "gramps32.ini")
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# Classes
|
||||
# Module functions
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
class ConfigManager(object):
|
||||
"""
|
||||
Class to construct the singleton CONFIGMAN where all
|
||||
settings are stored.
|
||||
"""
|
||||
def __init__(self, filename = None):
|
||||
"""
|
||||
Configure manager constructor takes an optional filename.
|
||||
|
||||
The data dictionary stores the settings:
|
||||
|
||||
self.data[section][setting] = value
|
||||
|
||||
The value has a type that matches the default. It is an error
|
||||
to attempt to set the setting to a different type. To change
|
||||
the type, you must re-register the setting, and re-set the
|
||||
value. Values can be any simple type in Python (except,
|
||||
currently longs, which are saved as ints to avoid type
|
||||
errors). This includes: str, int, list, tuple, dict, float,
|
||||
etc. Of course, composite types must themselves be composed of
|
||||
simple types.
|
||||
|
||||
The default values are given in Python code and stored here
|
||||
on start-up:
|
||||
|
||||
self.default[section][setting] = default_value
|
||||
|
||||
Callbacks are stored as callables here:
|
||||
|
||||
self.callbacks[section][setting] = (id, func)
|
||||
|
||||
The default filename (usually the one you are reading from)
|
||||
is stored as self.filename. However, you can save to another
|
||||
filename using self.save(otherfilename).
|
||||
"""
|
||||
self._cb_id = 0 # callback id counter
|
||||
self.filename = filename
|
||||
self.callbacks = {}
|
||||
self.default = {}
|
||||
self.data = {}
|
||||
self.reset()
|
||||
|
||||
def __getitem__(self, item):
|
||||
"""
|
||||
For item access, such as config["interface.dont-ask"]
|
||||
"""
|
||||
return self.get(item)
|
||||
|
||||
def __setitem__(self, item, value):
|
||||
"""
|
||||
For item assignment, such as config["interface.dont-ask"] = True
|
||||
"""
|
||||
self.set(item, value)
|
||||
|
||||
def reset(self, key=None):
|
||||
"""
|
||||
Resets one, a section, or all settings values to their defaults.
|
||||
This does not disconnect callbacks.
|
||||
"""
|
||||
if key is None:
|
||||
section = None
|
||||
setting = None
|
||||
elif "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else: # key is not None and doesn't have a "."
|
||||
section = key
|
||||
setting = None
|
||||
# Now, do the reset on the right parts:
|
||||
if section is None:
|
||||
self.data = {}
|
||||
for section in self.default:
|
||||
self.data[section] = {}
|
||||
for setting in self.default[section]:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
elif setting is None:
|
||||
self.data[section] = {}
|
||||
for setting in self.default[section]:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
else:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
# Callbacks are still connected
|
||||
|
||||
def get_sections(self):
|
||||
"""
|
||||
Return all section names.
|
||||
"""
|
||||
return self.data.keys()
|
||||
|
||||
def get_section_settings(self, section):
|
||||
"""
|
||||
Return all section setting names.
|
||||
"""
|
||||
return self.data[section].keys()
|
||||
|
||||
def load(self, filename=None, oldstyle=False):
|
||||
"""
|
||||
Loads an .ini into self.data.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
if filename and os.path.exists(filename):
|
||||
parser = ConfigParser.RawConfigParser()
|
||||
parser.read(filename)
|
||||
for sec in parser.sections():
|
||||
name = sec.lower()
|
||||
if name not in self.data:
|
||||
# Add the setting from file
|
||||
# These might be old settings, or third-party settings
|
||||
self.data[name] = {}
|
||||
for opt in parser.options(sec):
|
||||
raw_value = parser.get(sec, opt).strip()
|
||||
setting = opt.lower()
|
||||
if oldstyle:
|
||||
####################### Upgrade from oldstyle < 3.2
|
||||
# Oldstyle didn't mark setting type, but had it
|
||||
# set in preferences. New style gets it from evaling
|
||||
# the setting's value
|
||||
#######################
|
||||
# if we know this setting, convert type
|
||||
key = "%s.%s" % (name, setting)
|
||||
if self.has_default(key):
|
||||
vtype = type(self.get_default(key))
|
||||
if vtype == bool:
|
||||
value = raw_value in ["1", "True"]
|
||||
elif vtype == list:
|
||||
print >> sys.stderr, "WARNING: ignoring old key '%s'" % key
|
||||
continue # there were no lists in oldstyle
|
||||
else:
|
||||
value = vtype(raw_value)
|
||||
else:
|
||||
# else, ignore it
|
||||
print >> sys.stderr, "WARNING: ignoring old key '%s'" % key
|
||||
continue # with next setting
|
||||
####################### End upgrade code
|
||||
else:
|
||||
value = safe_eval(raw_value)
|
||||
####################### Now, let's test and set:
|
||||
if (name in self.default and
|
||||
setting in self.default[name]):
|
||||
if type(value) == type(self.default[name][setting]):
|
||||
self.data[name][setting] = value
|
||||
else:
|
||||
print >> sys.stderr, ("WARNING: ignoring key with wrong type "
|
||||
"'%s.%s'" % (name, setting))
|
||||
else:
|
||||
# this could be a third-party setting; add it:
|
||||
self.data[name][setting] = value
|
||||
|
||||
def save(self, filename = None):
|
||||
"""
|
||||
Saves the current section/settings to an .ini file. Optional filename
|
||||
will override the default filename to save to, if given.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
if filename:
|
||||
try:
|
||||
head = os.path.split( filename )[0]
|
||||
os.makedirs( head )
|
||||
except OSError, exp:
|
||||
if exp.errno != errno.EEXIST:
|
||||
raise
|
||||
key_file = open(filename, "w")
|
||||
key_file.write(";; Gramps key file\n")
|
||||
key_file.write((";; Automatically created at %s" %
|
||||
time.strftime("%Y/%m/%d %H:%M:%S")) + "\n\n")
|
||||
sections = sorted(self.data)
|
||||
for section in sections:
|
||||
key_file.write(("[%s]\n") % section)
|
||||
keys = sorted(self.data[section])
|
||||
for key in keys:
|
||||
value = self.data[section][key]
|
||||
# If it has a default:
|
||||
if self.has_default("%s.%s" % (section, key)):
|
||||
if value == self.get_default("%s.%s" % (section, key)):
|
||||
default = ";;"
|
||||
else:
|
||||
default = ""
|
||||
if isinstance(value, long):
|
||||
value = int(value)
|
||||
key_file.write(("%s%s=%s\n")% (default,
|
||||
key,
|
||||
repr(value)))
|
||||
key_file.write("\n")
|
||||
key_file.close()
|
||||
# else, no filename given; nothing to save so do nothing quietly
|
||||
|
||||
def get(self, key):
|
||||
"""
|
||||
Get the setting's value. raise an error if an invalid section.setting.
|
||||
Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
return self.data[section][setting]
|
||||
|
||||
def is_set(self, key):
|
||||
"""
|
||||
Does the setting exist? Returns True if does, False otherwise.
|
||||
Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
return False
|
||||
if section not in self.data:
|
||||
return False
|
||||
if setting not in self.data[section]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_default(self, key):
|
||||
"""
|
||||
Does the setting have a default value? Returns True if it does,
|
||||
False otherwise. Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
return False
|
||||
if section not in self.default:
|
||||
return False
|
||||
if setting not in self.default[section]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_default(self, key):
|
||||
"""
|
||||
Get the setting's default value. Raises an error if invalid key is
|
||||
give. Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.default:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.default[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
return self.default[section][setting]
|
||||
|
||||
def register(self, key, default):
|
||||
"""
|
||||
Register a section.setting, and set the default.
|
||||
Will overwrite any previously set default, and set setting if not one.
|
||||
The default value deterimines the type of the setting.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
self.data[section] = {}
|
||||
if section not in self.default:
|
||||
self.default[section] = {}
|
||||
if section not in self.callbacks:
|
||||
self.callbacks[section] = {}
|
||||
if setting not in self.callbacks[section]:
|
||||
self.callbacks[section][setting] = []
|
||||
# Add the default value to settings, if not exist:
|
||||
if setting not in self.data[section]:
|
||||
self.data[section][setting] = default
|
||||
# Set the default, regardless:
|
||||
self.default[section][setting] = default
|
||||
|
||||
def connect(self, key, func):
|
||||
"""
|
||||
Connect a callback func that gets called when key is changed.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
self._cb_id += 1
|
||||
self.callbacks[section][setting].append((self._cb_id, func))
|
||||
return self._cb_id
|
||||
|
||||
def disconnect(self, callback_id):
|
||||
"""
|
||||
Removes a callback given its callback ID. The ID is generated and
|
||||
returned when the function is connected to the key (section.setting).
|
||||
"""
|
||||
for section in self.callbacks:
|
||||
for setting in self.callbacks[section]:
|
||||
for (cbid, func) in self.callbacks[section][setting]:
|
||||
if callback_id == cbid:
|
||||
self.callbacks[section][setting].remove((cbid, func))
|
||||
|
||||
def emit(self, key):
|
||||
"""
|
||||
Emits the signal "key" which will call the callbacks associated
|
||||
with that setting.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.callbacks:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.callbacks[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
for (cbid, func) in self.callbacks[section][setting]:
|
||||
func(self, 0, str(self.data[section][setting]), None)
|
||||
|
||||
def set(self, key, value):
|
||||
"""
|
||||
Set the setting's value. There are only two ways to get into
|
||||
the data dictionary: via the load() method that reads a file,
|
||||
or from this method.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
# Check value to see if right type:
|
||||
if type(value) == long:
|
||||
value = int(value)
|
||||
if type(value) == unicode:
|
||||
value = str(value)
|
||||
if self.has_default(key):
|
||||
if type(self.get_default(key)) != type(value):
|
||||
raise AttributeError("attempting to set '%s' to wrong type "
|
||||
"'%s'; should be '%s'" %
|
||||
(key, type(value),
|
||||
type(self.get_default(key))))
|
||||
if (setting in self.data[section] and
|
||||
self.data[section][setting] == value):
|
||||
# Do nothing if existed and is the same
|
||||
pass
|
||||
else:
|
||||
# Set the value:
|
||||
self.data[section][setting] = value
|
||||
# Only call callback if the value changed!
|
||||
if (section in self.callbacks and
|
||||
setting in self.callbacks[section]):
|
||||
self.emit(key)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# Convience functions to call ConfigManager instance methods
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
|
||||
def register(key, value):
|
||||
""" Module shortcut to register key, value """
|
||||
return CONFIGMAN.register(key, value)
|
||||
|
@ -9,6 +9,7 @@ pkgdata_PYTHON = \
|
||||
__init__.py \
|
||||
callback.py \
|
||||
callman.py \
|
||||
configmanager.py \
|
||||
progressmon.py \
|
||||
longop.py
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
Generic utilities useful for users of the gen package
|
||||
"""
|
||||
|
||||
from configmanager import ConfigManager
|
||||
from progressmon import ProgressMonitor
|
||||
from longop import LongOpStatus
|
||||
from callback import Callback
|
||||
|
415
src/gen/utils/configmanager.py
Normal file
415
src/gen/utils/configmanager.py
Normal file
@ -0,0 +1,415 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2005-2007 Donald N. Allingham
|
||||
# Copyright (C) 2008-2009 Gary Burton
|
||||
# Copyright (C) 2009 Doug Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# 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$
|
||||
|
||||
"""
|
||||
This package implements access to GRAMPS configuration.
|
||||
"""
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# System imports
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import ConfigParser
|
||||
import errno
|
||||
|
||||
try:
|
||||
from ast import literal_eval as safe_eval
|
||||
except:
|
||||
# PYTHON2.5 COMPATIBILITY: no ast present
|
||||
# not as safe as literal_eval, but works for python2.5:
|
||||
def safe_eval(exp):
|
||||
# restrict eval to empty environment
|
||||
return eval(exp, {})
|
||||
|
||||
#---------------------------------------------------------------
|
||||
#
|
||||
# Classes
|
||||
#
|
||||
#---------------------------------------------------------------
|
||||
class ConfigManager(object):
|
||||
"""
|
||||
Class to construct the singleton CONFIGMAN where all
|
||||
settings are stored.
|
||||
"""
|
||||
def __init__(self, filename = None):
|
||||
"""
|
||||
Configure manager constructor takes an optional filename.
|
||||
|
||||
The data dictionary stores the settings:
|
||||
|
||||
self.data[section][setting] = value
|
||||
|
||||
The value has a type that matches the default. It is an error
|
||||
to attempt to set the setting to a different type. To change
|
||||
the type, you must re-register the setting, and re-set the
|
||||
value. Values can be any simple type in Python (except,
|
||||
currently longs, which are saved as ints to avoid type
|
||||
errors). This includes: str, int, list, tuple, dict, float,
|
||||
etc. Of course, composite types must themselves be composed of
|
||||
simple types.
|
||||
|
||||
The default values are given in Python code and stored here
|
||||
on start-up:
|
||||
|
||||
self.default[section][setting] = default_value
|
||||
|
||||
Callbacks are stored as callables here:
|
||||
|
||||
self.callbacks[section][setting] = (id, func)
|
||||
|
||||
The default filename (usually the one you are reading from)
|
||||
is stored as self.filename. However, you can save to another
|
||||
filename using self.save(otherfilename).
|
||||
"""
|
||||
self._cb_id = 0 # callback id counter
|
||||
self.filename = filename
|
||||
self.callbacks = {}
|
||||
self.default = {}
|
||||
self.data = {}
|
||||
self.reset()
|
||||
|
||||
def __getitem__(self, item):
|
||||
"""
|
||||
For item access, such as config["interface.dont-ask"]
|
||||
"""
|
||||
return self.get(item)
|
||||
|
||||
def __setitem__(self, item, value):
|
||||
"""
|
||||
For item assignment, such as config["interface.dont-ask"] = True
|
||||
"""
|
||||
self.set(item, value)
|
||||
|
||||
def reset(self, key=None):
|
||||
"""
|
||||
Resets one, a section, or all settings values to their defaults.
|
||||
This does not disconnect callbacks.
|
||||
"""
|
||||
if key is None:
|
||||
section = None
|
||||
setting = None
|
||||
elif "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else: # key is not None and doesn't have a "."
|
||||
section = key
|
||||
setting = None
|
||||
# Now, do the reset on the right parts:
|
||||
if section is None:
|
||||
self.data = {}
|
||||
for section in self.default:
|
||||
self.data[section] = {}
|
||||
for setting in self.default[section]:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
elif setting is None:
|
||||
self.data[section] = {}
|
||||
for setting in self.default[section]:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
else:
|
||||
self.data[section][setting] = self.default[section][setting]
|
||||
# Callbacks are still connected
|
||||
|
||||
def get_sections(self):
|
||||
"""
|
||||
Return all section names.
|
||||
"""
|
||||
return self.data.keys()
|
||||
|
||||
def get_section_settings(self, section):
|
||||
"""
|
||||
Return all section setting names.
|
||||
"""
|
||||
return self.data[section].keys()
|
||||
|
||||
def load(self, filename=None, oldstyle=False):
|
||||
"""
|
||||
Loads an .ini into self.data.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
if filename and os.path.exists(filename):
|
||||
parser = ConfigParser.RawConfigParser()
|
||||
parser.read(filename)
|
||||
for sec in parser.sections():
|
||||
name = sec.lower()
|
||||
if name not in self.data:
|
||||
# Add the setting from file
|
||||
# These might be old settings, or third-party settings
|
||||
self.data[name] = {}
|
||||
for opt in parser.options(sec):
|
||||
raw_value = parser.get(sec, opt).strip()
|
||||
setting = opt.lower()
|
||||
if oldstyle:
|
||||
####################### Upgrade from oldstyle < 3.2
|
||||
# Oldstyle didn't mark setting type, but had it
|
||||
# set in preferences. New style gets it from evaling
|
||||
# the setting's value
|
||||
#######################
|
||||
# if we know this setting, convert type
|
||||
key = "%s.%s" % (name, setting)
|
||||
if self.has_default(key):
|
||||
vtype = type(self.get_default(key))
|
||||
if vtype == bool:
|
||||
value = raw_value in ["1", "True"]
|
||||
elif vtype == list:
|
||||
print >> sys.stderr, "WARNING: ignoring old key '%s'" % key
|
||||
continue # there were no lists in oldstyle
|
||||
else:
|
||||
value = vtype(raw_value)
|
||||
else:
|
||||
# else, ignore it
|
||||
print >> sys.stderr, "WARNING: ignoring old key '%s'" % key
|
||||
continue # with next setting
|
||||
####################### End upgrade code
|
||||
else:
|
||||
value = safe_eval(raw_value)
|
||||
####################### Now, let's test and set:
|
||||
if (name in self.default and
|
||||
setting in self.default[name]):
|
||||
if type(value) == type(self.default[name][setting]):
|
||||
self.data[name][setting] = value
|
||||
else:
|
||||
print >> sys.stderr, ("WARNING: ignoring key with wrong type "
|
||||
"'%s.%s'" % (name, setting))
|
||||
else:
|
||||
# this could be a third-party setting; add it:
|
||||
self.data[name][setting] = value
|
||||
|
||||
def save(self, filename = None):
|
||||
"""
|
||||
Saves the current section/settings to an .ini file. Optional filename
|
||||
will override the default filename to save to, if given.
|
||||
"""
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
if filename:
|
||||
try:
|
||||
head = os.path.split( filename )[0]
|
||||
os.makedirs( head )
|
||||
except OSError, exp:
|
||||
if exp.errno != errno.EEXIST:
|
||||
raise
|
||||
key_file = open(filename, "w")
|
||||
key_file.write(";; Gramps key file\n")
|
||||
key_file.write((";; Automatically created at %s" %
|
||||
time.strftime("%Y/%m/%d %H:%M:%S")) + "\n\n")
|
||||
sections = sorted(self.data)
|
||||
for section in sections:
|
||||
key_file.write(("[%s]\n") % section)
|
||||
keys = sorted(self.data[section])
|
||||
for key in keys:
|
||||
value = self.data[section][key]
|
||||
# If it has a default:
|
||||
if self.has_default("%s.%s" % (section, key)):
|
||||
if value == self.get_default("%s.%s" % (section, key)):
|
||||
default = ";;"
|
||||
else:
|
||||
default = ""
|
||||
if isinstance(value, long):
|
||||
value = int(value)
|
||||
key_file.write(("%s%s=%s\n")% (default,
|
||||
key,
|
||||
repr(value)))
|
||||
key_file.write("\n")
|
||||
key_file.close()
|
||||
# else, no filename given; nothing to save so do nothing quietly
|
||||
|
||||
def get(self, key):
|
||||
"""
|
||||
Get the setting's value. raise an error if an invalid section.setting.
|
||||
Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
return self.data[section][setting]
|
||||
|
||||
def is_set(self, key):
|
||||
"""
|
||||
Does the setting exist? Returns True if does, False otherwise.
|
||||
Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
return False
|
||||
if section not in self.data:
|
||||
return False
|
||||
if setting not in self.data[section]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def has_default(self, key):
|
||||
"""
|
||||
Does the setting have a default value? Returns True if it does,
|
||||
False otherwise. Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
return False
|
||||
if section not in self.default:
|
||||
return False
|
||||
if setting not in self.default[section]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_default(self, key):
|
||||
"""
|
||||
Get the setting's default value. Raises an error if invalid key is
|
||||
give. Key is a sting in the "section.setting" format.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.default:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.default[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
return self.default[section][setting]
|
||||
|
||||
def register(self, key, default):
|
||||
"""
|
||||
Register a section.setting, and set the default.
|
||||
Will overwrite any previously set default, and set setting if not one.
|
||||
The default value deterimines the type of the setting.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
self.data[section] = {}
|
||||
if section not in self.default:
|
||||
self.default[section] = {}
|
||||
if section not in self.callbacks:
|
||||
self.callbacks[section] = {}
|
||||
if setting not in self.callbacks[section]:
|
||||
self.callbacks[section][setting] = []
|
||||
# Add the default value to settings, if not exist:
|
||||
if setting not in self.data[section]:
|
||||
self.data[section][setting] = default
|
||||
# Set the default, regardless:
|
||||
self.default[section][setting] = default
|
||||
|
||||
def connect(self, key, func):
|
||||
"""
|
||||
Connect a callback func that gets called when key is changed.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
self._cb_id += 1
|
||||
self.callbacks[section][setting].append((self._cb_id, func))
|
||||
return self._cb_id
|
||||
|
||||
def disconnect(self, callback_id):
|
||||
"""
|
||||
Removes a callback given its callback ID. The ID is generated and
|
||||
returned when the function is connected to the key (section.setting).
|
||||
"""
|
||||
for section in self.callbacks:
|
||||
for setting in self.callbacks[section]:
|
||||
for (cbid, func) in self.callbacks[section][setting]:
|
||||
if callback_id == cbid:
|
||||
self.callbacks[section][setting].remove((cbid, func))
|
||||
|
||||
def emit(self, key):
|
||||
"""
|
||||
Emits the signal "key" which will call the callbacks associated
|
||||
with that setting.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.callbacks:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.callbacks[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
for (cbid, func) in self.callbacks[section][setting]:
|
||||
func(self, 0, str(self.data[section][setting]), None)
|
||||
|
||||
def set(self, key, value):
|
||||
"""
|
||||
Set the setting's value. There are only two ways to get into
|
||||
the data dictionary: via the load() method that reads a file,
|
||||
or from this method.
|
||||
"""
|
||||
if "." in key:
|
||||
section, setting = key.split(".", 1)
|
||||
else:
|
||||
raise AttributeError("Invalid config section.setting name: '%s'" %
|
||||
key)
|
||||
if section not in self.data:
|
||||
raise AttributeError("No such config section name: '%s'" % section)
|
||||
if setting not in self.data[section]:
|
||||
raise AttributeError("No such config setting name: '%s.%s'" %
|
||||
(section, setting))
|
||||
# Check value to see if right type:
|
||||
if type(value) == long:
|
||||
value = int(value)
|
||||
if type(value) == unicode:
|
||||
value = str(value)
|
||||
if self.has_default(key):
|
||||
if type(self.get_default(key)) != type(value):
|
||||
raise AttributeError("attempting to set '%s' to wrong type "
|
||||
"'%s'; should be '%s'" %
|
||||
(key, type(value),
|
||||
type(self.get_default(key))))
|
||||
if (setting in self.data[section] and
|
||||
self.data[section][setting] == value):
|
||||
# Do nothing if existed and is the same
|
||||
pass
|
||||
else:
|
||||
# Set the value:
|
||||
self.data[section][setting] = value
|
||||
# Only call callback if the value changed!
|
||||
if (section in self.callbacks and
|
||||
setting in self.callbacks[section]):
|
||||
self.emit(key)
|
||||
|
Loading…
Reference in New Issue
Block a user