Source code for tools.parameters

# -*- coding: utf-8 -*-
'''
Created on 6 de Dez de 2013

@author: julio
'''

import warnings

from utils import yes_no


[docs]class ParametersFile(object): """Base class to construct a ParametersClass. Each parameter is defined by the following pair: - field: the name of the parameter which will be used both as an attribute of this class, and; - value: which is the value of that same parameter. Fields are separated into lists of predetermined types: str (text), float (real_n), int (int_n) and bool (boolean). Fields can be mandatory or optional (opt_). Fields are separated from values with a given separator (field_sep). Values can be a single value or a list of values, which are separated with yet another given separator (values_sep). Only one field per line will be parsed. This allows values containing field_sep. """ def __init__(self, field_sep, value_sep, par_set=None, par_file=None, text=None, real_n=None, int_n=None, boolean=None, opt_text=None, opt_real=None, opt_int=None, opt_boolean=None, parpath=None, order=None): """Constructor. """ self.path = parpath self.field_sep = field_sep self.value_sep = value_sep self.par_set = par_set or '' self.par_file = par_file or '' self.text = text or [] self.real = real_n or [] self.int = int_n or [] self.boolean = boolean or [] self.opt_text = opt_text or [] self.opt_real = opt_real or [] self.opt_int = opt_int or [] self.opt_boolean = opt_boolean or [] self.optional = (self.opt_text + self.opt_real + self.opt_int + self.opt_boolean) self.fields = self.text + self.real + self.int + self.boolean self.order = order if order and len(order) != len(self.fields + self.optional): raise ValueError('Incomplete list of ordered fields.') if parpath: self.load(parpath)
[docs] def template(self, par_path): """Write a parameter file with the template to follow, which must have been defined in the constructor docstring. """ self.path = par_path par_file = open(par_path, 'w') lines = self.__doc__.splitlines() for line in lines: par_file.write(line.strip() + '\n') par_file.close()
[docs] def set_field(self, field, value): """Create or update the value of an attr called field, given the desired object type. """ if field in self.text + self.opt_text: setattr(self, field, _split(value, str.strip, self.value_sep)) elif field in self.real + self.opt_real: setattr(self, field, _split(value, float, self.value_sep)) elif field in self.int + self.opt_int: setattr(self, field, _split(value, int, self.value_sep)) elif field in self.boolean + self.opt_boolean: setattr(self, field, yes_no(value)) else: setattr(self, field, value.strip())
[docs] def load(self, par_path): """Load a parameter file. TODO: load ordered """ self.path = par_path with open(self.path) as fid: lines = fid.readlines() checklist = list(self.fields) for line in lines: fieldvalue = line.split(self.field_sep, 1) field = fieldvalue[0] if field in self.fields + self.optional: value = fieldvalue[1] self.set_field(field, value) if field in self.fields: checklist.remove(field) if checklist: raise AttributeError('There are missing parameters: {0}.' .format(', '.join(map(str, checklist))))
[docs] def save(self, par_path=None): """Write the parameters file. """ if not par_path: par_path = self.path else: self.path = par_path par = open(par_path, 'w') par.write('·' * (25 + len(self.par_set)) + '\n') par.write('····· {0} parameters ·····\n'.format(self.par_set)) par.write('·' * (25 + len(self.par_set)) + '\n') if self.order: fields = self.order else: fields = self.fields + self.optional for field in fields: if hasattr(self, field): value = getattr(self, field) if field in (self.text + self.opt_text + self.real + self.int + self.opt_real + self.opt_int): par.write(field + self.field_sep + ' ' + _join(value, self.value_sep) + '\n') elif field in self.boolean + self.opt_boolean: if value: value = 'y' else: value = 'n' par.write(field + self.field_sep + ' ' + value + '\n') par.close()
[docs] def update(self, fields, values, save=False, par_path=None): """Updates a list of existing fields with the corresponding values. """ for i, field in enumerate(fields): if field in self.fields + self.optional: self.set_field(field, values[i]) else: warnings.warn("Error while setting field: {0}".format(field)) if save: self.save(par_path)
def _split(string, to_type, sep): """Convert a string into a give type, returning a single converted value or a list of converted values. """ if isinstance(string, str): items = map(to_type, string.split(sep)) else: items = map(to_type, [string]) if len(items) == 1: return items[0] else: return items def _join(items, sep): """Convert a list of items or a single item into a string, separating items with the given sep. """ if isinstance(items, list): return (sep + ' ').join(map(str, items)) else: return str(items)