Annotation of hatari/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 by Eero Tamminen <[email protected]>
        !             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:     defaultpath = "%s%c.hatari" % (os.path.expanduser("~"), os.path.sep)
        !            68: 
        !            69:     def __init__(self, cfgfile, defaults = {}, miss_is_error = True):
        !            70:         "ConfigStore(cfgfile[,defaults,miss_is_error])"
        !            71:         self.defaults = defaults
        !            72:         self.miss_is_error = miss_is_error
        !            73:         path = self._get_fullpath(cfgfile)
        !            74:         self.cfgfile = cfgfile
        !            75:         self.load(path)
        !            76:     
        !            77:     def load(self, path):
        !            78:         "load(path), load given configuration file"
        !            79:         if path:
        !            80:             sections = self._read(path)
        !            81:             if sections:
        !            82:                 print "Loaded configuration file:", path
        !            83:                 self.cfgfile = os.path.basename(path)
        !            84:                 self.sections = sections
        !            85:             else:
        !            86:                 print "ERROR: configuration file '%' loading failed" % path
        !            87:                 return
        !            88:         else:
        !            89:             print "WARNING: configuration file missing, using defaults"
        !            90:             self.sections = self.defaults
        !            91:         self.path = path
        !            92:         self.original = self.get_checkpoint()
        !            93:         self.changed = False
        !            94: 
        !            95:     def is_loaded(self):
        !            96:         "is_loaded() -> True if configuration loading succeeded"
        !            97:         if self.sections:
        !            98:             return True
        !            99:         return False
        !           100: 
        !           101:     def get_path(self):
        !           102:         "get_path() -> configuration file path"
        !           103:         return self.path
        !           104:     
        !           105:     def _get_fullpath(self, cfgfile):
        !           106:         "get_fullpath(cfgfile) -> path or None, check first CWD & then HOME for cfgfile"
        !           107:         # hatari.cfg can be in home or current work dir
        !           108:         for path in (os.getcwd(), os.path.expanduser("~")):
        !           109:             if path:
        !           110:                 path = self._check_path(path, cfgfile)
        !           111:                 if path:
        !           112:                     return path
        !           113:         return None
        !           114: 
        !           115:     def _check_path(self, path, cfgfile):
        !           116:         """check_path(path,cfgfile) -> path
        !           117:         
        !           118:         return full path if cfg in path/.hatari/ or in path prefixed with '.'"""
        !           119:         sep = os.path.sep
        !           120:         testpath = "%s%c.hatari%c%s" % (path, sep, sep, cfgfile)
        !           121:         if os.path.exists(testpath):
        !           122:             return testpath
        !           123:         testpath = "%s%c.%s" % (path, sep, cfgfile)
        !           124:         if os.path.exists(testpath):
        !           125:             return testpath
        !           126:         return None
        !           127:     
        !           128:     def _read(self, path):
        !           129:         "_read(path) -> (all keys, section2key mappings)"
        !           130:         config = open(path, "r")
        !           131:         if not config:
        !           132:             return ({}, {})
        !           133:         name = "[_orphans_]"
        !           134:         seckeys = {}
        !           135:         sections = {}
        !           136:         for line in config.readlines():
        !           137:             line = line.strip()
        !           138:             if not line or line[0] == '#':
        !           139:                 continue
        !           140:             if line[0] == '[':
        !           141:                 if line in sections:
        !           142:                     print "WARNING: section '%s' twice in configuration" % line
        !           143:                 if seckeys:
        !           144:                     sections[name] = seckeys
        !           145:                     seckeys = {}
        !           146:                 name = line
        !           147:                 continue
        !           148:             if line.find('=') < 0:
        !           149:                 print "WARNING: line without key=value pair:\n%s" % line
        !           150:                 continue
        !           151:             key, text = [string.strip() for string in line.split('=')]
        !           152:             seckeys[key] = text_to_value(text)
        !           153:         if seckeys:
        !           154:             sections[name] = seckeys
        !           155:         return sections
        !           156: 
        !           157:     def get_checkpoint(self):
        !           158:         "get_checkpoint() -> checkpoint, get the state of variables at this point"
        !           159:         checkpoint = {}
        !           160:         for section in self.sections.keys():
        !           161:             checkpoint[section] = self.sections[section].copy()
        !           162:         return checkpoint
        !           163:     
        !           164:     def get_checkpoint_changes(self, checkpoint):
        !           165:         "get_checkpoint_changes() -> list of (key, value) pairs for later changes"
        !           166:         changed = []
        !           167:         if not self.changed:
        !           168:             return changed
        !           169:         for section in self.sections.keys():
        !           170:             if section not in checkpoint:
        !           171:                 for key, value in self.sections[section].items():
        !           172:                     changed.append((key, value))
        !           173:                 continue
        !           174:             for key, value in self.sections[section].items():                    
        !           175:                 if (key not in checkpoint[section] or
        !           176:                 value != checkpoint[section][key]):
        !           177:                     text = value_to_text(key, value)
        !           178:                     changed.append(("%s.%s" % (section, key), text))
        !           179:         return changed
        !           180:     
        !           181:     def revert_to_checkpoint(self, checkpoint):
        !           182:         "revert_to_checkpoint(checkpoint), revert to given checkpoint"
        !           183:         self.sections = checkpoint
        !           184: 
        !           185:     def get(self, section, key):
        !           186:         return self.sections[section][key]
        !           187: 
        !           188:     def set(self, section, key, value):
        !           189:         "set(section,key,value), set given key to given section"
        !           190:         if section not in self.sections:
        !           191:             if self.miss_is_error:
        !           192:                 raise AttributeError, "no section '%s'" % section
        !           193:             self.sections[section] = {}
        !           194:         if key not in self.sections[section]:
        !           195:             if self.miss_is_error:
        !           196:                 raise AttributeError, "key '%s' not in section '%s'" % (key, section)
        !           197:             self.sections[section][key] = value
        !           198:             self.changed = True
        !           199:         elif self.sections[section][key] != value:
        !           200:             self.changed = True
        !           201:         self.sections[section][key] = value
        !           202:         
        !           203:     def is_changed(self):
        !           204:         "is_changed() -> True if current configuration is changed"
        !           205:         return self.changed
        !           206: 
        !           207:     def get_changes(self):
        !           208:         "get_changes(), return (key, value) list for each changed config option"
        !           209:         return self.get_checkpoint_changes(self.original)
        !           210:     
        !           211:     def write(self, fileobj):
        !           212:         "write(fileobj), write current configuration to given file object"
        !           213:         sections = self.sections.keys()
        !           214:         sections.sort()
        !           215:         for name in sections:
        !           216:             fileobj.write("%s\n" % name)
        !           217:             keys = self.sections[name].keys()
        !           218:             keys.sort()
        !           219:             for key in keys:
        !           220:                 value = value_to_text(key, self.sections[name][key])
        !           221:                 fileobj.write("%s = %s\n" % (key, value))
        !           222:             fileobj.write("\n")
        !           223: 
        !           224:     def save(self):
        !           225:         "save() -> path, if configuration changed, save it"
        !           226:         if not self.changed:
        !           227:             print "No configuration changes to save, skipping"
        !           228:             return None
        !           229:         if not self.path:
        !           230:             print "WARNING: no existing configuration file, trying to create one"
        !           231:             if not os.path.exists(self.defaultpath):
        !           232:                 os.mkdir(self.defaultpath)
        !           233:             self.path = "%s%c%s" % (self.defaultpath, os.path.sep, self.cfgfile)
        !           234:         fileobj = open(self.path, "w")
        !           235:         if not fileobj:
        !           236:             print "ERROR: opening '%s' for saving failed" % self.path
        !           237:             return None
        !           238:         self.write(fileobj)
        !           239:         print "Saved configuration file:", self.path
        !           240:         self.changed = False
        !           241:         return path
        !           242:     
        !           243:     def save_as(self, path):
        !           244:         "save_as(path) -> path, save configuration to given file and select it"
        !           245:         assert(path)
        !           246:         if not os.path.exists(os.path.dirname(path)):
        !           247:             os.makedirs(os.path.dirname(path))
        !           248:         self.path = path
        !           249:         self.changed = True
        !           250:         self.save()
        !           251:         return path
        !           252: 
        !           253:     def save_tmp(self, path):
        !           254:         "save_tmp(path) -> path, save configuration to given file without selecting it"
        !           255:         if not os.path.exists(os.path.dirname(path)):
        !           256:             os.makedirs(os.path.dirname(path))
        !           257:         fileobj = open(path, "w")
        !           258:         if not fileobj:
        !           259:             print "ERROR: opening '%s' for saving failed" % path
        !           260:             return None
        !           261:         self.write(fileobj)
        !           262:         print "Saved temporary configuration file:", path
        !           263:         return path

unix.superglobalmegacorp.com

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