Annotation of previous/python-ui/config.py, revision 1.1

1.1     ! root        1: #!/usr/bin/env python
        !             2: #
        !             3: # Class and helper functions for handling (Hatari) INI style
        !             4: # configuration files: loading, saving, setting/getting variables,
        !             5: # mapping them to sections, listing changes
        !             6: #
        !             7: # Copyright (C) 2008-2010 by Eero Tamminen <eerot at berlios>
        !             8: #
        !             9: # This program is free software; you can redistribute it and/or modify
        !            10: # it under the terms of the GNU General Public License as published by
        !            11: # the Free Software Foundation; either version 2 of the License, or
        !            12: # (at your option) any later version.
        !            13: #
        !            14: # This program is distributed in the hope that it will be useful,
        !            15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            17: # GNU General Public License for more details.
        !            18: 
        !            19: import os
        !            20: 
        !            21: # ------------------------------------------------------
        !            22: # Helper functions for type safe Hatari configuration variable access.
        !            23: # Map booleans, integers and strings to Python types, and back to strings.
        !            24: 
        !            25: def value_to_text(key, value):
        !            26:     "value_to_text(key, value) -> text, convert Python type to string"
        !            27:     valtype = type(value)
        !            28:     if valtype == bool:
        !            29:         assert(key[0] == "b") # bool prefix
        !            30:         if value:
        !            31:             text = "TRUE"
        !            32:         else:
        !            33:             text = "FALSE"
        !            34:     elif valtype == int:
        !            35:         assert(key[0] in ("n", "k")) # numeric/keycode prefix
        !            36:         text = str(value)
        !            37:     else:
        !            38:         assert(key[0] == "s") # string prefix
        !            39:         if value == None:
        !            40:             text = ""
        !            41:         else:
        !            42:             text = value
        !            43:     return text
        !            44: 
        !            45: def text_to_value(text):
        !            46:     "text_to_value(text) -> value, convert INI file values to real types"
        !            47:     # bool?
        !            48:     upper = text.upper()
        !            49:     if upper == "FALSE":
        !            50:         value = False
        !            51:     elif upper == "TRUE":
        !            52:         value = True
        !            53:     else:
        !            54:         try:
        !            55:             # integer?
        !            56:             value = int(text)
        !            57:         except ValueError:
        !            58:             # string
        !            59:             value = text
        !            60:     return value
        !            61: 
        !            62: 
        !            63: # ------------------------------------------------------
        !            64: # Handle INI style configuration files as used by Hatari
        !            65: 
        !            66: class ConfigStore:
        !            67:     def __init__(self, userconfdir, defaults = {}, miss_is_error = True):
        !            68:         "ConfigStore(userconfdir, fgfile[,defaults,miss_is_error])"
        !            69:         self.defaults = defaults
        !            70:         self.userpath = self._get_full_userpath(userconfdir)
        !            71:         self.miss_is_error = miss_is_error
        !            72:     
        !            73:     def _get_full_userpath(self, leafdir):
        !            74:         "get_userpath(leafdir) -> config file default save path from HOME, CWD or their subdir"
        !            75:         # user's hatari.cfg can be in home or current work dir,
        !            76:         # current dir is used only if $HOME fails
        !            77:         for path in (os.getenv("HOME"), os.getenv("HOMEPATH"), os.getcwd()):
        !            78:             if path and os.path.exists(path) and os.path.isdir(path):
        !            79:                 if leafdir:
        !            80:                     hpath = "%s%c%s" % (path, os.path.sep, leafdir)
        !            81:                     if os.path.exists(hpath) and os.path.isdir(hpath):
        !            82:                         return hpath
        !            83:                 return path
        !            84:         return None
        !            85: 
        !            86:     def get_filepath(self, filename):
        !            87:         "get_filepath(filename) -> return correct full path to config file"
        !            88:         # user config has preference over system one
        !            89:         for path in (self.userpath, os.getenv("HATARI_SYSTEM_CONFDIR")):
        !            90:             if path:
        !            91:                 file = "%s%c%s" % (path, os.path.sep, filename)
        !            92:                 if os.path.isfile(file):
        !            93:                     return file
        !            94:         # writing needs path name although it's missing for reading
        !            95:         return "%s%c%s" % (self.userpath, os.path.sep, filename)
        !            96:     
        !            97:     def load(self, path):
        !            98:         "load(path) -> load given configuration file"
        !            99:         if os.path.isfile(path):
        !           100:             sections = self._read(path)
        !           101:             if sections:
        !           102:                 self.sections = sections
        !           103:             else:
        !           104:                 print "ERROR: configuration file loading failed!"
        !           105:                 return
        !           106:         else:
        !           107:             print "WARNING: configuration file missing!"
        !           108:             if self.defaults:
        !           109:                 print "-> using dummy 'defaults'."
        !           110:             self.sections = self.defaults
        !           111:         self.path = path
        !           112:         self.cfgfile = os.path.basename(path)
        !           113:         self.original = self.get_checkpoint()
        !           114:         self.changed = False
        !           115: 
        !           116:     def is_loaded(self):
        !           117:         "is_loaded() -> True if configuration loading succeeded"
        !           118:         if self.sections:
        !           119:             return True
        !           120:         return False
        !           121: 
        !           122:     def get_path(self):
        !           123:         "get_path() -> configuration file path"
        !           124:         return self.path
        !           125:     
        !           126:     def _read(self, path):
        !           127:         "_read(path) -> (all keys, section2key mappings)"
        !           128:         print "Reading configuration file '%s'..." % path
        !           129:         config = open(path, "r")
        !           130:         if not config:
        !           131:             return ({}, {})
        !           132:         name = "[_orphans_]"
        !           133:         seckeys = {}
        !           134:         sections = {}
        !           135:         for line in config.readlines():
        !           136:             line = line.strip()
        !           137:             if not line or line[0] == '#':
        !           138:                 continue
        !           139:             if line[0] == '[':
        !           140:                 if line in sections:
        !           141:                     print "WARNING: section '%s' twice in configuration" % line
        !           142:                 if seckeys:
        !           143:                     sections[name] = seckeys
        !           144:                     seckeys = {}
        !           145:                 name = line
        !           146:                 continue
        !           147:             if line.find('=') < 0:
        !           148:                 print "WARNING: line without key=value pair:\n%s" % line
        !           149:                 continue
        !           150:             key, text = [string.strip() for string in line.split('=')]
        !           151:             seckeys[key] = text_to_value(text)
        !           152:         if seckeys:
        !           153:             sections[name] = seckeys
        !           154:         return sections
        !           155: 
        !           156:     def get_checkpoint(self):
        !           157:         "get_checkpoint() -> checkpoint, get the state of variables at this point"
        !           158:         checkpoint = {}
        !           159:         for section in self.sections.keys():
        !           160:             checkpoint[section] = self.sections[section].copy()
        !           161:         return checkpoint
        !           162:     
        !           163:     def get_checkpoint_changes(self, checkpoint):
        !           164:         "get_checkpoint_changes() -> list of (key, value) pairs for later changes"
        !           165:         changed = []
        !           166:         if not self.changed:
        !           167:             return changed
        !           168:         for section in self.sections.keys():
        !           169:             if section not in checkpoint:
        !           170:                 for key, value in self.sections[section].items():
        !           171:                     changed.append((key, value))
        !           172:                 continue
        !           173:             for key, value in self.sections[section].items():                    
        !           174:                 if (key not in checkpoint[section] or
        !           175:                 value != checkpoint[section][key]):
        !           176:                     text = value_to_text(key, value)
        !           177:                     changed.append(("%s.%s" % (section, key), text))
        !           178:         return changed
        !           179:     
        !           180:     def revert_to_checkpoint(self, checkpoint):
        !           181:         "revert_to_checkpoint(checkpoint), revert to given checkpoint"
        !           182:         self.sections = checkpoint
        !           183: 
        !           184:     def get(self, section, key):
        !           185:         return self.sections[section][key]
        !           186: 
        !           187:     def set(self, section, key, value):
        !           188:         "set(section,key,value), set given key to given section"
        !           189:         if section not in self.sections:
        !           190:             if self.miss_is_error:
        !           191:                 raise AttributeError, "no section '%s'" % section
        !           192:             self.sections[section] = {}
        !           193:         if key not in self.sections[section]:
        !           194:             if self.miss_is_error:
        !           195:                 raise AttributeError, "key '%s' not in section '%s'" % (key, section)
        !           196:             self.sections[section][key] = value
        !           197:             self.changed = True
        !           198:         elif self.sections[section][key] != value:
        !           199:             self.changed = True
        !           200:         self.sections[section][key] = value
        !           201:         
        !           202:     def is_changed(self):
        !           203:         "is_changed() -> True if current configuration is changed"
        !           204:         return self.changed
        !           205: 
        !           206:     def get_changes(self):
        !           207:         "get_changes(), return (key, value) list for each changed config option"
        !           208:         return self.get_checkpoint_changes(self.original)
        !           209:     
        !           210:     def write(self, fileobj):
        !           211:         "write(fileobj), write current configuration to given file object"
        !           212:         sections = self.sections.keys()
        !           213:         sections.sort()
        !           214:         for name in sections:
        !           215:             fileobj.write("%s\n" % name)
        !           216:             keys = self.sections[name].keys()
        !           217:             keys.sort()
        !           218:             for key in keys:
        !           219:                 value = value_to_text(key, self.sections[name][key])
        !           220:                 fileobj.write("%s = %s\n" % (key, value))
        !           221:             fileobj.write("\n")
        !           222: 
        !           223:     def save(self):
        !           224:         "save() -> path, if configuration changed, save it"
        !           225:         if not self.changed:
        !           226:             print "No configuration changes to save, skipping"
        !           227:             return None
        !           228:         fileobj = None
        !           229:         if self.path:
        !           230:             try:
        !           231:                 fileobj = open(self.path, "w")
        !           232:             except:
        !           233:                 pass
        !           234:         if not fileobj:
        !           235:             print "WARNING: non-existing/writable configuration file, creating a new one..."
        !           236:             if not os.path.exists(self.userpath):
        !           237:                 os.makedirs(self.userpath)
        !           238:             self.path = "%s%c%s" % (self.userpath, os.path.sep, self.cfgfile)
        !           239:             fileobj = open(self.path, "w")
        !           240:         if not fileobj:
        !           241:             print "ERROR: opening '%s' for saving failed" % self.path
        !           242:             return None
        !           243:         self.write(fileobj)
        !           244:         print "Saved configuration file:", self.path
        !           245:         self.changed = False
        !           246:         return self.path
        !           247:     
        !           248:     def save_as(self, path):
        !           249:         "save_as(path) -> path, save configuration to given file and select it"
        !           250:         assert(path)
        !           251:         if not os.path.exists(os.path.dirname(path)):
        !           252:             os.makedirs(os.path.dirname(path))
        !           253:         self.path = path
        !           254:         self.changed = True
        !           255:         return self.save()
        !           256: 
        !           257:     def save_tmp(self, path):
        !           258:         "save_tmp(path) -> path, save configuration to given file without selecting it"
        !           259:         if not os.path.exists(os.path.dirname(path)):
        !           260:             os.makedirs(os.path.dirname(path))
        !           261:         fileobj = open(path, "w")
        !           262:         if not fileobj:
        !           263:             print "ERROR: opening '%s' for saving failed" % path
        !           264:             return None
        !           265:         self.write(fileobj)
        !           266:         print "Saved temporary configuration file:", path
        !           267:         return path

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.