# coding: utf-8 # GNU Solfege - free ear training software # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2007 Tom Cato Amundsen # # 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., 51 Franklin ST, Fifth Floor, Boston, MA 02110-1301 USA """ TODO: - cfg.get_list - cfg.set_list - watches outside ConfigUtils >>> import cfg >>> cfg.initialise(None, "default.config", "~/.cfg-test") >>> cfg.set_string("section/stringvar", "value") >>> cfg.get_string("section/stringvar") 'value' >>> cfg.set_int("section/intvar", 14) >>> cfg.get_int("section/intvar") 14 >>> cfg.set_float("section/floatvar", 3.141592) >>> cfg.get_float("section/floatvar") == 3.141592 1 >>> cfg.set_bool("section/boolvar", 4) >>> cfg.get_bool("section/boolvar") 1 >>> cfg.set_bool("section/boolvar", 0) >>> cfg.get_bool("section/boolvar") 0 >>> cfg.set_list("section/listv", [1, 2, 3]) >>> cfg.get_list("section/listv") [1, 2, 3] >>> c = ConfigUtils("section") >>> c.get_string("section/stringvar") 'value' >>> c.get_int("section/intvar") 14 >>> c.get_bool("section/boolvar") 0 >>> c.get_float("section/floatvar") == 3.141592 1 >>> cfg.initialise(None, None, "~/.solfege-cfg-testing") >>> c.get_string("ss/a") '' >>> c.get_string("ss/a=hei") 'hei' >>> c.get_int("ss/a=3") 3 >>> c.get_list("ss/a") [] >>> c.get_list("ss/a=[1, 2, 3]") [1, 2, 3] >>> comment_re.match("# basd") != None True >>> section_re.match("#[section]") == None True >>> section_re.match(" [section]") == None True >>> section_re.match("[section]") != None True >>> value_re.match("key=value") != None True >>> value_re.match("#key=value") == None True >>> value_re.match(" key=value") == None True """ import re import codecs import os, os.path import filesystem section_re = re.compile("^\[([\w-]*?)\]") value_re = re.compile( "^([\w-]*?)=(.*)") comment_re = re.compile("#.*") _blocked_watches = {} _watches = {} _watch_counter = {} _user_filename = None _app_defaults_filename = None _system_filename = None data = {} def split(key): return key.split("/") def parse_file_into_dict(dictionary, filename): f = codecs.open(filename, "rU", "utf-8") line = f.readline() section = None while line: section_m = section_re.match(line) value_m = value_re.match(line) comment_m = comment_re.match(line) if comment_m: pass elif section_m: section = section_m.groups()[0] if section not in dictionary: dictionary[section] = {} elif value_m: assert section dictionary[section][value_m.groups()[0]] = value_m.groups()[1] elif not line.strip(): pass else: print filename raise Exception("Shit happended line %s" % line) line = f.readline() f.close() return dictionary def sync(): dump(data, _user_filename) def _maybe_create_key(key): global data section, k = split(key) if section not in data: data[section] = {} def iterate_sections(): for n in data.keys(): yield n ######################## ## set_XXXX functions ## ######################## def set_string(key, val): global data, _watches, _blocked_watches _maybe_create_key(key) section, k = split(key) oldval = get_string(key) data[section][k] = val if key in _watches and (oldval != get_string(key)): if key in _blocked_watches and _blocked_watches[key] > 0: return for cb in _watches[key].values(): cb(key) def set_int(key, val): global data, _watches, _blocked_watches assert isinstance(val, int) _maybe_create_key(key) section, k = split(key) oldval = get_string(key) data[section][k] = str(val) if key in _watches and (oldval != get_string(key)): if key in _blocked_watches and _blocked_watches[key] > 0: return for cb in _watches[key].values(): cb(key) def set_float(key, val): global data, _watches, _blocked_watches assert isinstance(val, (float, int)) _maybe_create_key(key) section, k = split(key) oldval = get_string(key) data[section][k] = str(val) if key in _watches and (oldval != get_string(key)): if key in _blocked_watches and _blocked_watches[key] > 0: return for cb in _watches[key].values(): cb(key) def set_bool(key, val): _maybe_create_key(key) if val: set_string(key, "true") else: set_string(key, "false") def set_list(key, val): set_string(key, str(val)) ######################## ## get_XXX functions ## ######################## def get_string(key): if len(key.split("=")) == 2: key, default = key.split("=") else: default = "" section, k = split(key) try: return data[section][k] except KeyError: return default def get_int(key): if len(key.split("=")) == 2: key, default = key.split("=") else: default = 0 section, k = split(key) try: # UGH win32 fix if not data[section][k]: return 0 return int(float(data[section][k])) except KeyError: return int(default) def get_float(key): if len(key.split("=")) == 2: key, default = key.split("=") else: default = 0 section, k = split(key) try: return float(data[section][k]) except KeyError: return float(default) def get_list(key): if len(key.split("=")) == 2: key, default = key.split("=") else: default = [] section, k = split(key) try: return eval(data[section][k]) except KeyError: return default def get_bool(key): if get_string(key) == 'true': return 1 elif get_string(key) == 'false': return 0 else: return 0 ##################################### def del_key(key): global data, _watches, _blocked_watches section, k = split(key) #FIXME watches if section not in data: return if k not in data[section]: return del data[section][k] if not data[section]: del data[section] def del_section(section): global data, _watches, _blocked_watches #FIXME watches if section not in data: # Trying to delete a deleted section return del data[section] ###################################### ## reading and writing the database ## ###################################### def dump(dict, fn): f = open(fn, 'w') for section in dict: f.write("[%s]\n" % section) for name in dict[section]: f.write("%s=%s\n" % (name, dict[section][name])) f.write("\n") f.close() def drop_user_config(): """ Reread the config data, but only read the systems defaults from /usr/share/solfege/default.config and /etc/solfege, not $HOME/.solfegerc """ global data, _watches, _watch_counter, _blocked_watches data = {} _watches = {} _watch_counter = 0 _blocked_watches = {} data = parse_file_into_dict(data, _app_defaults_filename) if _system_filename and os.path.isfile(_system_filename): data = parse_file_into_dict(data, _system_filename) def reread_data(): global data, _watches, _watch_counter, _blocked_watches _watches = {} _watch_counter = 0 _blocked_watches = {} if _app_defaults_filename: data = parse_file_into_dict({}, _app_defaults_filename) if _system_filename: data = parse_file_into_dict(data, _system_filename) if _user_filename and os.path.isfile(_user_filename): data = parse_file_into_dict(data, _user_filename) def initialise(app_defaults_filename, system_filename, user_filename): """ app_defaults_filename: file must exist! system_filename: sys admin can override app_defaults_filename user_filename: the state of the app is stored here, also user config. """ global data, _watches, _watch_counter, _blocked_watches global _app_defaults_filename, _system_filename, _user_filename _watches = {} _watch_counter = 0 _blocked_watches = {} _app_defaults_filename = app_defaults_filename _system_filename = system_filename _user_filename = user_filename = filesystem.expanduser(user_filename) if app_defaults_filename: try: data = parse_file_into_dict({}, app_defaults_filename) except: raise Exception("Solfege install is completely broken.\nCannot find required file %s" % app_defaults_filename) else: data = {} if system_filename and os.path.isfile(system_filename): data = parse_file_into_dict(data, system_filename) if os.path.isfile(user_filename): data = parse_file_into_dict(data, user_filename) class ConfigUtils(object): def __init__(self, exname): self.m_exname = exname def block_watch(self, name): """ Stop functions watching a name being called. You have to call the same number of unblock_watch calls as block_calls to remove a blocking. """ global _blocked_watches name = self._expand_name(name) if name not in _blocked_watches: _blocked_watches[name] = 0 _blocked_watches[name] += 1 def unblock_watch(self, name): global _blocked_watches name = self._expand_name(name) assert name in _blocked_watches assert _blocked_watches[name] > 0 _blocked_watches[name] -= 1 def add_watch(self, name, callback): global _watches, _watch_counter name = self._expand_name(name) if name not in _watches: _watches[name] = {} _watches[name][_watch_counter] = callback _watch_counter += 1 return _watch_counter - 1 def remove_watch(self, name, id): global _watches, _watch_counter name = self._expand_name(name) if name in _watches: if id in _watches[name]: del _watches[name][id] if _watches[name] == {}: del _watches[name] else: pass# FIXME print "warning: remove_watch: id don't exist:", id else: pass# FIXME print "warning: remove_watch: name is not watched:", name def _expand_name(self, name): if name.count("/") == 0: return "%s/%s" % (self.m_exname, name) return name ###### # set ###### def set_string(self, name, val): set_string(self._expand_name(name), val) def set_int(self, name, val): set_int(self._expand_name(name), val) def set_float(self, name, val): set_float(self._expand_name(name), val) def set_bool(self, name, val): set_bool(self._expand_name(name), val) def set_list(self, name, val): set_list(self._expand_name(name), val) ###### # get ###### def _get(self, func, name, default=""): return func(self._expand_name(name)+default) def get_string(self, name): r = self._get(get_string, name) if r is None: return "" else: return r def get_int(self, name): return self._get(get_int, name) def get_int_with_default(self, name, default): assert type(default) is type(0) return self.get_int(name+"=%i" % default) def get_float(self, name): return self._get(get_float, name) def get_bool(self, name): return self._get(get_bool, name) def get_list(self, name): try: if '=' in name: return eval(self._get(get_string, name)) return eval(self._get(get_string, name, "=[]")) except SyntaxError: return []