Source code for getdist.inifile

import os
import numpy as np


[docs] class IniError(Exception): pass
[docs] class IniFile: """ Class for storing option parameter values and reading/saving to file Unlike standard .ini files, IniFile allows inheritance, in that a .ini file can use INCLUDE(..) and DEFAULT(...) to include or override settings in another file (to avoid duplication) :ivar params: dictionary of name, values stored :ivar comments: dictionary of optional comments for parameter names """ def __init__(self, settings=None, keep_includes=False, expand_environment_variables=True): """ :param settings: a filename of a .ini file to read, or a dictionary of name/values :param keep_includes: - False: load all INCLUDE and DEFAULT files, making one params dictionary - True: only load settings in main file, and store INCLUDE and DEFAULT entries into defaults and includes filename lists. :param expand_environment_variables: whether to expand $(var) placeholders in parameter values using environment variables """ self.params = dict() self.comments = dict() self.readOrder = [] self.defaults = [] self.includes = [] self.original_filename = None self.expand_environment_variables = expand_environment_variables if isinstance(settings, str): self.readFile(settings, keep_includes) elif settings: self.params.update(settings)
[docs] def expand_placeholders(self, s): """Expand shell variables of the forms $(var), like in Makefiles""" if '$(' not in s: return s res = '' index = 0 pathlen = len(s) while index < pathlen: c = s[index] if c == '$': if s[index + 1] == '$': res = res + c index += 1 elif s[index + 1] == '(': s = s[index + 2:] pathlen = len(s) index = s.index(')') var = s[:index] if var in os.environ: res += os.environ[var] else: res = res + c index += 1 return res
def readFile(self, filename, keep_includes=False, if_not_defined=False): try: fileincludes = [] filedefaults = [] self.original_filename = filename comments = [] with open(filename, encoding='utf-8-sig') as textFileHandle: # Remove blank lines and comment lines from the python list of lists. for line in textFileHandle: s = line.strip() if s == 'END': break if s.startswith('#'): comments.append(s[1:].rstrip()) continue elif s.startswith('INCLUDE('): fileincludes.append(s[s.find('(') + 1:s.rfind(')')]) elif s.startswith('DEFAULT('): filedefaults.append(s[s.find('(') + 1:s.rfind(')')]) elif s != '': eq = s.find('=') if eq >= 0: key = s[0:eq].strip() if key in self.params: if if_not_defined: continue raise IniError('Error: duplicate key: ' + key + ' in ' + filename) value = s[eq + 1:].strip() if self.expand_environment_variables: value = self.expand_placeholders(value) self.params[key] = value self.readOrder.append(key) if len(comments): self.comments[key] = comments if not s.startswith('#'): comments = [] if keep_includes: self.includes += fileincludes self.defaults += filedefaults else: for ffile in fileincludes: if os.path.isabs(ffile): self.readFile(ffile, if_not_defined=if_not_defined) else: self.readFile(os.path.join(os.path.dirname(filename), ffile), if_not_defined=if_not_defined) for ffile in filedefaults: if os.path.isabs(ffile): self.readFile(ffile, if_not_defined=True) else: self.readFile(os.path.join(os.path.dirname(filename), ffile), if_not_defined=True) return self.params except: print('Error in ' + filename) raise def __str__(self): return "\n".join(self.fileLines())
[docs] def saveFile(self, filename=None): """ Save to a .ini file :param filename: name of file to save to """ if not filename: filename = self.original_filename if not filename: raise IniError('No filename for iniFile.saveFile()') with open(filename, 'w', encoding='utf-8') as f: f.write(str(self))
def fileLines(self): def asIniText(value): if isinstance(value, type('')): return value if type(value) == bool: return str(value)[0] return str(value) parameterLines = [] for include in self.includes: parameterLines.append('INCLUDE(' + include + ')') for default in self.defaults: parameterLines.append('DEFAULT(' + default + ')') keys = list(self.params.keys()) keys.sort() for key in self.readOrder: if key in keys: parameterLines.append(key + '=' + asIniText(self.params[key])) keys.remove(key) for key in keys: parameterLines.append(key + '=' + asIniText(self.params[key])) return parameterLines def replaceTags(self, placeholder, text): for key in self.params: self.params[key] = self.params[key].replace(placeholder, text) return self.params def delete_keys(self, keys): for k in keys: self.params.pop(k, None) def _undefined(self, name): raise IniError('parameter not defined: ' + name)
[docs] def hasKey(self, name): """ Test if key name exists :param name: parameter name :return: True or False test if key name exists """ return name in self.params
[docs] def isSet(self, name, allowEmpty=False): """ Tests whether value for name is set or is empty :param name: name of parameter :param allowEmpty: whether to allow empty strings (return True is parameter name exists but is not set, "x = ") """ return name in self.params and (allowEmpty or self.params[name] != "")
def asType(self, name, tp, default=None, allowEmpty=False): if self.isSet(name, allowEmpty): if tp == bool: return self.bool(name, default) elif tp == list: return self.split(name, default) elif tp == np.ndarray: return self.ndarray(name, default) else: return tp(self.params[name]) elif default is not None: return default else: self._undefined(name)
[docs] def setAttr(self, name, instance, default=None, allowEmpty=False): """ Set attribute of an object to value of parameter, using same type as existing value or default :param name: parameter name :param instance: instance of an object, so instance.name is the value to set :param default: default value if instance.name does not exist :param allowEmpty: whether to allow empty values """ default = getattr(instance, name, default) setattr(instance, name, self.asType(name, type(default), default, allowEmpty=allowEmpty))
def getAttr(self, instance, name, default=None, comment=None): val = getattr(instance, name, default) self.params[name] = val if comment: self.comments[name] = comment
[docs] def bool(self, name, default=False): """ Get boolean value :param name: parameter name :param default: default value if not set """ if self.isSet(name): s = self.params[name] if isinstance(s, bool): return s if s[0] == 'T': return True elif s[0] == 'F': return False raise IniError('parameter does not have valid T(rue) or F(alse) boolean value: ' + name) elif default is not None: return default else: self._undefined(name)
[docs] def bool_list(self, name, default=None): """ Get list of boolean values, e.g. from name = T F T :param name: parameter name :param default: default value if not set """ if not default: default = [] return self.split(name, default, tp=bool)
[docs] def string(self, name, default=None, allowEmpty=True): """ Get string value :param name: parameter name :param default: default value if not set :param allowEmpty: whether to return empty string if value is empty (otherwise return default) """ return self.asType(name, str, default, allowEmpty=allowEmpty)
[docs] def list(self, name, default=None, tp=None): """ Get list (from space-separated values) :param name: parameter name :param default: default value :param tp: type for each member of the list """ if not default: default = [] return self.split(name, default, tp)
[docs] def float(self, name, default=None): """ Get float value :param name: parameter name :param default: default value """ return self.asType(name, float, default)
[docs] def float_list(self, name, default=None): """ Get list of float values :param name: parameter name :param default: default value """ if not default: default = [] return self.split(name, default, tp=float)
[docs] def int(self, name, default=None): """ Get int value :param name: parameter name :param default: default value """ return self.asType(name, int, default)
[docs] def int_list(self, name, default=None): """ Get list of int values :param name: parameter name :param default: default value """ if not default: default = [] return self.split(name, default, tp=int)
[docs] def split(self, name, default=None, tp=None): """ Gets a list of values, optionally cast to type tp :param name: parameter name :param default: default value :param tp: type for each list member """ if name in self.params and isinstance(self.params[name], (list, tuple)): if tp is None: return self.params[name] else: return [tp(x) for x in self.params[name]] s = self.string(name, default) if isinstance(s, str): if tp is not None: return [tp(x) for x in s.split()] return s.split() else: return s
[docs] def ndarray(self, name, default=None, tp=np.float64): """ Get numpy array of values :param name: parameter name :param default: default value :param tp: type for array """ return np.array(self.split(name, default, tp=tp))
[docs] def array_int(self, name, index=1, default=None): """ Get one int value, for entries of the form name(index) :param name: base parameter name :param index: index (in brackets) :param default: default value """ return self.int(name + '(%u)' % index, default)
[docs] def array_string(self, name, index=1, default=None): """ Get one str value, for entries of the form name(index) :param name: base parameter name :param index: index (in brackets) :param default: default value """ return self.string(name + '(%u)' % index, default)
[docs] def array_bool(self, name, index=1, default=None): """ Get one boolean value, for entries of the form name(index) :param name: base parameter name :param index: index (in brackets) :param default: default value """ return self.bool(name + '(%u)' % index, default)
[docs] def array_float(self, name, index=1, default=None): """ Get one float value, for entries of the form name(index) :param name: base parameter name :param index: index (in brackets) :param default: default value """ return self.float(name + '(%u)' % index, default)
def relativeFileName(self, name, default=None): s = self.string(name, default) if not os.path.isabs(s) and self.original_filename is not None: return os.path.join(os.path.dirname(self.original_filename), s) return s