From a265c1e59d3c07a3f792eac27830286ca58cfa2b Mon Sep 17 00:00:00 2001 From: Michi Date: Thu, 24 Apr 2014 16:51:26 +0200 Subject: [PATCH 01/15] i try to rebase the dp to the master --- .../data/tardis_default_config_definition.yml | 362 +++++ tardis/io/default_config_parser.py | 1187 +++++++++++++++++ .../tardis_configv1_artis_density_v_slice.yml | 2 +- .../data/tardis_configv1_ascii_density.yml | 2 +- ...tardis_configv1_ascii_density_uniabund.yml | 6 +- 5 files changed, 1554 insertions(+), 5 deletions(-) create mode 100644 tardis/data/tardis_default_config_definition.yml create mode 100644 tardis/io/default_config_parser.py diff --git a/tardis/data/tardis_default_config_definition.yml b/tardis/data/tardis_default_config_definition.yml new file mode 100644 index 00000000000..cbff78d9186 --- /dev/null +++ b/tardis/data/tardis_default_config_definition.yml @@ -0,0 +1,362 @@ +tardis_config_version: + property_type: string + default: None + mandatory: True + help: Version of the configuration file + + +supernova: + luminosity_requested: + property_type: quantity + mandatory: True + default: 1 solLum + help: requested output luminosity for simulation + + time_explosion: + property_type: quantity + mandatory: True + default: None + help: time since explosion + + distance: + property_type: quantity + mandatory: False + default: None + help: distance to supernova + + + +atom_data: + property_type: string + mandatory: True + help: path or filename to the Atomic Data HDF5 file + +plasma: + initial_t_inner: + property_type: quantity + mandatory: False + default: -1 K + help: > + initial temperature of the inner boundary black body. If set to -1 K + will result in automatic calculation of boundary + + + initial_t_rad: + property_type: quantity + mandatory: False + default: 10000 K + help: initial radiative temperature in all cells (if set + + disable_electron_scattering: + property_type: bool + mandatory: False + default: False + help: > + disable electron scattering process in montecarlo part - non-physical only + for tests + + ionization: + property_type: string + mandatory: True + default: None + allowed_value: nebular lte + help: ionization treatment mode + + + excitation: + property_type: string + mandatory: True + default: None + allowed_value: lte dilute-lte + help: excitation treatment mode + + radiative_rates_type: + property_type: string + mandatory: True + default: None + allowed_value: dilute-blackbody detailed + help: radiative rates treatment mode + + line_interaction_type: + property_type: string + mandatory: True + default: None + allowed_value: scatter downbranch macroatom + help: line interaction mode + + w_epsilon: + property_type: float + mandatory: False + default: 1e-10 + help: w to use when j_blues get numerically 0. - avoids numerical complications + + + nlte: + species: + property_type: list + mandatory: False + default: [] + help: > + Species that are requested to be NLTE treated in the format + ['Si 2', 'Ca 1', etc.] + + coronal_approximation: + property_type: bool + default: False + mandatory: False + help: set all jblues=0.0 + + classical_nebular: + property_type: bool + default: False + mandatory: False + help: sets all beta_sobolevs to 1 + + + +model: + structure: + property_type : container-property + type: + property_type: container-declaration + containers: ['file', 'specific'] + _file: ['filename','filetype'] + +file: ['v_inner_boundary','v_outer_boundary'] + _specific: ['specific-property'] + + + filename: + property_type: string + default: None + mandatory: True + help: file name (with path) to structure model + + filetype: + property_type: string + default: None + mandatory: True + help: file type + #### there are only a handful of types available how do we validate that #### + + + + v_inner_boundary: + property_type: quantity + default: 0 km/s + mandatory: False + help: location of the inner boundary chosen from the model + + v_outer_boundary: + property_type: quantity + default: inf km/s + mandatory: False + help: location of the inner boundary chosen from the model + + specific_property: + velocity: + property_type: quantity_range + default: None + mandatory: True + help: location of boundaries in the velocity field. There will be n-1 cells as this specifis both the inner and outer velocity components + + + density: + property_type: container-property + type: + property_type: container-declaration + containers: ['branch85_w7'] + + _branch85_w7: ['branch85_w7-property'] # list + + branch85_w7-property: + time_0: + property_type: quantity + default: 19.9999584 s + mandatory: False + help: This needs no change - DO NOT TOUCH + + density_coefficient: + property_type: float + default: 3e29 + mandatory: False + help: This needs no change - DO NOT TOUCH + + abundances: + property_type: container-property + type: + property_type: container-declaration + containers: ['file','uniform'] + _uniform: [] + _file: ['filetype','filename'] + + filename: + property_type: string + default: None + mandatory: True + help: filename + + filetype: + property_type: string + default: None + mandatory: False + help: type of abundance file to read in + + + + + + + +montecarlo: + seed: + property_type: int + default: 23111963 + mandatory: False + help: Seed for the random number generator + + no_of_packets: + property_type: int + default: None + mandatory: True + help: Seed for the random number generator + + iterations: + property_type: int + default: None + mandatory: True + help: Number of maximum iterations + + black_body_sampling: + property_type: quantity_range_sampled + default: [1 angstrom, 1e6 angstrom, 1e6 angstrom] + mandatory: False + help: Sampling of the black-body for energy packet creation (giving maximum and minimum packet frequency) + + last_no_of_packets: + property_type: int + default: 100 + mandatory: False + help: This can set the number of packets for the last run. If set to None it will remain the same as all other runs. + + no_of_virtual_packets: + property_type: int + default: 0 + mandatory: False + help: Setting the number of virtual packets for the last iteration. + + enable_reflective_inner_boundary: + property_type: bool + default: False + mandatory: False + help: > + experimental feature to enable a reflective boundary. + + inner_boundary_albedo: + property_type: float + default: 0.0 + mandatory: False + help: albedo of the reflective boundary + + convergence_strategy: + property_type : container-property + type: + property_type: container-declaration + containers: ['damped', 'specific'] + _damped: ['damping_constant'] + +damped: ['t_inner', 't_rad', 'w'] + _specific: ['damping_constant', 'threshold', 'fraction', 'hold-iterations'] + +specific: ['t_inner', 't_rad', 'w'] + + t_inner_update_exponent: + property_type: float + default: -0.5 + mandatory: False + help: L=4*pi*r**2*T^y + + lock_t_inner_cycles: + property_type: int + mandatory: False + default: 1 + help: > + The number of cycles to lock the update of the inner boundary temperature. + This process helps with convergence. The default is to switch it off (1 cycle) + hold-iterations: + property_type: int + default: 3 + mandatory: True + help: > + the number of iterations that the convergence criteria need to be + fulfilled before TARDIS accepts the simulation as converged + + fraction: + property_type: float + default: 0.8 + mandatory: True + help: > + the fraction of shells that have to converge to the given + convergence threshold. For example, 0.8 means that 80% of shells + have to converge to the threshold that convergence is established + + damping_constant: + property_type: float + mandatory: False + default: 0.5 + help: damping constant + + threshold: + property_type: float + mandatory: True + help: > + specifies the threshold that is taken as convergence + (i.e. 0.05 means that the value does not change more than 5%) + + + t_inner: + damping_constant: + property_type: float + mandatory: False + default: 0.5 + help: damping constant + + threshold: + property_type: float + mandatory: False + help: > + specifies the threshold that is taken as convergence + (i.e. 0.05 means that the value does not change more than 5%) + + t_rad: + damping_constant: + property_type: float + mandatory: False + default: 0.5 + help: damping constant + + threshold: + property_type: float + mandatory: True + help: > + specifies the threshold that is taken as convergence + (i.e. 0.05 means that the value does not change more than 5%) + + + w: + damping_constant: + property_type: float + mandatory: False + default: 0.5 + help: damping constant + + threshold: + property_type: float + mandatory: True + help: > + specifies the threshold that is taken as convergence + (i.e. 0.05 means that the value does not change more than 5%) + +spectrum: + property_type: quantity_range_sampled + default: None + mandatory: True + help: Final spectrum sampling + diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py new file mode 100644 index 00000000000..c6c0d664982 --- /dev/null +++ b/tardis/io/default_config_parser.py @@ -0,0 +1,1187 @@ +# coding=utf-8 + +import re +import logging +from astropy import units +from tardis.util import parse_quantity +from astropy.units.core import UnitsException +from tardis.atomic import symbol2atomic_number +import yaml +import pprint + +logger = logging.getLogger(__name__) + + + +class Error(Exception): + """Base class for exceptions in the config parser.""" + pass + + +class ConfigTypeError(Error, ValueError): + """ + Exception raised if the type of the configured value mismatches the type + specified in the default configuration. + """ + + def __init__(self, value, expected_type, help): + self.value = value + self.expected_type = expected_type + self.help = help + + def __str__(self): + return "Expected type %s but found %s.\nHelp:%s " % \ + (repr(self.expected_type), repr(type(self.value)), help) + + +class ConfigError(Error): + """ + Exception raised if something is wrong in the configuration. + """ + + def __init__(self, path): + self.path = path + + def __str__(self): + return "Error in the configuration at %s " % ("->".join(self.path)) + +class ConfigValueError(ConfigError, ValueError): + """ + Exception raised if the given value does not match the allowed constraints. + """ + + default_msg = "Given value (%s) not allowed in constraint (%s). [%s]" + def __init__(self, config_value, allowed_constraint, path, msg=None): + self.config_value = config_value + self.allowed_constraint = allowed_constraint + self.path = path + if msg is None: + self.msg = self.default_msg + else: + self.msg = msg + + def __str__(self): + return self.msg % (str(self.config_value), str(self.allowed_constraint), self.path) + + + + + + + + +class DefaultConfigError(ConfigError): + """ + Exception raised if something is wrong in the default configuration. + """ + + def __str__(self): + return "Error in the default configuration at %s " % \ + ("->".join(self.path)) + + +class PropertyType(object): + def __init__(self): + self._default = None + self._allowed_value = None + self._allowed_type = None + self._help = None + self._mandatory = False + self._lower = None + self._upper =None + pass + + @property + def default(self): + return self._default + + @default.setter + def default(self, value): + self._default = self.to_type(value) + + @property + def allowed_value(self): + return self._allowed_value + + @allowed_value.setter + def allowed_value(self, value): + if isinstance(value, basestring): + self._allowed_value = set(self.__list_dtype(value.split())) + elif isinstance(value, list) or isinstance(value, set): + self._allowed_value = set(self.__list_dtype(value)) + elif isinstance(value, float) or isinstance(value, int): + self._allowed_type = set([value]) + else: + raise ValueError("Can not set allowed value.") + + + + @property + def allowed_type(self): + return self._allowed_value + + @allowed_type.setter + def allowed_type(self, value): + self._allowed_type = value + if '_parse_allowed_type' in (set(dir(self.__class__)) - set(dir(PropertyType))) and value != None: + self._lower, self._upper = self._parse_allowed_type(value) + + @property + def help(self): + return self._help + + @help.setter + def help(self, value): + self._help = value + + @property + def mandatory(self): + return self._mandatory + + @mandatory.setter + def mandatory(self, value): + self._mandatory = value + + def check_type(self, value): + return True + + def to_type(self, value): + return value + + def __list_dtype(self, mixed_list): + try: + tmp = [str(a) for a in mixed_list] + except ValueError: + try: + tmp = [float(a) for a in mixed_list] + except ValueError: + try: + tmp = [int(a) for a in mixed_list] + except: + raise ValueError("Forbidden type in allowed_type") + return tmp + + + def _check_allowed_value(self, _value): + """ + Returns True if the value is allowed or no allowed value is given. + """ + if self._allowed_value != None: + atype = type(iter(self.allowed_value).next()) + value = atype(_value) + if value in self.allowed_value: + return True + else: + return False + else: + return True + + def __repr__(self): + if hasattr(self, "_allowed_type"): + return "Type %s; Allowed type: %s" %(self.__class__.__name__, self._allowed_type) + else: + return "Type %s; " %(self.__class__.__name__) + + +class PropertyTypeContainer(PropertyType): + + def check_type(self): + pass + +class PropertyTypeBool(PropertyType): + + def check_type(self, value): + try: + foo = bool(value) + return True + except: + return False + + def to_type(self, value): + return bool(value) + + + +class PropertyTypeInt(PropertyType): + + def check_type(self, value): + try: + int(value) + if float.is_integer(float(value)): + if self._check_allowed_value(value) and self._check_allowed_type(value): + return True + else: + return False + except ValueError: + return False + + def to_type(self, value): + return int(value) + #ToDo: use this if allowed type is specified + def _parse_allowed_type(self, allowed_type): + string = allowed_type.strip() + upper = None + lower = None + if string.find("<") or string.find(">"): + #like x < a + match = re.compile('[<][\s]*[0-9.+^*eE]*$').findall(string) + if match: + value = re.compile('[0-9.+^*eE]+').findall(string)[0] + upper = float(value) + #like a > x" + match = re.compile('^[\s0-9.+^*eE]*[\s]*[<]$').findall(string) + if match: + value = re.compile('[0-9.+^*eE]+').findall(string)[0] + upper = float(value) + #like x > a + match = re.compile('[>][\s]*[0-9.+^*eE]*$').findall(string) + if match: + value = re.compile('[0-9.+^*eE]+').findall(string)[0] + lower = float(value) + #like a < x + match = re.compile('^[\s0-9.+^*eE]*[\s]*[<]$').findall(string) + if match: + value = re.compile('[0-9.+^*eE]+').findall(string)[0] + lower = float(value) + return lower, upper + + def __check_type(self, value, lower_lim, upper_lim): + upper, lower = True, True + if upper_lim != None: + upper = value < upper_lim + if lower_lim != None: + lower = value > lower_lim + return upper and lower + + + def _check_allowed_type(self, value): + if self._allowed_type != None: + if self.__check_type(value, self._lower, self._upper): + return True + else: + return False + else: + return True + + def _is_valid(self, value): + if not self.check_type(value): + return False + if self.allowed_value != None: + return False + if not self.__check_type(value, self._lower, self._upper): + return False + return True + + + + + + +class PropertyTypeFloat(PropertyTypeInt): + + def check_type(self, value): + try: + float(value) + if self._check_allowed_value(value) and self._check_allowed_type(value): + return True + except ValueError: + return False + + def to_type(self, value): + return float(value) + + +class PropertyTypeQuantity(PropertyType): + + def check_type(self, value): + try: + quantity_split = value.strip().split() + quantity_value = quantity_split[0] + quantity_unit = ' '.join(quantity_split[1:]) + + print('--->>-') + print(self._default) + print(value) + print('----') + if self._default is not None : + + #d_quantity_split = self._default.strip().split() + self._default.to( quantity_unit ) + float(quantity_value) + units.Unit(quantity_unit) + return True + except ValueError: + return False + + def to_type(self, value): + quantity_split = value.strip().split() + quantity_value = quantity_split[0] + quantity_unit = ' '.join(quantity_split[1:]) + return float(quantity_value) * units.Unit(quantity_unit) + +class PropertyTypeQuantityRange(PropertyTypeQuantity): + + def _to_units(self, los): + if len(los) > 2: + loq = [(lambda x: (units.Quantity(float(x[0]),x[1])))(x.split()) for x in los[:-1]] + else: + loq = [(lambda x: (units.Quantity(float(x[0]),x[1])))(x.split()) for x in los] + try: + _ = reduce((lambda a, b: a.to(b.unit)), loq) + loq = [a.to(loq[0].unit) for a in loq] + return loq + except UnitsException as e: + msg = "Incompatible units in %s"%str(los) + str(e) + raise ValueError(msg) + + def check_type(self, value): + if isinstance(value, dict): + if reduce((lambda a, b: a and b in value), [True, 'start', 'end']): + los = [value['start'], value['end']] + loq = self._to_units(los) + if abs(loq[0].value - loq[1].value) > 0: + return True + elif isinstance(value, list): + if len(value) == 2: + loq = self._to_units(value) + if abs(loq[0].value - loq[1].value) > 0: + return True + return False + + def to_type(self, value): + if isinstance(value, list): + return self._to_units(value[:2]) + elif isinstance(value, dict): + los = [value['start'], value['end']] + return self._to_units(los) + + +class PropertyTypeQuantityRangeSampled(PropertyTypeQuantityRange): + + def check_type(self, value): + if isinstance(value, dict): + if reduce((lambda a, b: a and b in value), [True, 'start', 'stop', 'num']): + los = [value['start'], value['stop']] + loq = self._to_units(los) + if abs(loq[0].value - loq[1].value) > 0: + return True + elif isinstance(value, list): + if len(value) == 3: + loq = self._to_units(value) + if abs(loq[0].value - loq[1].value) > 0: + return True + return False + + def to_type(self, value): + if isinstance(value, list): + _tmp = self._to_units(value[:2]) + _tmp.append(value[2]) + return _tmp + elif isinstance(value, dict): + los = [value['start'], value['stop']] + _tmp = self._to_units(los) + _tmp.append(value['num']) + return _tmp + + +class PropertyTypeString(PropertyType): + + def check_type(self, value): + try: + str(value) + if self._check_allowed_value(value): + return True + except ValueError: + return False + + def to_type(self, value): + return str(value) + +class PropertyTypeStringList(PropertyTypeString): + + def check_type(self, value): + try: + str(value) + except ValueError: + return False + if value in self.allowed_value: + return True + else: + return False + + def to_type(self, value): + return str(value) + + pass + + +class PropertyTypeList(PropertyType): + + def check_type(self, value): + try: + return isinstance(value, list) + except ValueError: + return False + + def to_type(self, value): + if isinstance(value, list): + return value + elif isinstance(value, basestring): + return value.split() + else: + return [] + + +class PropertyTypeRange(PropertyType): + + def check_type(self, value): + if isinstance(value, dict): + if reduce((lambda a, b: a in value), [True, 'start', 'stop']): + if abs(value['start'] - value['stop']) > 0: + return True + elif isinstance(value, list): + if len(value) == 2: + if abs(value[0] - value[1]) > 0: + return True + return False + + def to_type(self, value): + if isinstance(value, list): + return value + elif isinstance(value, dict): + return [value['start'], value['stop']] + +class PropertyTypeRangeSampled(PropertyTypeRange): + + def check_type(self, value): + if isinstance(value, dict): + if reduce((lambda a, b: a in value),\ + [True, 'start', 'stop', 'num']): + if abs(value['start'] - value['stop']) > 0: + return True + elif isinstance(value, list): + if len(value) == 3: + if abs(value[0] - value[1]) > 0: + return True + return False + + def to_type(self, value): + if isinstance(value, list): + return value + elif isinstance(value, dict): + return [value['start'], value['stop'], value['num']] + +class PropertyTypeAbundances(PropertyType): + + elements = { 'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, 'ds':110, 'rg':111, 'cn':112 } + + def check_type(self, _value): + value = dict((k.lower(), v) for k,v in _value.items()) + if set(value).issubset(set(self.elements)): + return True + else: + return False + + def to_type(self, _value): + if isinstance(_value, dict): + value = dict((k.lower(), v) for k,v in _value.items()) + abundances = dict.fromkeys(self.elements.copy(), 0.0) + for k in value: + abundances[k] = value[k] + abundances = {k: v for k, v in abundances.items() if not (v == 0.)} + return abundances + else: + raise ConfigError + +class PropertyTypeLegacyAbundances(PropertyType): + + elements = { 'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, 'ds':110, 'rg':111, 'cn':112 } + types = ['uniform'] + + def check_type(self, _value): + value = dict((k.lower(), v) for k,v in _value.items()) + if 'type' in value: + if value['type'] in self.types: + print('type is ok') + tmp = value.copy() + tmp.pop('type', None) + if set(tmp).issubset(set(self.elements)): + return True + else: + return False + return False + + def to_type(self, _value): + if isinstance(_value, dict): + value = dict((k.lower(), v) for k,v in _value.items()) + abundances = dict.fromkeys(self.elements.copy(), 0.0) + for k in value: + abundances[k] = value[k] + abundances['type'] = value['type'] + return abundances + else: + raise ConfigError + + + + + +class DefaultParser(object): + """Not invented here syndrome""" + + __check = {} + __convert = {} + __list_of_leaf_types = [] + __types = {} + + def __init__(self, default_dict, item_path=None): + """Creates a new property object for the given config level + :param default_dict: default configuration + :return: + """ + + self.__item_path = item_path + #create property type dict + self.__types['arbitrary'] = PropertyType + + self.__types['int'] = PropertyTypeInt + self.__register_leaf('int') + + self.__types['float'] = PropertyTypeFloat + self.__register_leaf('float') + + self.__types['quantity'] = PropertyTypeQuantity + self.__register_leaf('quantity') + + self.__types['quantity_range'] = PropertyTypeQuantityRange + self.__register_leaf('quantity_range') + + self.__types['quantity_range_sampled'] = PropertyTypeQuantityRangeSampled + self.__register_leaf('quantity_range_sampled') + + self.__types['string'] = PropertyTypeString + self.__register_leaf('string') + + + self.__types['range'] = PropertyTypeRange + self.__register_leaf('range') + + self.__types['range_sampled'] = PropertyTypeRangeSampled + self.__register_leaf('range_sampled') + + self.__types['list'] = PropertyTypeList + self.__register_leaf('list') + + self.__types['container-declaration'] = PropertyTypeContainer + self.__register_leaf('container-declaration') + + self.__types['container-property'] = PropertyTypeContainer + self.__register_leaf('container-property') + + self.__types['abundance_set'] = PropertyTypeAbundances + self.__register_leaf('abundance_set') + + self.__types['legacy-abundances'] =PropertyTypeLegacyAbundances + self.__register_leaf('legacy-abundances') + + self.__types['bool'] = PropertyTypeBool + self.__register_leaf('bool') + + self.__mandatory = False + self.__default_value = None + + self.__allowed_value = None + self.__allowed_type = None + self.__config_value = None + self.__path = None + + self.__default_dict = default_dict + + if not 'property_type' in default_dict: + self.__property_type = 'arbitrary' + else: + self.__property_type = default_dict['property_type'] + #print(self.__property_type) + #print(self.__types.keys()) + if not self.__property_type in self.__types.keys(): + raise ValueError + self.__type = self.__types[self.__property_type]() + + if 'allowed_value' in default_dict: + self.__type.allowed_value = default_dict['allowed_value'] + + if 'allowed_type' in default_dict: + self.__type.allowed_type = default_dict['allowed_type'] + +#ToDo: move all to classes + if 'default' in default_dict: + if default_dict['default'] != None and not default_dict['default'] in ['None','']: + self.__type.default = default_dict['default'] + + if 'mandatory' in default_dict: + self.__type.mandatory = default_dict['mandatory'] + + self.is_leaf = self.__is_leaf(self.__property_type) + + def get_default(self): + """Returns the default value of this property, if specified. + :return: default value + """ + return self.__type.default + + def set_default(self, value): + """ + Set a new default value. + :param value: new default value + """ + if value is not None: + if self.__type.check_type(value): + self.__type.default = value + else: + raise ConfigValueError(value, self.__type.allowed_value, self.get_path_in_dict(), msg='Default value (%s) violates property constraint (%s). [%s]') + else: + self.__type.default = None + + def is_mandatory(self): + """ + Returns True if this property is a mandatory. + :return: mandatory + """ + return self.__type.mandatory + + def has_default(self): + """ + Returns True if this property has a default value + :return: has a default value + """ + try: + if self.__type.default != None: + return True + else: + return False + except NameError: + pass + + def set_path_in_dic(self, path): + """ + Set the path to this property in the config + :param path: path(chain of keys) + :return: + """ + self.__path = path + + def get_path_in_dict(self): + """ + Returns the path of this property in the config + :return: path + """ + return self.__path + + def set_config_value(self, value): + """ + Set a new value + :param value: + :return: + """ + self.__config_value = value + + def get_value(self): + """ + Returns the configuration value from the configuration. + If the value specified in the configuration is invalid + the default value is returned + :return: value + """ + if (self.__config_value is not None): + if self.__type.check_type(self.__config_value): + return self.__type.to_type(self.__config_value) + else: + raise ConfigValueError(self.__config_value, self.__type.allowed_value, self.get_path_in_dict()) + else: + if self.has_default(): + logger.info("Value <%s> specified in the configuration violates a constraint\ + given in the default configuration. Expected type: %s. Using the default value."%(str(self.__config_value),str(self.__property_type))) + return self.__type.default + else: + if self.is_mandatory(): + raise ValueError('Value is mandatory, but no value was given in default configuration. [%s]' %str(self.get_path_in_dict())) + else: + logger.info("Value is not mandatory and is not specified in the configuration. [%s]" %(str(self.get_path_in_dict()))) + return None + + + def is_container(self): + """ + Returns True if this property is of type container. + :return: + """ + return self.__is_container() + + def get_container_dic(self): + """ + If this property is a container it returns the corresponding + container dictionary + :return: container dictionary + """ + if self.__is_container(): + return self.__container_dic + + @classmethod + def update_container_dic(cls, container_dic, current_entry_name): + if reduce(lambda a, b: a or b,\ + [container_dic.has_key(i) for i in ['and', 'or']], True): + if 'or' in container_dic: + if current_entry_name in container_dic['or']: + container_dic['or'] = [] + return container_dic + if 'and' in container_dic: + if current_entry_name in container_dic['and']: + current_entry_name['and'].remove(current_entry_name) + return container_dic + + + def is_valid(self, value): + if not self.__check[self.__property_type](self, value): + return False + if self.__allowed_value: + if not self.__is_allowed_value(value, self.__allowed_value): + return False + if self.__allowed_type: + if not self.__check_value(value, self.__lower, self.__upper): + return False + return True + + def __register_leaf(self, type_name): + #print(type_name) + if not type_name in self.__list_of_leaf_types: + self.__list_of_leaf_types.append(type_name) + + def __is_leaf(self, type_name): + return type_name in self.__list_of_leaf_types + + def __is_container(self): + if self.__property_type == 'container-property': + try: + self.__container_dic = self.__default_dict['type']['containers'] + return True + except KeyError: + return False + else: + return False + +# __check['container-property'] = __is_container + + def __is_container_declaration(self, value): + pass + + +class Container(DefaultParser): + def __init__(self, container_default_dict, container_dict, container_path=None): + """Creates a new container object. + :param container_default_dict: Dictionary containing the default properties of the container. + :param container_dict: Dictionary containing the configuration of the container. + """ + + #self.__register_leaf('list') + #self.__register_leaf('int') + #self.__register_leaf('float') + #self.__register_leaf('quantity') + #self.__register_leaf('string') + + self.__container_path = container_path + self.__type = None + self.__allowed_value = None + self.__allowed_type = None + self.__config_value = None + self.__path = None + self.__paper_abundances = False + self.__has_additional_items = False + + self.__property_type = 'container-property' + + self.__default_container = {} + self.__config_container = {} + + #check if it is a valid default container + if not 'type' in container_default_dict: + raise ValueError('The given default container is no valid') + + #set allowed containers + try: + self.__allowed_container = container_default_dict['type']['containers'] + except KeyError: + raise ValueError('No container names specified') + + #check if the specified container in the config is allowed + try: + #print(container_dict) + if not container_dict['type'] in self.__allowed_container: + + raise ValueError('Wrong container type') + else: + type_dict = container_dict['type'] + self.__type = container_dict['type'] + except KeyError: + raise ValueError('No container type specified') + + #get selected container from conf + try: + self.__selected_container = container_dict['type'] + except KeyError: + self.__selected_container = None + raise ValueError('No container type specified in config') + + ####This is for the uniform abundances section in the paper. + if self.__type == 'uniform' and self.__container_path[-1] == 'abundances': + self.__paper_abundances = True + cabundances_section = PropertyTypeAbundances() + tmp_container_dict = dict(container_dict) + tmp_container_dict.pop('type', None) + cabundances_section.check_type(tmp_container_dict) + tmp = cabundances_section.to_type(tmp_container_dict) + self.__default_container, self.__config_container = tmp, tmp + #### + else: + #look for necessary items + entry_name = '_' + self.__selected_container + try: + necessary_items = container_default_dict['type'][entry_name] + except KeyError: + raise ValueError('Container insufficient specified') + + #look for additional items + entry_name = '+' + self.__selected_container + try: + additional_items = container_default_dict['type'][entry_name] + self.__has_additional_items = True + except KeyError: + self.__has_additional_items = False + pass + + + def parse_container_items(top_default, top_config, level_name, full_path): + """Recursive parser for the container default dictionary and the container configuration dictionary. + + :param top_default: container default dictionary of the upper recursion level + :param top_config: container configuration dictionary of the upper recursion level + :param level_name: name(key) of the of the upper recursion level + :param path: path in the nested container dictionary from the main level to the current level + :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + each branch. If the current recursion level is a leaf the configured value and a configuration object is + returned + """ + path = reduce_list(list(full_path), self.__container_path + [item]) + print('--C') + print(item) + print(full_path) + print(path) + print('--') + tmp_conf_ob = {} + tmp_conf_val = {} + #pdb.set_trace() + if isinstance(top_default, dict): + default_property = DefaultParser(top_default) + if default_property.is_container(): + container_conf = get_value_by_path(top_config, path) + ccontainer = Container(top_default, container_conf) + return ccontainer.get_container_ob(), ccontainer.get_container_conf() + elif not default_property.is_leaf: + # print(top_default.items()) + for k, v in top_default.items(): + print('>>><<<') + print(k) + tmp_conf_ob[k], tmp_conf_val[k] = parse_container_items(v, top_config, k, full_path + [k]) + return tmp_conf_ob, tmp_conf_val + else: + default_property.set_path_in_dic(path) + try: + conf_value = get_value_by_path(top_config, path) + except KeyError: + conf_value = None + + if conf_value is not None: + default_property.set_config_value(conf_value) + + return default_property, default_property.get_value() + + def reduce_list(a,b): + """ + removes items from list a which are in b + """ + for k in b: + a.remove(k) + return a + + + def get_value_by_path(dict, path): + """ + Value from a nested dictionary specified by its path. + :param dict: nested source dictionary + :param path: path (composed of keys) in the dictionary + :return: + """ + for key in path: + dict = dict[key] + return dict + + if not self.__paper_abundances: + for item in necessary_items: + if not item in container_dict.keys(): + raise ValueError('Entry %s is missing in container [%s]' % (str(item), self.__container_path)) + else: + self.__default_container[item], self.__config_container[item] = parse_container_items(container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) + if self.__has_additional_items: + for item in additional_items: + try: + self.__default_container[item], self.__config_container[item] = parse_container_items(container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) + except KeyError: + pass + + #go through all items and create an conf object thereby check the conf + self.__container_ob = self.__default_container + if isinstance(self.__config_container, dict): + self.__conf = self.__config_container + else: + pdb.set_trace() + self.__conf = {"No Name":self.__config_container} + + + def get_container_ob(self): + """ + Return the container configuration object + :return: + """ + return self.__container_ob + + def get_container_conf(self): + """ + Return the configuration + :return: + """ + self.__conf['type'] = self.__type + return self.__conf + + +class Config(object): + """ + An configuration object represents the parsed configuration. + """ + + + def __init__(self, default_configuration, input_configuration): + """Creates the configuration object. + :param default_configuration: Default configuration dictionary + :param input_configuration: Configuration dictionary + """ + self.__conf_o = None + self.__conf_v = None + self.mandatories = {} + self.fulfilled = {} + self.__create_default_conf(default_configuration) + self.__parse_config(default_configuration, input_configuration) + self.__help_string = '' + + @classmethod + def from_yaml(cls, fname_config, fname_default): + with open(fname_config) as f: + conff = f.read() + conf = yaml.safe_load(conff) + with open(fname_default) as f: + defaf = f.read() + defa = yaml.safe_load(defaf) + return cls(defa, conf) + + + def __mandatory_key(self, path): + """Return the key string for dictionary of mandatory entries + :param path: path (composed of keys) in the dictionary + :return: corresponding key + """ + return ':'.join(path) + + + + def register_mandatory(self, name, path): + """Register a mandatory entry + :param name: name of the mandatory entry to be registered + :param path: path (composed of keys) in the dictionary + """ + self.mandatories[self.__mandatory_key(path)] = name + + def deregister_mandatory(self, name, path): + """Register a deregistered mandatory entry + :param name: name of the mandatory entry to be deregistered + :param path: path (composed of keys) in the dictionary + """ + self.fulfilled[self.__mandatory_key(path)] = name + + def is_mandatory_fulfilled(self): + """ + Check if all mandatory entries are deregistered. + """ + if len(set(self.mandatories.keys()) - set(self.fulfilled.keys())) <= 0: + return True + else: + return False + + def __parse_config(self, default_configuration, configuration): + """Parser for the default dictionary and the configuration dictionary. + :param default_configuration: Default configuration dictionary + :param configuration: Configuration dictionary + """ + + def find_item(dict, key): + """ + Returns the value for a specific key in a nested dictionary + :param dict: nested dictionary + :param key: + """ + if key in dict: return dict[key] + for k, v in dict.items(): + if isinstance(v, dict): + item = find_item(v, key) + if item is not None: + return item + + + def get_property_by_path(d, path): + """ Returns the value for a specific path(chain of keys) in a nested dictionary + :param dict: nested dictionary + :param path: chain of keys as list + """ + if len(path)<=0: + return d + else: + try: + v = d + for k in path: + v = v[k] + return v + except KeyError: + return None + + def recursive_parser(top_default, configuration, path): + """ + Recursive parser for the default dictionary. + :param top_default: container default dictionary of the upper recursion level + :param configuration: configuration dictionary + :param path: path in the nested container dictionary from the main level to the current level + :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + each branch. If the current recursion level is a leaf, the configuration value and object are + returned + """ + tmp_conf_ob = {} + tmp_conf_val = {} + if isinstance(top_default, dict): + default_property = DefaultParser(top_default, item_path=path) + if default_property.is_mandatory(): + self.register_mandatory(self, path) + self.deregister_mandatory(self, path) + + if default_property.is_container(): + container_conf = get_property_by_path(configuration, path) + try: + ccontainer = Container(top_default, container_conf, container_path=path) + return ccontainer.get_container_ob(), ccontainer.get_container_conf() + except: + return None, None + elif not default_property.is_leaf: + no_default = self.__check_items_in_conf(get_property_by_path(configuration, path), top_default) + if len(no_default) > 0: + logger.warning('The items %s from the configuration are not specified in the default configuration'%str(no_default)) + for k, v in top_default.items(): + #print('>---<') + #print(k) + tmp_conf_ob[k], tmp_conf_val[k] = recursive_parser(v, configuration, path + [k]) + #print(tmp_conf_val[k]) + return tmp_conf_ob, tmp_conf_val + else: + default_property.set_path_in_dic(path) + try: +# print('get_property_by_path') + #print(path) + conf_value = get_property_by_path(configuration, path) +# print(conf_value) +# print('End:get_property_by_path') + except KeyError: + conf_value = None + + if conf_value is not None: + default_property.set_config_value(conf_value) + return default_property, default_property.get_value() + + + self.__conf_o, self.__conf_v = recursive_parser(default_configuration, configuration, []) + # print('|\|\|\|') + # print(self.__conf_v) + + def __check_items_in_conf(self, config_dict, default_dict): + if isinstance(config_dict, dict) and len(config_dict) > 0: + return list(set(config_dict.keys()) - set(default_dict.keys())) + else: + return list(default_dict.keys()) + + + + def __create_default_conf(self, default_conf): + """Returns the default configuration values as dictionary. + :param default_conf: default configuration dictionary + :return: default configuration values + """ + + def recursive_default_parser(top_default, path): + """Recursive parser for the default dictionary. + :param top_default: container default dictionary of the upper recursion level + :param path: path in the nested container dictionary from the main level to the current level + :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + each branch. If the current recursion level is a leaf, the default configuration value is + returned + """ + tmp_default = {} + if isinstance(top_default, dict): + default_property = DefaultParser(top_default) + if not default_property.is_container(): + if not default_property.is_leaf: + for k, v in top_default.items(): + tmp_default[k] = recursive_default_parser(v, path + [k]) + return tmp_default + else: + default_property.set_path_in_dic(path) + if default_property.has_default(): + return default_property.get_default() + else: + return None + + self.__default_config = recursive_default_parser(default_conf, []) + + + + def get_config(self): + """Returns the parsed configuration as dictionary. + :return: configuration values as dictionary + """ + print(self.__conf_v) + return self.__conf_v + + def get_default_config(self): + """Returns the default configuration values as dictionary + :return: default configuration values as dictionary + """ + return self.__default_config + + def get_config_object(self): + """Returns the default configuration objects as dictionary + :return: default configuration objects as dictionary + """ + return self.__conf_o + + def get_help(self): + return(pprint.pformat(self.get_default_config())) + + + def __repr__(self): + return(str(pprint.pformat(self.get_config()))) + + diff --git a/tardis/io/tests/data/tardis_configv1_artis_density_v_slice.yml b/tardis/io/tests/data/tardis_configv1_artis_density_v_slice.yml index 528bd380098..53dfab507d9 100644 --- a/tardis/io/tests/data/tardis_configv1_artis_density_v_slice.yml +++ b/tardis/io/tests/data/tardis_configv1_artis_density_v_slice.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 diff --git a/tardis/io/tests/data/tardis_configv1_ascii_density.yml b/tardis/io/tests/data/tardis_configv1_ascii_density.yml index 87ba8bfcfce..88bae0e81c1 100644 --- a/tardis/io/tests/data/tardis_configv1_ascii_density.yml +++ b/tardis/io/tests/data/tardis_configv1_ascii_density.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 diff --git a/tardis/io/tests/data/tardis_configv1_ascii_density_uniabund.yml b/tardis/io/tests/data/tardis_configv1_ascii_density_uniabund.yml index f1d596f89b3..7c0a8b9e61d 100644 --- a/tardis/io/tests/data/tardis_configv1_ascii_density_uniabund.yml +++ b/tardis/io/tests/data/tardis_configv1_ascii_density_uniabund.yml @@ -5,7 +5,7 @@ #Currently only simple1d is allowed tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 @@ -47,12 +47,12 @@ montecarlo: last_no_of_packets: 1.e+5 no_of_virtual_packets: 5 - convergence_criteria: + convergence_strategy: type: specific damping_constant: 1.0 threshold: 0.05 fraction: 0.8 - hold: 3 + hold-iterations: 3 t_inner: damping_constant: 1.0 From 97dffa7be1c0cc933f7454b1b85384bccaee986c Mon Sep 17 00:00:00 2001 From: Michi Date: Thu, 24 Apr 2014 16:56:55 +0200 Subject: [PATCH 02/15] add new test to the default parser --- tardis/io/tests/test_default_config_parser.py | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 tardis/io/tests/test_default_config_parser.py diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py new file mode 100644 index 00000000000..588170cbfbc --- /dev/null +++ b/tardis/io/tests/test_default_config_parser.py @@ -0,0 +1,160 @@ +import tardis +from tardis.io.default_config_parser import DefaultParser, Config + +import os +import yaml +import pytest +from glob import glob + +existing_configs = glob(os.path.join('tardis', 'docs', 'examples', '*.yml')) +config_definition = os.path.join('tardis', 'data', 'tardis_default_config_definition.yml') + +@pytest.mark.parametrize(("config_filename",), existing_configs) +def test_configread(config_filename): + config = Config.from_yaml(config_filename, config_definition) + + +#test the whole thing +def test_default_config_parser(): + test_config_fname = os.path.join(tardis.__path__[0], 'data', 'conf_tes.yml') + test_default_fname = os.path.join(tardis.__path__[0], 'data', 'conf_def.yml') + + with open(test_config_fname) as f: + test_config = yaml.SafeLoader(f) + + with open(test_default_fname) as f: + test_default = yaml.SafeLoader(f) + + + test_conf_ob = Config(test_default, test_config) + + +def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory): + test_ob = DefaultParser(test_dic) + + if not default == None: + dhelper = True + else: + dhelper = False + + assert test_ob.has_default() == dhelper + assert test_ob.get_default() == default + assert test_ob.is_leaf + assert test_ob.is_container() == container + assert test_ob.is_mandatory() == mandatory + + #set good default + test_ob.set_default(default) + + assert test_ob.get_default() == default + #set bad default + if not wdefault == None: + with pytest.raises(ValueError): + test_ob.set_default(wdefault) + + assert test_ob.get_value() == default + + #set good value + test_ob.set_config_value(value) + + assert test_ob.get_value() == value + + #set bad value + if not wvalue == None: + test_ob.set_config_value(wvalue) + assert test_ob.get_value() == default + + return 0 + + + +def test_default_parser_float(): + example_dic = {'default': 99.99, + 'help': 'float value for testing', + 'mandatory': True, + 'property_type': 'float'} + default = 99.99 + wdefault = "xx" + value = 11.12 + wvalue = "yy" + container = False + mandatory = True + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + + +def test_default_parser_integer(): + example_dic = {'default': 99, + 'help': 'integer value for testing', + 'mandatory': True, + 'property_type': 'int'} + + default = 99 + wdefault = 9.15 + value = 11 + wvalue = 9.22 + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + +def test_default_parser_quantity(): + example_dic = {'default': '99.99 cm', + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity'} + + default = "99.99 cm" + wdefault = "kl" + value = "11.12 m" + wvalue = "yy" + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + + +def test_default_parser_range(): + example_dic = {'default': [0, 10], + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range'} + + default = [0,10] + wdefault = 1 + value = [7,8] + wvalue = 2 + container = False + mandatory = False + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + +def test_default_parser_range_sampled(): + example_dic = {'default': [0, 10, 1], + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range_sampled'} + + default = [0,10,1] + wdefault = [1,3] + value = [1,5,1] + wvalue = [1,1] + container = False + mandatory = False + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + +def test_default_parser_string(): + example_dic = {'default': 'DEFAULT', + 'help': 'string for testing', + 'mandatory': True, + 'property_type': 'string'} + + default = "DEFAULT" + wdefault = None + value = "blub" + wvalue = None + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + From 1c82be9dac97985c5a7f967c7efef78bd37b06ac Mon Sep 17 00:00:00 2001 From: Michi Date: Thu, 24 Apr 2014 16:59:28 +0200 Subject: [PATCH 03/15] added documentation to branch --- docs/default_config_parser.rst | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/default_config_parser.rst diff --git a/docs/default_config_parser.rst b/docs/default_config_parser.rst new file mode 100644 index 00000000000..48ce4881b51 --- /dev/null +++ b/docs/default_config_parser.rst @@ -0,0 +1,72 @@ + +Default Configuration Parser +============================ + +The default config parser takes a user configuration and a default configuration and creates a consistent and valid configuration for tardis based on the constraints given in the default configuration. Both input data are normally given as a yaml dictionary with a consistent hierarchical structure i.e. for every item in the user configuration there has to be a declaration in the default configuration at the same hierarchical level. This declaration can be either an unspecific empty level declaration like: +- Main_level: + - Second_level: + - Third_level: + … +Or a declaration of a configuration item like: +- item: + - property_type: int + - default: 1 + - mandatory: True + - help: ‘This is a doc string.' + +This contains always the keywords help, default, mandatory, and property_type. The keyword help is a doc-string which describes the corresponding item. Default specifies the default value which is used in case that no value for this item is specified in the corresponding user configuration item. If the keyword mandatory is True, the item has to be specified in the user configuration. The keyword property_type is used to specify the type of the item. At the moment, the config parser knows the following types: +Int: The property type int is for integer like config items. +Float: The property type float is for float like config items. +String: The property type string is for string like config items. +Quantity: The property type quantity is for physical quantities with units given as string. The string contains value and unit separated by a whitespace E.g. 2 cm. +Range: The property type range specifies a range via start and end. Note: abs(start - end ) > 0 +Quantity_range: Like property type range but with quantities as start and stop. The consistency of the units is checked. +Additionally to the four standard keywords the types integer, float, and quantity can have the keywords allowed_value and allowed_type. allowed_value specifies the allowed values in a list, whereas allowed_type specifies a range of allowed values like “x>10”. + +Container +--------- + +For more complex configurations with dependencies, you can use the containers which allow branching in the configuration. A container is declared in the default configuration file by setting the property_type to container property and specifying the properties of the container with keyword type. The property_type of this section is container-declaration which allows you to specify the possible container items with the keyword container. For every specified container item, the code expects the declaration of all sub items. The keywords for this are “_“ + “name of the container item”. +If the type declaration for this container is finished you can specify all container items like normal items. Here is an example for a container configuration with two branches +- container_example: + - property_type: container-property + - type: + - property_type: container-declaration + - containers: ['one', 'two', 'three'] + - _one: ['one_one', 'one_two'] + - _two: ['two_one'] + + - one_one: + - property_type: string + - default: 'This is a container item' + - mandatory: False + - help: This is a container item from the container one. + + - one_two: + - sub_one_two_one: + - property_type: string + - default: 'This is a container item' + - mandatory: False + - help: This is a container item from the container one. + - sub_one_two_two: + - property_type: string + - default: 'This is a container item' + - mandatory: False + - help: This is a container item from the container one. + + - two_one: + - quantity_range: + - property_type: quantity_range + - default: [1 m,10 cm] #[Start,End] + - mandatory: False + - help: Like property type range but with quantities as start and stop. The consistency of the units is checked. + +How to use +---------- + +To use the default parser create a new config object form the class Config by either from a dictionaries or from yaml files. +- My_config = Config(default configuration dictionary, user configuration dictionary) +or +- My_config = Config.from_yaml(default configuration file, user configuration file) +To access the configuration for tardis use the method get_config + From b493e3edf5bba51ff394ef793109c68a00c03e16 Mon Sep 17 00:00:00 2001 From: Michi Date: Thu, 24 Apr 2014 23:48:28 +0200 Subject: [PATCH 04/15] today i fixed the test for the default config parser --- tardis/io/default_config_parser.py | 60 +++++++++++++++++-- tardis/io/tests/test_default_config_parser.py | 35 ++++------- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index c6c0d664982..fb7a908c4dd 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -8,6 +8,7 @@ from tardis.atomic import symbol2atomic_number import yaml import pprint +import ast logger = logging.getLogger(__name__) @@ -298,6 +299,11 @@ def check_type(self, value): quantity_split = value.strip().split() quantity_value = quantity_split[0] quantity_unit = ' '.join(quantity_split[1:]) + try: + float(quantity_value) + units.Unit(quantity_unit) + except ValueError: + return False print('--->>-') print(self._default) @@ -310,7 +316,7 @@ def check_type(self, value): float(quantity_value) units.Unit(quantity_unit) return True - except ValueError: + except (ValueError,AttributeError): return False def to_type(self, value): @@ -418,16 +424,29 @@ def to_type(self, value): class PropertyTypeList(PropertyType): def check_type(self, value): - try: - return isinstance(value, list) - except ValueError: - return False + if isinstance(value, list): + return True + elif isinstance(value, basestring): + try: + ast.literal_eval(value) + return True + except SyntaxError: + try: + value.split() + return True + except: + return False + return False + def to_type(self, value): if isinstance(value, list): return value elif isinstance(value, basestring): - return value.split() + try: + return ast.literal_eval(value) + except SyntaxError: + return value.split() else: return [] @@ -443,6 +462,15 @@ def check_type(self, value): if len(value) == 2: if abs(value[0] - value[1]) > 0: return True + elif isinstance(value, basestring): + try: + clist = ast.literal_eval(value) + if abs(clist[0] - clist[1]) > 0: + return True + except SyntaxError: + clist = value.split() + if abs(clist[0] - clist[1]) > 0: + return True return False def to_type(self, value): @@ -450,6 +478,12 @@ def to_type(self, value): return value elif isinstance(value, dict): return [value['start'], value['stop']] + elif isinstance(value, basestring): + try: + return ast.literal_eval(value) + except SyntaxError: + return value.split() + class PropertyTypeRangeSampled(PropertyTypeRange): @@ -463,6 +497,15 @@ def check_type(self, value): if len(value) == 3: if abs(value[0] - value[1]) > 0: return True + elif isinstance(value, basestring): + try: + clist = ast.literal_eval(value) + if abs(clist[0] - clist[1]) > 0: + return True + except SyntaxError: + clist = value.split() + if abs(clist[0] - clist[1]) > 0: + return True return False def to_type(self, value): @@ -470,6 +513,11 @@ def to_type(self, value): return value elif isinstance(value, dict): return [value['start'], value['stop'], value['num']] + elif isinstance(value, basestring): + try: + return ast.literal_eval(value) + except SyntaxError: + return value.split() class PropertyTypeAbundances(PropertyType): diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 588170cbfbc..732c9a964af 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -1,6 +1,7 @@ import tardis -from tardis.io.default_config_parser import DefaultParser, Config +from tardis.io.default_config_parser import DefaultParser, Config, ConfigValueError +from astropy import units as u import os import yaml import pytest @@ -14,20 +15,6 @@ def test_configread(config_filename): config = Config.from_yaml(config_filename, config_definition) -#test the whole thing -def test_default_config_parser(): - test_config_fname = os.path.join(tardis.__path__[0], 'data', 'conf_tes.yml') - test_default_fname = os.path.join(tardis.__path__[0], 'data', 'conf_def.yml') - - with open(test_config_fname) as f: - test_config = yaml.SafeLoader(f) - - with open(test_default_fname) as f: - test_default = yaml.SafeLoader(f) - - - test_conf_ob = Config(test_default, test_config) - def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory): test_ob = DefaultParser(test_dic) @@ -37,6 +24,7 @@ def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, else: dhelper = False + assert test_ob.has_default() == dhelper assert test_ob.get_default() == default assert test_ob.is_leaf @@ -44,25 +32,26 @@ def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, assert test_ob.is_mandatory() == mandatory #set good default - test_ob.set_default(default) + test_ob.set_default(str(default)) assert test_ob.get_default() == default #set bad default - if not wdefault == None: + if wdefault is not None: with pytest.raises(ValueError): test_ob.set_default(wdefault) assert test_ob.get_value() == default #set good value - test_ob.set_config_value(value) + test_ob.set_config_value(str(value)) assert test_ob.get_value() == value #set bad value - if not wvalue == None: - test_ob.set_config_value(wvalue) - assert test_ob.get_value() == default + if wvalue is not None: + with pytest.raises(ConfigValueError): + test_ob.set_config_value(wvalue) + test_ob.get_value() return 0 @@ -103,9 +92,9 @@ def test_default_parser_quantity(): 'mandatory': True, 'property_type': 'quantity'} - default = "99.99 cm" + default = 99.99 * u.cm wdefault = "kl" - value = "11.12 m" + value = 11.12 * u. m wvalue = "yy" container = False mandatory = True From 81add23917bd2467b4c9f989fbccd4ae2e667521 Mon Sep 17 00:00:00 2001 From: Michi Date: Fri, 25 Apr 2014 13:49:12 +0200 Subject: [PATCH 05/15] code cleanup the first act --- tardis/io/default_config_parser.py | 406 +++++++++--------- .../data/tardis_configv1_artis_density.yml | 2 +- tardis/io/tests/test_default_config_parser.py | 122 +++--- 3 files changed, 265 insertions(+), 265 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index fb7a908c4dd..dd0a227d986 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -2,16 +2,15 @@ import re import logging +import pprint +import ast + from astropy import units -from tardis.util import parse_quantity from astropy.units.core import UnitsException -from tardis.atomic import symbol2atomic_number import yaml -import pprint -import ast -logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) class Error(Exception): @@ -32,7 +31,7 @@ def __init__(self, value, expected_type, help): def __str__(self): return "Expected type %s but found %s.\nHelp:%s " % \ - (repr(self.expected_type), repr(type(self.value)), help) + (repr(self.expected_type), repr(type(self.value)), help) class ConfigError(Error): @@ -45,13 +44,15 @@ def __init__(self, path): def __str__(self): return "Error in the configuration at %s " % ("->".join(self.path)) - + + class ConfigValueError(ConfigError, ValueError): """ Exception raised if the given value does not match the allowed constraints. """ - + default_msg = "Given value (%s) not allowed in constraint (%s). [%s]" + def __init__(self, config_value, allowed_constraint, path, msg=None): self.config_value = config_value self.allowed_constraint = allowed_constraint @@ -60,15 +61,9 @@ def __init__(self, config_value, allowed_constraint, path, msg=None): self.msg = self.default_msg else: self.msg = msg - + def __str__(self): return self.msg % (str(self.config_value), str(self.allowed_constraint), self.path) - - - - - - class DefaultConfigError(ConfigError): @@ -78,9 +73,9 @@ class DefaultConfigError(ConfigError): def __str__(self): return "Error in the default configuration at %s " % \ - ("->".join(self.path)) - - + ("->".join(self.path)) + + class PropertyType(object): def __init__(self): self._default = None @@ -89,21 +84,21 @@ def __init__(self): self._help = None self._mandatory = False self._lower = None - self._upper =None + self._upper = None pass - + @property def default(self): return self._default - + @default.setter def default(self, value): self._default = self.to_type(value) - + @property def allowed_value(self): return self._allowed_value - + @allowed_value.setter def allowed_value(self, value): if isinstance(value, basestring): @@ -114,41 +109,40 @@ def allowed_value(self, value): self._allowed_type = set([value]) else: raise ValueError("Can not set allowed value.") - - - + + @property def allowed_type(self): return self._allowed_value - + @allowed_type.setter def allowed_type(self, value): self._allowed_type = value if '_parse_allowed_type' in (set(dir(self.__class__)) - set(dir(PropertyType))) and value != None: self._lower, self._upper = self._parse_allowed_type(value) - + @property def help(self): return self._help - + @help.setter def help(self, value): self._help = value - + @property def mandatory(self): return self._mandatory - + @mandatory.setter def mandatory(self, value): self._mandatory = value - + def check_type(self, value): return True - + def to_type(self, value): return value - + def __list_dtype(self, mixed_list): try: tmp = [str(a) for a in mixed_list] @@ -161,8 +155,8 @@ def __list_dtype(self, mixed_list): except: raise ValueError("Forbidden type in allowed_type") return tmp - - + + def _check_allowed_value(self, _value): """ Returns True if the value is allowed or no allowed value is given. @@ -176,35 +170,32 @@ def _check_allowed_value(self, _value): return False else: return True - + def __repr__(self): if hasattr(self, "_allowed_type"): - return "Type %s; Allowed type: %s" %(self.__class__.__name__, self._allowed_type) + return "Type %s; Allowed type: %s" % (self.__class__.__name__, self._allowed_type) else: - return "Type %s; " %(self.__class__.__name__) - - + return "Type %s; " % (self.__class__.__name__) + + class PropertyTypeContainer(PropertyType): - def check_type(self): pass - + + class PropertyTypeBool(PropertyType): - def check_type(self, value): try: foo = bool(value) return True except: return False - - def to_type(self, value): + + def to_type(self, value): return bool(value) - - - + + class PropertyTypeInt(PropertyType): - def check_type(self, value): try: int(value) @@ -215,10 +206,11 @@ def check_type(self, value): return False except ValueError: return False - + def to_type(self, value): return int(value) - #ToDo: use this if allowed type is specified + #ToDo: use this if allowed type is specified + def _parse_allowed_type(self, allowed_type): string = allowed_type.strip() upper = None @@ -245,7 +237,7 @@ def _parse_allowed_type(self, allowed_type): value = re.compile('[0-9.+^*eE]+').findall(string)[0] lower = float(value) return lower, upper - + def __check_type(self, value, lower_lim, upper_lim): upper, lower = True, True if upper_lim != None: @@ -253,47 +245,41 @@ def __check_type(self, value, lower_lim, upper_lim): if lower_lim != None: lower = value > lower_lim return upper and lower - - + + def _check_allowed_type(self, value): if self._allowed_type != None: - if self.__check_type(value, self._lower, self._upper): + if self.__check_type(value, self._lower, self._upper): return True else: return False else: return True - + def _is_valid(self, value): if not self.check_type(value): return False if self.allowed_value != None: return False if not self.__check_type(value, self._lower, self._upper): - return False + return False return True - - - - - - + + class PropertyTypeFloat(PropertyTypeInt): - def check_type(self, value): try: float(value) if self._check_allowed_value(value) and self._check_allowed_type(value): - return True + return True except ValueError: return False - + def to_type(self, value): return float(value) - - + + class PropertyTypeQuantity(PropertyType): - def check_type(self, value): try: quantity_split = value.strip().split() @@ -304,42 +290,41 @@ def check_type(self, value): units.Unit(quantity_unit) except ValueError: return False - + print('--->>-') print(self._default) print(value) print('----') - if self._default is not None : - + if self._default is not None: #d_quantity_split = self._default.strip().split() - self._default.to( quantity_unit ) + self._default.to(quantity_unit) float(quantity_value) units.Unit(quantity_unit) return True - except (ValueError,AttributeError): + except (ValueError, AttributeError): return False - + def to_type(self, value): quantity_split = value.strip().split() quantity_value = quantity_split[0] quantity_unit = ' '.join(quantity_split[1:]) return float(quantity_value) * units.Unit(quantity_unit) - + + class PropertyTypeQuantityRange(PropertyTypeQuantity): - def _to_units(self, los): if len(los) > 2: - loq = [(lambda x: (units.Quantity(float(x[0]),x[1])))(x.split()) for x in los[:-1]] + loq = [(lambda x: (units.Quantity(float(x[0]), x[1])))(x.split()) for x in los[:-1]] else: - loq = [(lambda x: (units.Quantity(float(x[0]),x[1])))(x.split()) for x in los] + loq = [(lambda x: (units.Quantity(float(x[0]), x[1])))(x.split()) for x in los] try: - _ = reduce((lambda a, b: a.to(b.unit)), loq) + _ = reduce((lambda a, b: a.to(b.unit)), loq) loq = [a.to(loq[0].unit) for a in loq] return loq except UnitsException as e: - msg = "Incompatible units in %s"%str(los) + str(e) + msg = "Incompatible units in %s" % str(los) + str(e) raise ValueError(msg) - + def check_type(self, value): if isinstance(value, dict): if reduce((lambda a, b: a and b in value), [True, 'start', 'end']): @@ -353,17 +338,16 @@ def check_type(self, value): if abs(loq[0].value - loq[1].value) > 0: return True return False - + def to_type(self, value): if isinstance(value, list): return self._to_units(value[:2]) elif isinstance(value, dict): los = [value['start'], value['end']] return self._to_units(los) - - + + class PropertyTypeQuantityRangeSampled(PropertyTypeQuantityRange): - def check_type(self, value): if isinstance(value, dict): if reduce((lambda a, b: a and b in value), [True, 'start', 'stop', 'num']): @@ -377,7 +361,7 @@ def check_type(self, value): if abs(loq[0].value - loq[1].value) > 0: return True return False - + def to_type(self, value): if isinstance(value, list): _tmp = self._to_units(value[:2]) @@ -388,10 +372,9 @@ def to_type(self, value): _tmp = self._to_units(los) _tmp.append(value['num']) return _tmp - - + + class PropertyTypeString(PropertyType): - def check_type(self, value): try: str(value) @@ -399,12 +382,12 @@ def check_type(self, value): return True except ValueError: return False - + def to_type(self, value): return str(value) - + + class PropertyTypeStringList(PropertyTypeString): - def check_type(self, value): try: str(value) @@ -414,15 +397,14 @@ def check_type(self, value): return True else: return False - + def to_type(self, value): return str(value) - + pass - - + + class PropertyTypeList(PropertyType): - def check_type(self, value): if isinstance(value, list): return True @@ -437,22 +419,21 @@ def check_type(self, value): except: return False return False - - + + def to_type(self, value): if isinstance(value, list): return value elif isinstance(value, basestring): try: return ast.literal_eval(value) - except SyntaxError: + except SyntaxError: return value.split() else: return [] - - + + class PropertyTypeRange(PropertyType): - def check_type(self, value): if isinstance(value, dict): if reduce((lambda a, b: a in value), [True, 'start', 'stop']): @@ -472,7 +453,7 @@ def check_type(self, value): if abs(clist[0] - clist[1]) > 0: return True return False - + def to_type(self, value): if isinstance(value, list): return value @@ -484,13 +465,12 @@ def to_type(self, value): except SyntaxError: return value.split() - + class PropertyTypeRangeSampled(PropertyTypeRange): - def check_type(self, value): if isinstance(value, dict): - if reduce((lambda a, b: a in value),\ - [True, 'start', 'stop', 'num']): + if reduce((lambda a, b: a in value), \ + [True, 'start', 'stop', 'num']): if abs(value['start'] - value['stop']) > 0: return True elif isinstance(value, list): @@ -507,7 +487,7 @@ def check_type(self, value): if abs(clist[0] - clist[1]) > 0: return True return False - + def to_type(self, value): if isinstance(value, list): return value @@ -518,21 +498,32 @@ def to_type(self, value): return ast.literal_eval(value) except SyntaxError: return value.split() - + + class PropertyTypeAbundances(PropertyType): - - elements = { 'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, 'ds':110, 'rg':111, 'cn':112 } + elements = {'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, + 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, + 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, + 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, + 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, + 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, + 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, + 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, + 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, + 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, + 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, + 'ds': 110, 'rg': 111, 'cn': 112} def check_type(self, _value): - value = dict((k.lower(), v) for k,v in _value.items()) + value = dict((k.lower(), v) for k, v in _value.items()) if set(value).issubset(set(self.elements)): return True else: return False - + def to_type(self, _value): if isinstance(_value, dict): - value = dict((k.lower(), v) for k,v in _value.items()) + value = dict((k.lower(), v) for k, v in _value.items()) abundances = dict.fromkeys(self.elements.copy(), 0.0) for k in value: abundances[k] = value[k] @@ -540,14 +531,25 @@ def to_type(self, _value): return abundances else: raise ConfigError - + + class PropertyTypeLegacyAbundances(PropertyType): - - elements = { 'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, 'ds':110, 'rg':111, 'cn':112 } + elements = {'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, + 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, + 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, + 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, + 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, + 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, + 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, + 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, + 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, + 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, + 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, + 'ds': 110, 'rg': 111, 'cn': 112} types = ['uniform'] def check_type(self, _value): - value = dict((k.lower(), v) for k,v in _value.items()) + value = dict((k.lower(), v) for k, v in _value.items()) if 'type' in value: if value['type'] in self.types: print('type is ok') @@ -558,10 +560,10 @@ def check_type(self, _value): else: return False return False - + def to_type(self, _value): if isinstance(_value, dict): - value = dict((k.lower(), v) for k,v in _value.items()) + value = dict((k.lower(), v) for k, v in _value.items()) abundances = dict.fromkeys(self.elements.copy(), 0.0) for k in value: abundances[k] = value[k] @@ -569,9 +571,6 @@ def to_type(self, _value): return abundances else: raise ConfigError - - - class DefaultParser(object): @@ -587,55 +586,55 @@ def __init__(self, default_dict, item_path=None): :param default_dict: default configuration :return: """ - + self.__item_path = item_path #create property type dict self.__types['arbitrary'] = PropertyType - + self.__types['int'] = PropertyTypeInt self.__register_leaf('int') - + self.__types['float'] = PropertyTypeFloat self.__register_leaf('float') - + self.__types['quantity'] = PropertyTypeQuantity self.__register_leaf('quantity') - + self.__types['quantity_range'] = PropertyTypeQuantityRange self.__register_leaf('quantity_range') - + self.__types['quantity_range_sampled'] = PropertyTypeQuantityRangeSampled self.__register_leaf('quantity_range_sampled') - + self.__types['string'] = PropertyTypeString self.__register_leaf('string') - - + self.__types['range'] = PropertyTypeRange self.__register_leaf('range') - + self.__types['range_sampled'] = PropertyTypeRangeSampled self.__register_leaf('range_sampled') - + self.__types['list'] = PropertyTypeList self.__register_leaf('list') - + self.__types['container-declaration'] = PropertyTypeContainer self.__register_leaf('container-declaration') - + self.__types['container-property'] = PropertyTypeContainer self.__register_leaf('container-property') - + self.__types['abundance_set'] = PropertyTypeAbundances self.__register_leaf('abundance_set') - - self.__types['legacy-abundances'] =PropertyTypeLegacyAbundances + + self.__types['legacy-abundances'] = PropertyTypeLegacyAbundances self.__register_leaf('legacy-abundances') - + self.__types['bool'] = PropertyTypeBool self.__register_leaf('bool') - + self.__mandatory = False + self.__default_value = None self.__allowed_value = None @@ -653,17 +652,16 @@ def __init__(self, default_dict, item_path=None): #print(self.__types.keys()) if not self.__property_type in self.__types.keys(): raise ValueError - self.__type = self.__types[self.__property_type]() + self.__type = self.__types[self.__property_type]() if 'allowed_value' in default_dict: self.__type.allowed_value = default_dict['allowed_value'] if 'allowed_type' in default_dict: self.__type.allowed_type = default_dict['allowed_type'] - -#ToDo: move all to classes + if 'default' in default_dict: - if default_dict['default'] != None and not default_dict['default'] in ['None','']: + if default_dict['default'] != None and not default_dict['default'] in ['None', '']: self.__type.default = default_dict['default'] if 'mandatory' in default_dict: @@ -686,10 +684,12 @@ def set_default(self, value): if self.__type.check_type(value): self.__type.default = value else: - raise ConfigValueError(value, self.__type.allowed_value, self.get_path_in_dict(), msg='Default value (%s) violates property constraint (%s). [%s]') + raise ConfigValueError(value, self.__type.allowed_value, self.get_path_in_dict(), + msg='Default value (%s) violates property constraint (%s). [%s]') else: self.__type.default = None + @property def is_mandatory(self): """ Returns True if this property is a mandatory. @@ -697,6 +697,7 @@ def is_mandatory(self): """ return self.__type.mandatory + @property def has_default(self): """ Returns True if this property has a default value @@ -744,19 +745,22 @@ def get_value(self): if self.__type.check_type(self.__config_value): return self.__type.to_type(self.__config_value) else: - raise ConfigValueError(self.__config_value, self.__type.allowed_value, self.get_path_in_dict()) + raise ConfigValueError(self.__config_value, self.__type.allowed_value, self.get_path_in_dict()) else: - if self.has_default(): + if self.has_default: logger.info("Value <%s> specified in the configuration violates a constraint\ - given in the default configuration. Expected type: %s. Using the default value."%(str(self.__config_value),str(self.__property_type))) + given in the default configuration. Expected type: %s. Using the default value." % ( + str(self.__config_value), str(self.__property_type))) return self.__type.default else: - if self.is_mandatory(): - raise ValueError('Value is mandatory, but no value was given in default configuration. [%s]' %str(self.get_path_in_dict())) + if self.is_mandatory: + raise ValueError('Value is mandatory, but no value was given in default configuration. [%s]' % str( + self.get_path_in_dict())) else: - logger.info("Value is not mandatory and is not specified in the configuration. [%s]" %(str(self.get_path_in_dict()))) + logger.info("Value is not mandatory and is not specified in the configuration. [%s]" % ( + str(self.get_path_in_dict()))) return None - + def is_container(self): """ @@ -776,7 +780,7 @@ def get_container_dic(self): @classmethod def update_container_dic(cls, container_dic, current_entry_name): - if reduce(lambda a, b: a or b,\ + if reduce(lambda a, b: a or b, \ [container_dic.has_key(i) for i in ['and', 'or']], True): if 'or' in container_dic: if current_entry_name in container_dic['or']: @@ -817,7 +821,7 @@ def __is_container(self): else: return False -# __check['container-property'] = __is_container + # __check['container-property'] = __is_container def __is_container_declaration(self, value): pass @@ -835,7 +839,7 @@ def __init__(self, container_default_dict, container_dict, container_path=None): #self.__register_leaf('float') #self.__register_leaf('quantity') #self.__register_leaf('string') - + self.__container_path = container_path self.__type = None self.__allowed_value = None @@ -890,14 +894,14 @@ def __init__(self, container_default_dict, container_dict, container_path=None): self.__default_container, self.__config_container = tmp, tmp #### else: - #look for necessary items + #look for necessary items entry_name = '_' + self.__selected_container try: necessary_items = container_default_dict['type'][entry_name] except KeyError: raise ValueError('Container insufficient specified') - - #look for additional items + + #look for additional items entry_name = '+' + self.__selected_container try: additional_items = container_default_dict['type'][entry_name] @@ -905,7 +909,7 @@ def __init__(self, container_default_dict, container_dict, container_path=None): except KeyError: self.__has_additional_items = False pass - + def parse_container_items(top_default, top_config, level_name, full_path): """Recursive parser for the container default dictionary and the container configuration dictionary. @@ -934,7 +938,7 @@ def parse_container_items(top_default, top_config, level_name, full_path): ccontainer = Container(top_default, container_conf) return ccontainer.get_container_ob(), ccontainer.get_container_conf() elif not default_property.is_leaf: - # print(top_default.items()) + # print(top_default.items()) for k, v in top_default.items(): print('>>><<<') print(k) @@ -951,15 +955,15 @@ def parse_container_items(top_default, top_config, level_name, full_path): default_property.set_config_value(conf_value) return default_property, default_property.get_value() - - def reduce_list(a,b): + + def reduce_list(a, b): """ removes items from list a which are in b """ for k in b: a.remove(k) - return a - + return a + def get_value_by_path(dict, path): """ @@ -977,24 +981,26 @@ def get_value_by_path(dict, path): if not item in container_dict.keys(): raise ValueError('Entry %s is missing in container [%s]' % (str(item), self.__container_path)) else: - self.__default_container[item], self.__config_container[item] = parse_container_items(container_default_dict[item], - container_dict[item], item, self.__container_path + [item]) + self.__default_container[item], self.__config_container[item] = parse_container_items( + container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) if self.__has_additional_items: for item in additional_items: try: - self.__default_container[item], self.__config_container[item] = parse_container_items(container_default_dict[item], - container_dict[item], item, self.__container_path + [item]) + self.__default_container[item], self.__config_container[item] = parse_container_items( + container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) except KeyError: pass - - #go through all items and create an conf object thereby check the conf + + #go through all items and create an conf object thereby check the conf self.__container_ob = self.__default_container if isinstance(self.__config_container, dict): self.__conf = self.__config_container else: pdb.set_trace() - self.__conf = {"No Name":self.__config_container} - + self.__conf = {"No Name": self.__config_container} + def get_container_ob(self): """ @@ -1040,7 +1046,7 @@ def from_yaml(cls, fname_config, fname_default): defaf = f.read() defa = yaml.safe_load(defaf) return cls(defa, conf) - + def __mandatory_key(self, path): """Return the key string for dictionary of mandatory entries @@ -1048,8 +1054,7 @@ def __mandatory_key(self, path): :return: corresponding key """ return ':'.join(path) - - + def register_mandatory(self, name, path): """Register a mandatory entry @@ -1099,7 +1104,7 @@ def get_property_by_path(d, path): :param dict: nested dictionary :param path: chain of keys as list """ - if len(path)<=0: + if len(path) <= 0: return d else: try: @@ -1124,35 +1129,34 @@ def recursive_parser(top_default, configuration, path): tmp_conf_val = {} if isinstance(top_default, dict): default_property = DefaultParser(top_default, item_path=path) - if default_property.is_mandatory(): + if default_property.is_mandatory: self.register_mandatory(self, path) self.deregister_mandatory(self, path) if default_property.is_container(): container_conf = get_property_by_path(configuration, path) try: - ccontainer = Container(top_default, container_conf, container_path=path) + ccontainer = Container(top_default, container_conf, container_path=path) return ccontainer.get_container_ob(), ccontainer.get_container_conf() + except: + logger.warning('Container specified in default_configuration, but not used in the current\ + configuration file. [%s]' % str(path)) return None, None + elif not default_property.is_leaf: no_default = self.__check_items_in_conf(get_property_by_path(configuration, path), top_default) if len(no_default) > 0: - logger.warning('The items %s from the configuration are not specified in the default configuration'%str(no_default)) + logger.warning('The items %s from the configuration are not specified in the default\ + configuration' % str(no_default)) for k, v in top_default.items(): - #print('>---<') - #print(k) tmp_conf_ob[k], tmp_conf_val[k] = recursive_parser(v, configuration, path + [k]) - #print(tmp_conf_val[k]) return tmp_conf_ob, tmp_conf_val + else: default_property.set_path_in_dic(path) try: -# print('get_property_by_path') - #print(path) conf_value = get_property_by_path(configuration, path) -# print(conf_value) -# print('End:get_property_by_path') except KeyError: conf_value = None @@ -1162,16 +1166,13 @@ def recursive_parser(top_default, configuration, path): self.__conf_o, self.__conf_v = recursive_parser(default_configuration, configuration, []) - # print('|\|\|\|') - # print(self.__conf_v) - + def __check_items_in_conf(self, config_dict, default_dict): if isinstance(config_dict, dict) and len(config_dict) > 0: return list(set(config_dict.keys()) - set(default_dict.keys())) else: - return list(default_dict.keys()) - - + return list(default_dict.keys()) + def __create_default_conf(self, default_conf): """Returns the default configuration values as dictionary. @@ -1197,14 +1198,13 @@ def recursive_default_parser(top_default, path): return tmp_default else: default_property.set_path_in_dic(path) - if default_property.has_default(): + if default_property.has_default: return default_property.get_default() else: return None self.__default_config = recursive_default_parser(default_conf, []) - def get_config(self): """Returns the parsed configuration as dictionary. @@ -1224,12 +1224,12 @@ def get_config_object(self): :return: default configuration objects as dictionary """ return self.__conf_o - + def get_help(self): - return(pprint.pformat(self.get_default_config())) - - + return (pprint.pformat(self.get_default_config())) + + def __repr__(self): - return(str(pprint.pformat(self.get_config()))) + return (str(pprint.pformat(self.get_config()))) diff --git a/tardis/io/tests/data/tardis_configv1_artis_density.yml b/tardis/io/tests/data/tardis_configv1_artis_density.yml index 28c6fdc814d..3974024df5f 100644 --- a/tardis/io/tests/data/tardis_configv1_artis_density.yml +++ b/tardis/io/tests/data/tardis_configv1_artis_density.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 732c9a964af..967856da766 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -1,67 +1,64 @@ -import tardis -from tardis.io.default_config_parser import DefaultParser, Config, ConfigValueError +import os +from glob import glob from astropy import units as u -import os -import yaml import pytest -from glob import glob + +from tardis.io.default_config_parser import DefaultParser, Config, ConfigValueError existing_configs = glob(os.path.join('tardis', 'docs', 'examples', '*.yml')) config_definition = os.path.join('tardis', 'data', 'tardis_default_config_definition.yml') + @pytest.mark.parametrize(("config_filename",), existing_configs) def test_configread(config_filename): config = Config.from_yaml(config_filename, config_definition) - def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory): test_ob = DefaultParser(test_dic) if not default == None: - dhelper = True + dhelper = True else: dhelper = False - - assert test_ob.has_default() == dhelper + assert test_ob.has_default == dhelper assert test_ob.get_default() == default assert test_ob.is_leaf assert test_ob.is_container() == container - assert test_ob.is_mandatory() == mandatory - + assert test_ob.is_mandatory == mandatory + #set good default test_ob.set_default(str(default)) - + assert test_ob.get_default() == default #set bad default if wdefault is not None: with pytest.raises(ValueError): test_ob.set_default(wdefault) - + assert test_ob.get_value() == default - + #set good value test_ob.set_config_value(str(value)) - + assert test_ob.get_value() == value - + #set bad value if wvalue is not None: with pytest.raises(ConfigValueError): test_ob.set_config_value(wvalue) test_ob.get_value() - + return 0 - - - + + def test_default_parser_float(): example_dic = {'default': 99.99, - 'help': 'float value for testing', - 'mandatory': True, - 'property_type': 'float'} + 'help': 'float value for testing', + 'mandatory': True, + 'property_type': 'float'} default = 99.99 wdefault = "xx" value = 11.12 @@ -69,81 +66,84 @@ def test_default_parser_float(): container = False mandatory = True ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) - - + + def test_default_parser_integer(): example_dic = {'default': 99, - 'help': 'integer value for testing', - 'mandatory': True, - 'property_type': 'int'} - + 'help': 'integer value for testing', + 'mandatory': True, + 'property_type': 'int'} + default = 99 wdefault = 9.15 value = 11 wvalue = 9.22 container = False mandatory = True - + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) - + + def test_default_parser_quantity(): example_dic = {'default': '99.99 cm', - 'help': 'quantity for testing', - 'mandatory': True, - 'property_type': 'quantity'} - + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity'} + default = 99.99 * u.cm wdefault = "kl" - value = 11.12 * u. m + value = 11.12 * u.m wvalue = "yy" container = False mandatory = True - + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) - - + + def test_default_parser_range(): example_dic = {'default': [0, 10], - 'help': 'range for testing', - 'mandatory': False, - 'property_type': 'range'} - - default = [0,10] + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range'} + + default = [0, 10] wdefault = 1 - value = [7,8] + value = [7, 8] wvalue = 2 container = False mandatory = False - + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_default_parser_range_sampled(): example_dic = {'default': [0, 10, 1], - 'help': 'range for testing', - 'mandatory': False, - 'property_type': 'range_sampled'} - - default = [0,10,1] - wdefault = [1,3] - value = [1,5,1] - wvalue = [1,1] + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range_sampled'} + + default = [0, 10, 1] + wdefault = [1, 3] + value = [1, 5, 1] + wvalue = [1, 1] container = False mandatory = False - + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) - + + def test_default_parser_string(): example_dic = {'default': 'DEFAULT', - 'help': 'string for testing', - 'mandatory': True, - 'property_type': 'string'} - + 'help': 'string for testing', + 'mandatory': True, + 'property_type': 'string'} + default = "DEFAULT" wdefault = None value = "blub" wvalue = None container = False mandatory = True - + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) From a328049460159b3b9b6e0f628da66f0a88111b69 Mon Sep 17 00:00:00 2001 From: Michi Date: Tue, 29 Apr 2014 00:46:18 +0200 Subject: [PATCH 06/15] dear git log tonight i removed the elements from the df file and used the element data from atomic. --- tardis/io/default_config_parser.py | 143 ++++++++---------- tardis/io/tests/test_default_config_parser.py | 14 ++ 2 files changed, 75 insertions(+), 82 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index dd0a227d986..6fee440c5b5 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -5,6 +5,7 @@ import pprint import ast +from tardis.atomic import atomic_symbols_data from astropy import units from astropy.units.core import UnitsException import yaml @@ -291,10 +292,6 @@ def check_type(self, value): except ValueError: return False - print('--->>-') - print(self._default) - print(value) - print('----') if self._default is not None: #d_quantity_split = self._default.strip().split() self._default.to(quantity_unit) @@ -337,6 +334,29 @@ def check_type(self, value): loq = self._to_units(value) if abs(loq[0].value - loq[1].value) > 0: return True + else: + return False + elif isinstance(value, basestring): + try: + clist = ast.literal_eval(value) + if len(clist) == 2: + loq = self._to_units(value) + if abs(loq[0].value - loq[1].value) > 0: + return True + else: + return False + else: + return False + except SyntaxError: + clist = value.split() + if len(clist) == 2: + loq = self._to_units(value) + if abs(loq[0].value - loq[1].value) > 0: + return True + else: + return False + else: + return False return False def to_type(self, value): @@ -501,18 +521,7 @@ def to_type(self, value): class PropertyTypeAbundances(PropertyType): - elements = {'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, - 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, - 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, - 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, - 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, - 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, - 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, - 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, - 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, - 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, - 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, - 'ds': 110, 'rg': 111, 'cn': 112} + elements = dict([(x,y.lower()) for (x,y) in atomic_symbols_data]) def check_type(self, _value): value = dict((k.lower(), v) for k, v in _value.items()) @@ -532,27 +541,14 @@ def to_type(self, _value): else: raise ConfigError - class PropertyTypeLegacyAbundances(PropertyType): - elements = {'neut': 0, 'h': 1, 'he': 2, 'li': 3, 'be': 4, 'b': 5, 'c': 6, 'n': 7, 'o': 8, 'f': 9, 'ne': 10, - 'na': 11, 'mg': 12, 'al': 13, 'si': 14, 'p': 15, 's': 16, 'cl': 17, 'ar': 18, 'k': 19, 'ca': 20, - 'sc': 21, 'ti': 22, 'v': 23, 'cr': 24, 'mn': 25, 'fe': 26, 'co': 27, 'ni': 28, 'cu': 29, 'zn': 30, - 'ga': 31, 'ge': 32, 'as': 33, 'se': 34, 'br': 35, 'kr': 36, 'rb': 37, 'sr': 38, 'y': 39, 'zr': 40, - 'nb': 41, 'mo': 42, 'tc': 43, 'ru': 44, 'rh': 45, 'pd': 46, 'ag': 47, 'cd': 48, 'in': 49, 'sn': 50, - 'sb': 51, 'te': 52, 'i': 53, 'xe': 54, 'cs': 55, 'ba': 56, 'la': 57, 'ce': 58, 'pr': 59, 'nd': 60, - 'pm': 61, 'sm': 62, 'eu': 63, 'gd': 64, 'tb': 65, 'dy': 66, 'ho': 67, 'er': 68, 'tm': 69, 'yb': 70, - 'lu': 71, 'hf': 72, 'ta': 73, 'w': 74, 're': 75, 'os': 76, 'ir': 77, 'pt': 78, 'au': 79, 'hg': 80, - 'tl': 81, 'pb': 82, 'bi': 83, 'po': 84, 'at': 85, 'rn': 86, 'fr': 87, 'ra': 88, 'ac': 89, 'th': 90, - 'pa': 91, 'u': 92, 'np': 93, 'pu': 94, 'am': 95, 'cm': 96, 'bk': 97, 'cf': 98, 'es': 99, 'fm': 100, - 'md': 101, 'no': 102, 'lr': 103, 'rf': 104, 'db': 105, 'sg': 106, 'bh': 107, 'hs': 108, 'mt': 109, - 'ds': 110, 'rg': 111, 'cn': 112} + elements = dict([(x,y.lower()) for (x,y) in atomic_symbols_data]) types = ['uniform'] def check_type(self, _value): value = dict((k.lower(), v) for k, v in _value.items()) if 'type' in value: if value['type'] in self.types: - print('type is ok') tmp = value.copy() tmp.pop('type', None) if set(tmp).issubset(set(self.elements)): @@ -648,8 +644,6 @@ def __init__(self, default_dict, item_path=None): self.__property_type = 'arbitrary' else: self.__property_type = default_dict['property_type'] - #print(self.__property_type) - #print(self.__types.keys()) if not self.__property_type in self.__types.keys(): raise ValueError self.__type = self.__types[self.__property_type]() @@ -792,19 +786,18 @@ def update_container_dic(cls, container_dic, current_entry_name): return container_dic - def is_valid(self, value): - if not self.__check[self.__property_type](self, value): - return False - if self.__allowed_value: - if not self.__is_allowed_value(value, self.__allowed_value): - return False - if self.__allowed_type: - if not self.__check_value(value, self.__lower, self.__upper): - return False - return True + # def is_valid(self, value): + # if not self.__check[self.__property_type](self, value): + # return False + # if self.__allowed_value: + # if not self.__is_allowed_value(value, self.__allowed_value): + # return False + # if self.__allowed_type: + # if not self.__check_value(value, self.__lower, self.__upper): + # return False + # return True def __register_leaf(self, type_name): - #print(type_name) if not type_name in self.__list_of_leaf_types: self.__list_of_leaf_types.append(type_name) @@ -834,11 +827,6 @@ def __init__(self, container_default_dict, container_dict, container_path=None): :param container_dict: Dictionary containing the configuration of the container. """ - #self.__register_leaf('list') - #self.__register_leaf('int') - #self.__register_leaf('float') - #self.__register_leaf('quantity') - #self.__register_leaf('string') self.__container_path = container_path self.__type = None @@ -866,7 +854,6 @@ def __init__(self, container_default_dict, container_dict, container_path=None): #check if the specified container in the config is allowed try: - #print(container_dict) if not container_dict['type'] in self.__allowed_container: raise ValueError('Wrong container type') @@ -910,6 +897,31 @@ def __init__(self, container_default_dict, container_dict, container_path=None): self.__has_additional_items = False pass + if not self.__paper_abundances: + for item in necessary_items: + if not item in container_dict.keys(): + raise ValueError('Entry %s is missing in container [%s]' % (str(item), self.__container_path)) + else: + self.__default_container[item], self.__config_container[item] = parse_container_items( + container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) + if self.__has_additional_items: + for item in additional_items: + try: + self.__default_container[item], self.__config_container[item] = parse_container_items( + container_default_dict[item], + container_dict[item], item, self.__container_path + [item]) + except KeyError: + pass + + #go through all items and create an conf object thereby check the conf + self.__container_ob = self.__default_container + if isinstance(self.__config_container, dict): + self.__conf = self.__config_container + else: + pdb.set_trace() + self.__conf = {"No Name": self.__config_container} + def parse_container_items(top_default, top_config, level_name, full_path): """Recursive parser for the container default dictionary and the container configuration dictionary. @@ -923,11 +935,6 @@ def parse_container_items(top_default, top_config, level_name, full_path): returned """ path = reduce_list(list(full_path), self.__container_path + [item]) - print('--C') - print(item) - print(full_path) - print(path) - print('--') tmp_conf_ob = {} tmp_conf_val = {} #pdb.set_trace() @@ -938,10 +945,7 @@ def parse_container_items(top_default, top_config, level_name, full_path): ccontainer = Container(top_default, container_conf) return ccontainer.get_container_ob(), ccontainer.get_container_conf() elif not default_property.is_leaf: - # print(top_default.items()) for k, v in top_default.items(): - print('>>><<<') - print(k) tmp_conf_ob[k], tmp_conf_val[k] = parse_container_items(v, top_config, k, full_path + [k]) return tmp_conf_ob, tmp_conf_val else: @@ -976,30 +980,6 @@ def get_value_by_path(dict, path): dict = dict[key] return dict - if not self.__paper_abundances: - for item in necessary_items: - if not item in container_dict.keys(): - raise ValueError('Entry %s is missing in container [%s]' % (str(item), self.__container_path)) - else: - self.__default_container[item], self.__config_container[item] = parse_container_items( - container_default_dict[item], - container_dict[item], item, self.__container_path + [item]) - if self.__has_additional_items: - for item in additional_items: - try: - self.__default_container[item], self.__config_container[item] = parse_container_items( - container_default_dict[item], - container_dict[item], item, self.__container_path + [item]) - except KeyError: - pass - - #go through all items and create an conf object thereby check the conf - self.__container_ob = self.__default_container - if isinstance(self.__config_container, dict): - self.__conf = self.__config_container - else: - pdb.set_trace() - self.__conf = {"No Name": self.__config_container} def get_container_ob(self): @@ -1210,7 +1190,6 @@ def get_config(self): """Returns the parsed configuration as dictionary. :return: configuration values as dictionary """ - print(self.__conf_v) return self.__conf_v def get_default_config(self): diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 967856da766..50443fd341d 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -99,6 +99,20 @@ def test_default_parser_quantity(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) +# def test_default_parser_quantity_range(): +# example_dic = {'default': ['1 cm', '5 cm'], +# 'help': 'quantity for testing', +# 'mandatory': True, +# 'property_type': 'quantity_range'} +# +# default = [1.0 * u.cm, 5 * u.cm] +# wdefault = "kl" +# value = [10 * u.m, 50 * u.cm] +# wvalue = "yy" +# container = False +# mandatory = True +# +# ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) def test_default_parser_range(): example_dic = {'default': [0, 10], From 04d0c2af4e2d8bc6e24c40f0ada7c6474fd832f3 Mon Sep 17 00:00:00 2001 From: Michi Date: Tue, 29 Apr 2014 17:54:24 +0200 Subject: [PATCH 07/15] new test for the config parser --- tardis/io/default_config_parser.py | 15 +- tardis/io/tests/test_default_config_parser.py | 163 +++++++++++++++--- 2 files changed, 149 insertions(+), 29 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index 6fee440c5b5..6e005aa8ace 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -347,7 +347,7 @@ def check_type(self, value): return False else: return False - except SyntaxError: + except (SyntaxError): clist = value.split() if len(clist) == 2: loq = self._to_units(value) @@ -357,6 +357,8 @@ def check_type(self, value): return False else: return False + except ValueError: + return False return False def to_type(self, value): @@ -524,9 +526,12 @@ class PropertyTypeAbundances(PropertyType): elements = dict([(x,y.lower()) for (x,y) in atomic_symbols_data]) def check_type(self, _value): - value = dict((k.lower(), v) for k, v in _value.items()) - if set(value).issubset(set(self.elements)): - return True + if isinstance(_value,dict): + value = dict((k.lower(), v) for k, v in _value.items()) + if set(value).issubset(set(self.elements.values())): + return True + else: + return False else: return False @@ -551,7 +556,7 @@ def check_type(self, _value): if value['type'] in self.types: tmp = value.copy() tmp.pop('type', None) - if set(tmp).issubset(set(self.elements)): + if set(tmp).issubset(set(self.elements.values())): return True else: return False diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 50443fd341d..33d7fa03d0b 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -3,6 +3,7 @@ from astropy import units as u import pytest +import ast from tardis.io.default_config_parser import DefaultParser, Config, ConfigValueError @@ -15,35 +16,42 @@ def test_configread(config_filename): config = Config.from_yaml(config_filename, config_definition) -def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory): +def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory, return_default=None, + return_value=None, value_as_string=True): test_ob = DefaultParser(test_dic) + if return_value is None: + return_value = value + + if return_default is None: + return_default = default + if not default == None: dhelper = True else: dhelper = False assert test_ob.has_default == dhelper - assert test_ob.get_default() == default + assert test_ob.get_default() == return_default assert test_ob.is_leaf assert test_ob.is_container() == container assert test_ob.is_mandatory == mandatory #set good default - test_ob.set_default(str(default)) + test_ob.set_default(default) - assert test_ob.get_default() == default + assert test_ob.get_default() == return_default #set bad default if wdefault is not None: with pytest.raises(ValueError): test_ob.set_default(wdefault) - assert test_ob.get_value() == default + assert test_ob.get_value() == return_default #set good value - test_ob.set_config_value(str(value)) + test_ob.set_config_value(value) - assert test_ob.get_value() == value + assert test_ob.get_value() == return_value #set bad value if wvalue is not None: @@ -90,29 +98,89 @@ def test_default_parser_quantity(): 'mandatory': True, 'property_type': 'quantity'} - default = 99.99 * u.cm + default = "99.99 cm" + return_default = 99.99 * u.cm wdefault = "kl" - value = 11.12 * u.m + value = "11.12 m" + return_value = 11.12 * u.m wvalue = "yy" container = False mandatory = True - ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default,return_value=return_value ) + +def test_default_parser_quantity_range(): + example_dic = {'default': ['1 cm', '5 cm'], + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity_range'} + + default = ['1.0 cm', '5 cm'] + return_default = [1.0 * u.cm, 5 * u.cm] + wdefault = "kl" + value = ['10 m', '50 cm'] + return_value = [10 * u.m, 50 * u.cm] + wvalue = "yy" + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default, return_value=return_value) + +def test_default_parser_quantity_range_old(): + example_dic = {'default':{'start':'1 cm', 'end':'5 cm'}, + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity_range'} + + default = ['1.0 cm', '5 cm'] + return_default = [1.0 * u.cm, 5 * u.cm] + wdefault = "kl" + value = ['10 m', '50 cm'] + return_value = [10 * u.m, 50 * u.cm] + wvalue = "yy" + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default, return_value=return_value) + +def test_default_parser_quantity_range_sampeled(): + example_dic = {'default': ['1 cm', '5 cm', 10], + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity_range_sampled'} + + default = ['1.0 cm', '5 cm',10] + return_default = [1.0 * u.cm, 5 * u.cm, 10] + wdefault = "kl" + value = ['10 m', '50 cm', 10] + return_value = [10 * u.m, 50 * u.cm, 10] + wvalue = "yy" + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default, return_value=return_value) + +def test_default_parser_quantity_range_sampeled_old(): + example_dic = {'default': {'start':'1 cm', 'stop':'5 cm', 'num':10}, + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity_range_sampled'} + + default = ['1.0 cm', '5 cm',10] + return_default = [1.0 * u.cm, 5 * u.cm, 10] + wdefault = "kl" + value = ['10 m', '50 cm', 10] + return_value = [10 * u.m, 50 * u.cm, 10] + wvalue = "yy" + container = False + mandatory = True -# def test_default_parser_quantity_range(): -# example_dic = {'default': ['1 cm', '5 cm'], -# 'help': 'quantity for testing', -# 'mandatory': True, -# 'property_type': 'quantity_range'} -# -# default = [1.0 * u.cm, 5 * u.cm] -# wdefault = "kl" -# value = [10 * u.m, 50 * u.cm] -# wvalue = "yy" -# container = False -# mandatory = True -# -# ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default, return_value=return_value) def test_default_parser_range(): example_dic = {'default': [0, 10], @@ -129,6 +197,20 @@ def test_default_parser_range(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) +def test_default_parser_range_old(): + example_dic = {'default': {'start':0,'stop':10}, + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range'} + + default = [0, 10] + wdefault = 1 + value = [7, 8] + wvalue = 2 + container = False + mandatory = False + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) def test_default_parser_range_sampled(): example_dic = {'default': [0, 10, 1], @@ -145,6 +227,20 @@ def test_default_parser_range_sampled(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) +def test_default_parser_range_sampled(): + example_dic = {'default': {'start':0,'stop':10,'num':1}, + 'help': 'range for testing', + 'mandatory': False, + 'property_type': 'range_sampled'} + + default = [0, 10, 1] + wdefault = [1, 3] + value = [1, 5, 1] + wvalue = [1, 1] + container = False + mandatory = False + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) def test_default_parser_string(): example_dic = {'default': 'DEFAULT', @@ -160,4 +256,23 @@ def test_default_parser_string(): mandatory = True ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + +def test_property_type_bundances(): + example_dic = {'default': {'He':0.4,'Mg':0.1,'Pb':0.5}, + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'abundance_set'} + + default = {'He':0.4,'Mg':0.1,'Pb':0.5} + return_default = {'he':0.4,'mg':0.1,'pb':0.5} + wdefault = "kl" + value = {'He':0.4,'Mg':0.6} + return_value = {'he':0.4,'mg':0.6} + wvalue = "yy" + container = False + mandatory = True + + ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, + return_default=return_default, return_value=return_value) + From 8e716cc9fb5879c8e0525990a91abff65c4c29f3 Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 15:04:41 +0200 Subject: [PATCH 08/15] new test yml files for the dp --- tardis/io/tests/data/conf_def.yml | 148 ++++++++++++++++++++++++++++++ tardis/io/tests/data/conf_tes.yml | 37 ++++++++ 2 files changed, 185 insertions(+) create mode 100644 tardis/io/tests/data/conf_def.yml create mode 100644 tardis/io/tests/data/conf_tes.yml diff --git a/tardis/io/tests/data/conf_def.yml b/tardis/io/tests/data/conf_def.yml new file mode 100644 index 00000000000..57af7b8f481 --- /dev/null +++ b/tardis/io/tests/data/conf_def.yml @@ -0,0 +1,148 @@ +value_test: + integer: + property_type: int + default: 99 + mandatory: True + help: 'The property type int is for integer like config items.' + integer_allowed: + property_type: int + default: 2 + allowed_value: [1,2,3,4,5,6] + mandatory: True + help: 'Like property type int, but only values given in allowed_values are valid. Allowed_value accepts a list or a string separated by spaces.' + float: + property_type: float + default: 99.99 + mandatory: True + help: 'The property type float is for float like config items.' + float_type: + property_type: float + default: 99.99 + allowed_type: ">10" + mandatory: True + help: 'Like property type float, but the range of allowed values is restricted by allowed_type. Allowed_type uses a mathematical nota to specify the range of valid values.' + float_allowed: + property_type: float + default: 9.4 + allowed_value: 1 2 13.2 10,1 + mandatory: True + help: 'Like property type float, but only values given in allowed_values are valid.' + string: + property_type: string + default: DEFAULT + mandatory: True + help: 'The property type string is for string like config items.' + string_allowed: + property_type: string + default: DEFAULT + allowed_value: cat dog + mandatory: True + help: 'Like property type string, but only values given in allowed_values are valid. Allowed_value accepts a list or a string separated by spaces.' + quantity: + property_type: quantity + default: 99.99 cm + mandatory: True + help: 'The property type quantity is for physical quantities with units given as string. The string contains value and unit separated by a whitespace E.g. 2 cm' + quantity_range: + property_type: quantity_range + default: [1 m,10 cm] #[Start,End] + mandatory: False + help: 'Like property type range but with quantitys as start and stop. The consistency of the units is checked.' + quantity_range_old: + property_type: quantity_range + default: [1 m,10 cm] #[Start,End] + mandatory: False + help: range for testing + quantity_range_sampled: + property_type: quantity_range_sampled + default: [1 m,10 cm, 0.1 cm] #[Start,End, sample] + mandatory: False + help: range for testing + + range: + property_type: range + default: [0,10] #[Start,End] + mandatory: False + help: 'The property type range specifies a range via start and end. Note: abs(start - end ) > 0' + range_sampled: + property_type: range_sampled + default: [0,10,1] #[Start,End,Nsample] + mandatory: False + help: 'Like property type range, ?? is should it be the # samples or the spacing ??' + +container_example: + property_type: container-property + type: + property_type: container-declaration + containers: ['one', 'two', 'three'] + _one: ['one_one', 'one_two'] + _two: ['two_one'] + + one_one: + property_type: string + default: 'This is a container item' + mandatory: False + help: This is a container item from the container one. + + one_two: + sub_one_two_one: + property_type: string + default: 'This is a container item' + mandatory: False + help: This is a container item from the container one. + sub_one_two_two: + property_type: string + default: 'This is a container item' + mandatory: False + help: This is a container item from the container one. + + two_one: + quantity_range: + property_type: quantity_range + default: [1 m,10 cm] #[Start,End] + mandatory: False + help: Like property type range but with quantitys as start and stop. The consistency of the units is checked. + + + + + + +supernova: + luminosity_requested: + property_type: quantity ### log_lbol to be discussed + default: 2 m + mandatory: True + help: requested luminosity for simulation + time_explosion: + property_type: quantity + default: 10 d + mandatory: False + help: time since explosion + +test: + structure: + property_type : container-property + type: + property_type: container-declaration + containers: ['file', 'specific'] + _file: ['file_property'] + file_property: + filename: + property_type: string + default: None + mandatory: True + help: file name (with path) to atomic data HDF5 file + file_container: + property_type : container-property + type: + property_type: container-declaration + containers: ['bla','blub'] + _bla: ['subset'] + subset: + subvalue: + property_type: string + default: blabla + mandatory: False + help: very helpful + diff --git a/tardis/io/tests/data/conf_tes.yml b/tardis/io/tests/data/conf_tes.yml new file mode 100644 index 00000000000..7dc9b19ddf0 --- /dev/null +++ b/tardis/io/tests/data/conf_tes.yml @@ -0,0 +1,37 @@ +value_test: + integer: 10 + integer_allowed: 3 + float: 10.5 + float_allowed: 1 + float_type: 52.3 + string: bla bla + string_allowed: cat + quantity: 10 cm + float_type: 20 + quantity_range: [2 cm, 10 km] + quantity_range_old: + start: 5 m + end: 30 km + quantity_range_sampled: [2 cm, 10 km, 1 m] + list: ['bla','blub'] + + +container_example: + type: one + one_one: 'Test' + one_two: + sub_one_one: 'More test' + sub_one_two: ' Date: Wed, 30 Apr 2014 15:05:50 +0200 Subject: [PATCH 09/15] the config parser test is fixed --- .../tardis_configv1_ascii_density_abund.yml | 2 +- ...rdis_configv1_density_exponential_test.yml | 4 ++-- ...tardis_configv1_density_power_law_test.yml | 4 ++-- .../tests/data/tardis_configv1_verysimple.yml | 4 ++-- tardis/io/tests/test_default_config_parser.py | 20 ++++++++++++++++--- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/tardis/io/tests/data/tardis_configv1_ascii_density_abund.yml b/tardis/io/tests/data/tardis_configv1_ascii_density_abund.yml index 3213466206a..860bbd06ecc 100644 --- a/tardis/io/tests/data/tardis_configv1_ascii_density_abund.yml +++ b/tardis/io/tests/data/tardis_configv1_ascii_density_abund.yml @@ -5,7 +5,7 @@ #Currently only simple1d is allowed tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 diff --git a/tardis/io/tests/data/tardis_configv1_density_exponential_test.yml b/tardis/io/tests/data/tardis_configv1_density_exponential_test.yml index 5d104e92ceb..3f3c6a77744 100644 --- a/tardis/io/tests/data/tardis_configv1_density_exponential_test.yml +++ b/tardis/io/tests/data/tardis_configv1_density_exponential_test.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure.h5 @@ -49,4 +49,4 @@ montecarlo: spectrum: start: 500 angstrom stop: 20000 angstrom - num: 10000 \ No newline at end of file + num: 10000 diff --git a/tardis/io/tests/data/tardis_configv1_density_power_law_test.yml b/tardis/io/tests/data/tardis_configv1_density_power_law_test.yml index 326a9388daf..ceea0730378 100644 --- a/tardis/io/tests/data/tardis_configv1_density_power_law_test.yml +++ b/tardis/io/tests/data/tardis_configv1_density_power_law_test.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 9.44 log_lsun + luminosity_requested: 9.44 solLum time_explosion: 13 day atom_data: kurucz_atom_pure.h5 @@ -50,4 +50,4 @@ montecarlo: spectrum: start: 500 angstrom stop: 20000 angstrom - num: 10000 \ No newline at end of file + num: 10000 diff --git a/tardis/io/tests/data/tardis_configv1_verysimple.yml b/tardis/io/tests/data/tardis_configv1_verysimple.yml index 0f5c64ff930..3deb0510a42 100644 --- a/tardis/io/tests/data/tardis_configv1_verysimple.yml +++ b/tardis/io/tests/data/tardis_configv1_verysimple.yml @@ -1,7 +1,7 @@ tardis_config_version: v1.0 supernova: - luminosity_requested: 2.8e9 Lsun + luminosity_requested: 2.8e9 solLum time_explosion: 13 day atom_data: kurucz_atom_pure_simple.h5 @@ -44,4 +44,4 @@ montecarlo: spectrum: start: 500 angstrom stop: 20000 angstrom - num: 10000 \ No newline at end of file + num: 10000 diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 33d7fa03d0b..9f4c05ec326 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -7,15 +7,26 @@ from tardis.io.default_config_parser import DefaultParser, Config, ConfigValueError -existing_configs = glob(os.path.join('tardis', 'docs', 'examples', '*.yml')) +existing_configs = glob(os.path.join('docs', 'examples', '*.yml')) +existing_configs += glob(os.path.join('tardis', 'io', 'tests', 'data', '*.yml')) config_definition = os.path.join('tardis', 'data', 'tardis_default_config_definition.yml') +test_config_definition = os.path.join('tardis', 'io', 'tests', 'data', 'conf_def.yml') +test_config = os.path.join('tardis', 'io', 'tests', 'data', 'conf_tes.yml') +existing_configs.remove(test_config_definition) +existing_configs.remove(test_config) +print(existing_configs) -@pytest.mark.parametrize(("config_filename",), existing_configs) + +@pytest.mark.parametrize("config_filename", existing_configs) def test_configread(config_filename): config = Config.from_yaml(config_filename, config_definition) +def test_configread_test_config(): + config = Config.from_yaml(test_config, test_config_definition) + + def default_parser_helper(test_dic, default, wdefault, value, wvalue, container, mandatory, return_default=None, return_value=None, value_as_string=True): test_ob = DefaultParser(test_dic) @@ -275,4 +286,7 @@ def test_property_type_bundances(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, return_default=return_default, return_value=return_value) - + + + + From 01d8cbdcc1e27eaf874ed3c0e18ce7ac6f1b439a Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 15:07:22 +0200 Subject: [PATCH 10/15] print removed --- tardis/io/tests/test_default_config_parser.py | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/tardis/io/tests/test_default_config_parser.py b/tardis/io/tests/test_default_config_parser.py index 9f4c05ec326..0ed0c160868 100644 --- a/tardis/io/tests/test_default_config_parser.py +++ b/tardis/io/tests/test_default_config_parser.py @@ -15,7 +15,6 @@ test_config = os.path.join('tardis', 'io', 'tests', 'data', 'conf_tes.yml') existing_configs.remove(test_config_definition) existing_configs.remove(test_config) -print(existing_configs) @pytest.mark.parametrize("config_filename", existing_configs) @@ -119,13 +118,14 @@ def test_default_parser_quantity(): mandatory = True ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, - return_default=return_default,return_value=return_value ) + return_default=return_default, return_value=return_value) + def test_default_parser_quantity_range(): example_dic = {'default': ['1 cm', '5 cm'], - 'help': 'quantity for testing', - 'mandatory': True, - 'property_type': 'quantity_range'} + 'help': 'quantity for testing', + 'mandatory': True, + 'property_type': 'quantity_range'} default = ['1.0 cm', '5 cm'] return_default = [1.0 * u.cm, 5 * u.cm] @@ -139,8 +139,9 @@ def test_default_parser_quantity_range(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, return_default=return_default, return_value=return_value) + def test_default_parser_quantity_range_old(): - example_dic = {'default':{'start':'1 cm', 'end':'5 cm'}, + example_dic = {'default': {'start': '1 cm', 'end': '5 cm'}, 'help': 'quantity for testing', 'mandatory': True, 'property_type': 'quantity_range'} @@ -157,13 +158,14 @@ def test_default_parser_quantity_range_old(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, return_default=return_default, return_value=return_value) + def test_default_parser_quantity_range_sampeled(): example_dic = {'default': ['1 cm', '5 cm', 10], 'help': 'quantity for testing', 'mandatory': True, 'property_type': 'quantity_range_sampled'} - default = ['1.0 cm', '5 cm',10] + default = ['1.0 cm', '5 cm', 10] return_default = [1.0 * u.cm, 5 * u.cm, 10] wdefault = "kl" value = ['10 m', '50 cm', 10] @@ -175,13 +177,14 @@ def test_default_parser_quantity_range_sampeled(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, return_default=return_default, return_value=return_value) + def test_default_parser_quantity_range_sampeled_old(): - example_dic = {'default': {'start':'1 cm', 'stop':'5 cm', 'num':10}, + example_dic = {'default': {'start': '1 cm', 'stop': '5 cm', 'num': 10}, 'help': 'quantity for testing', 'mandatory': True, 'property_type': 'quantity_range_sampled'} - default = ['1.0 cm', '5 cm',10] + default = ['1.0 cm', '5 cm', 10] return_default = [1.0 * u.cm, 5 * u.cm, 10] wdefault = "kl" value = ['10 m', '50 cm', 10] @@ -193,6 +196,7 @@ def test_default_parser_quantity_range_sampeled_old(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory, return_default=return_default, return_value=return_value) + def test_default_parser_range(): example_dic = {'default': [0, 10], 'help': 'range for testing', @@ -208,8 +212,9 @@ def test_default_parser_range(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_default_parser_range_old(): - example_dic = {'default': {'start':0,'stop':10}, + example_dic = {'default': {'start': 0, 'stop': 10}, 'help': 'range for testing', 'mandatory': False, 'property_type': 'range'} @@ -223,6 +228,7 @@ def test_default_parser_range_old(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_default_parser_range_sampled(): example_dic = {'default': [0, 10, 1], 'help': 'range for testing', @@ -238,8 +244,9 @@ def test_default_parser_range_sampled(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_default_parser_range_sampled(): - example_dic = {'default': {'start':0,'stop':10,'num':1}, + example_dic = {'default': {'start': 0, 'stop': 10, 'num': 1}, 'help': 'range for testing', 'mandatory': False, 'property_type': 'range_sampled'} @@ -253,6 +260,7 @@ def test_default_parser_range_sampled(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_default_parser_string(): example_dic = {'default': 'DEFAULT', 'help': 'string for testing', @@ -268,17 +276,18 @@ def test_default_parser_string(): ex = default_parser_helper(example_dic, default, wdefault, value, wvalue, container, mandatory) + def test_property_type_bundances(): - example_dic = {'default': {'He':0.4,'Mg':0.1,'Pb':0.5}, + example_dic = {'default': {'He': 0.4, 'Mg': 0.1, 'Pb': 0.5}, 'help': 'quantity for testing', 'mandatory': True, 'property_type': 'abundance_set'} - default = {'He':0.4,'Mg':0.1,'Pb':0.5} - return_default = {'he':0.4,'mg':0.1,'pb':0.5} + default = {'He': 0.4, 'Mg': 0.1, 'Pb': 0.5} + return_default = {'he': 0.4, 'mg': 0.1, 'pb': 0.5} wdefault = "kl" - value = {'He':0.4,'Mg':0.6} - return_value = {'he':0.4,'mg':0.6} + value = {'He': 0.4, 'Mg': 0.6} + return_value = {'he': 0.4, 'mg': 0.6} wvalue = "yy" container = False mandatory = True From f788f84ac737bcac7b32cdfffc939470a3b44014 Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 17:19:28 +0200 Subject: [PATCH 11/15] Special offer! Now with extra numpy docstrings! --- tardis/io/default_config_parser.py | 266 ++++++++++++++++++++--------- 1 file changed, 189 insertions(+), 77 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index 6e005aa8ace..d6b4fbc8fae 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -324,7 +324,8 @@ def _to_units(self, los): def check_type(self, value): if isinstance(value, dict): - if reduce((lambda a, b: a and b in value), [True, 'start', 'end']): + if (reduce((lambda a, b: a and b in value.keys()), [True, 'start', 'end'])) \ + or (reduce((lambda a, b: a and b in value.keys()), [True, 'start', 'stop'])): #for legacy support los = [value['start'], value['end']] loq = self._to_units(los) if abs(loq[0].value - loq[1].value) > 0: @@ -670,14 +671,19 @@ def __init__(self, default_dict, item_path=None): def get_default(self): """Returns the default value of this property, if specified. - :return: default value + + Returns + ------- + default value """ return self.__type.default def set_default(self, value): - """ - Set a new default value. - :param value: new default value + """Set a new default value. + Parameters + ---------- + value: + new default value """ if value is not None: if self.__type.check_type(value): @@ -690,17 +696,21 @@ def set_default(self, value): @property def is_mandatory(self): - """ - Returns True if this property is a mandatory. - :return: mandatory + """Returns True if this property is a mandatory. + Returns + ------- + bool: + True if this property is a mandatory. """ return self.__type.mandatory @property def has_default(self): - """ - Returns True if this property has a default value - :return: has a default value + """Returns True if this property has a default value + Returns + ------- + bool: + True if a default value was given. """ try: if self.__type.default != None: @@ -711,25 +721,29 @@ def has_default(self): pass def set_path_in_dic(self, path): - """ - Set the path to this property in the config - :param path: path(chain of keys) - :return: + """Set the path to this property in the config + Parameters + ---------- + path: list of str + Path in config dictionary. """ self.__path = path def get_path_in_dict(self): - """ - Returns the path of this property in the config - :return: path + """Returns the path of this property in the config + Return + ------ + path: list of str + Path in config dictionary. """ return self.__path def set_config_value(self, value): - """ - Set a new value - :param value: - :return: + """Set a new config value. + Parameters + ---------- + value: + New config value. """ self.__config_value = value @@ -738,7 +752,10 @@ def get_value(self): Returns the configuration value from the configuration. If the value specified in the configuration is invalid the default value is returned - :return: value + Return + ------ + value: + Config value. """ if (self.__config_value is not None): if self.__type.check_type(self.__config_value): @@ -764,7 +781,6 @@ def get_value(self): def is_container(self): """ Returns True if this property is of type container. - :return: """ return self.__is_container() @@ -772,7 +788,10 @@ def get_container_dic(self): """ If this property is a container it returns the corresponding container dictionary - :return: container dictionary + Return + ------ + container dictionary: dict + Container dictionary """ if self.__is_container(): return self.__container_dic @@ -791,17 +810,6 @@ def update_container_dic(cls, container_dic, current_entry_name): return container_dic - # def is_valid(self, value): - # if not self.__check[self.__property_type](self, value): - # return False - # if self.__allowed_value: - # if not self.__is_allowed_value(value, self.__allowed_value): - # return False - # if self.__allowed_type: - # if not self.__check_value(value, self.__lower, self.__upper): - # return False - # return True - def __register_leaf(self, type_name): if not type_name in self.__list_of_leaf_types: self.__list_of_leaf_types.append(type_name) @@ -828,8 +836,12 @@ def __is_container_declaration(self, value): class Container(DefaultParser): def __init__(self, container_default_dict, container_dict, container_path=None): """Creates a new container object. - :param container_default_dict: Dictionary containing the default properties of the container. - :param container_dict: Dictionary containing the configuration of the container. + Parameters + ---------- + container_default_dict: dict + Dictionary containing the default properties of the container. + container_dict: dict + Dictionary containing the configuration of the container. """ @@ -930,12 +942,19 @@ def __init__(self, container_default_dict, container_dict, container_path=None): def parse_container_items(top_default, top_config, level_name, full_path): """Recursive parser for the container default dictionary and the container configuration dictionary. - - :param top_default: container default dictionary of the upper recursion level - :param top_config: container configuration dictionary of the upper recursion level - :param level_name: name(key) of the of the upper recursion level - :param path: path in the nested container dictionary from the main level to the current level - :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + Parameters + ---------- + top_default: dict + container default dictionary of the upper recursion level + top_config: dict + container configuration dictionary of the upper recursion level + level_name: str + name(key) of the of the upper recursion level + path: list of str + path in the nested container dictionary from the main level to the current level + Return + ------ + If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf the configured value and a configuration object is returned """ @@ -967,7 +986,17 @@ def parse_container_items(top_default, top_config, level_name, full_path): def reduce_list(a, b): """ - removes items from list a which are in b + removes items from list a which are in b. (o.B.d.A trivial) + Parameters + ---------- + a: list + minuend + b: list + subtrahend + Return + ------ + a: list + difference """ for k in b: a.remove(k) @@ -977,9 +1006,16 @@ def reduce_list(a, b): def get_value_by_path(dict, path): """ Value from a nested dictionary specified by its path. - :param dict: nested source dictionary - :param path: path (composed of keys) in the dictionary - :return: + Parameters + ---------- + dict: dict + nested source dictionary + path: list of str + path (composed of keys) in the dictionary + Return + ------ + dict: str + value corresponding to the given path """ for key in path: dict = dict[key] @@ -990,14 +1026,20 @@ def get_value_by_path(dict, path): def get_container_ob(self): """ Return the container configuration object - :return: + Return + ------ + self.__container_ob: DefaultParser + container configuration object """ return self.__container_ob def get_container_conf(self): """ Return the configuration - :return: + Return + ------ + self.__container_ob: dict + container configuration """ self.__conf['type'] = self.__type return self.__conf @@ -1011,8 +1053,12 @@ class Config(object): def __init__(self, default_configuration, input_configuration): """Creates the configuration object. - :param default_configuration: Default configuration dictionary - :param input_configuration: Configuration dictionary + Parameters + ---------- + default_configuration: dict + Default configuration dictionary + input_configuration: dict + Configuration dictionary """ self.__conf_o = None self.__conf_v = None @@ -1035,29 +1081,47 @@ def from_yaml(cls, fname_config, fname_default): def __mandatory_key(self, path): """Return the key string for dictionary of mandatory entries - :param path: path (composed of keys) in the dictionary - :return: corresponding key + Parameters + ---------- + path: list of str + path (composed of keys) in the dictionary + Return + ------ + mandatory_key: str + corresponding key """ return ':'.join(path) def register_mandatory(self, name, path): """Register a mandatory entry - :param name: name of the mandatory entry to be registered - :param path: path (composed of keys) in the dictionary + Parameters + ---------- + name: str + name of the mandatory entry to be registered + path: list of str + path (composed of keys) in the dictionary """ self.mandatories[self.__mandatory_key(path)] = name def deregister_mandatory(self, name, path): """Register a deregistered mandatory entry - :param name: name of the mandatory entry to be deregistered - :param path: path (composed of keys) in the dictionary + Parameters + ---------- + name: str + name of the mandatory entry to be deregistered + path: list of str + path (composed of keys) in the dictionary """ self.fulfilled[self.__mandatory_key(path)] = name def is_mandatory_fulfilled(self): """ Check if all mandatory entries are deregistered. + Return + ------ + mandatory: bool + True if all mandatory entries are deregistered, otherwise False """ if len(set(self.mandatories.keys()) - set(self.fulfilled.keys())) <= 0: return True @@ -1066,15 +1130,28 @@ def is_mandatory_fulfilled(self): def __parse_config(self, default_configuration, configuration): """Parser for the default dictionary and the configuration dictionary. - :param default_configuration: Default configuration dictionary - :param configuration: Configuration dictionary + Parameters + ------ + default_configuration: dict + Default configuration dictionary + configuration: dict + Configuration dictionary """ def find_item(dict, key): """ Returns the value for a specific key in a nested dictionary - :param dict: nested dictionary - :param key: + note:: Deprecated, use get_property_by_path() + Parameters + ---------- + dict: dict + nested dictionary + key: str + key in the nested dictionary + Return + ------ + item: object + value corresponding to the specific key. """ if key in dict: return dict[key] for k, v in dict.items(): @@ -1086,8 +1163,16 @@ def find_item(dict, key): def get_property_by_path(d, path): """ Returns the value for a specific path(chain of keys) in a nested dictionary - :param dict: nested dictionary - :param path: chain of keys as list + Parameters + ---------- + dict: dict + nested dictionary + path: list of str + chain of keys as list + Return + ------ + item: object + value in the nested dictionary at the specific path. """ if len(path) <= 0: return d @@ -1103,10 +1188,17 @@ def get_property_by_path(d, path): def recursive_parser(top_default, configuration, path): """ Recursive parser for the default dictionary. - :param top_default: container default dictionary of the upper recursion level - :param configuration: configuration dictionary - :param path: path in the nested container dictionary from the main level to the current level - :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + Parameters + ---------- + top_default: dict + container default dictionary of the upper recursion level + configuration: dict + configuration dictionary + path: list of str + path in the nested container dictionary from the main level to the current level + Return + ------ + If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf, the configuration value and object are returned """ @@ -1159,17 +1251,28 @@ def __check_items_in_conf(self, config_dict, default_dict): return list(default_dict.keys()) - def __create_default_conf(self, default_conf): + def __create_default_conf(self, default_coobjectsnf): """Returns the default configuration values as dictionary. - :param default_conf: default configuration dictionary - :return: default configuration values + Parameters + ---------- + default_conf: dict + default configuration dictionary + Return + ------ + default configuration values """ def recursive_default_parser(top_default, path): """Recursive parser for the default dictionary. - :param top_default: container default dictionary of the upper recursion level - :param path: path in the nested container dictionary from the main level to the current level - :return: If the current recursion level is not a leaf, the function returns a dictionary with itself for + Parameters + ---------- + top_default: dict + container default dictionary of the upper recursion level + path: list of str + path in the nested container dictionary from the main level to the current level + Return + ------ + If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf, the default configuration value is returned """ @@ -1193,19 +1296,28 @@ def recursive_default_parser(top_default, path): def get_config(self): """Returns the parsed configuration as dictionary. - :return: configuration values as dictionary + Return + ------ + configuration: dict + configuration values as dictionary """ return self.__conf_v def get_default_config(self): """Returns the default configuration values as dictionary - :return: default configuration values as dictionary + Return + ------ + default_configuration: dict + default configuration values as dictionary """ return self.__default_config def get_config_object(self): """Returns the default configuration objects as dictionary - :return: default configuration objects as dictionary + Return + ------ + default_configuration: objects + default configuration objects as dictionary """ return self.__conf_o From c7613435b04df90a46e8f5d0c935fb31c0b7c930 Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 18:31:41 +0200 Subject: [PATCH 12/15] Special offer! Now with fixed numpy docstrings! --- tardis/io/default_config_parser.py | 92 ++++++++++++++++-------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index d6b4fbc8fae..165c876228e 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -78,7 +78,12 @@ def __str__(self): class PropertyType(object): - def __init__(self): + """ + Base class for all property types containing all the basic methods. + """ + + +def __init__(self): self._default = None self._allowed_value = None self._allowed_type = None @@ -90,7 +95,10 @@ def __init__(self): @property def default(self): - return self._default + """ + + """ + return self._default @default.setter def default(self, value): @@ -699,7 +707,7 @@ def is_mandatory(self): """Returns True if this property is a mandatory. Returns ------- - bool: + bool True if this property is a mandatory. """ return self.__type.mandatory @@ -709,7 +717,7 @@ def has_default(self): """Returns True if this property has a default value Returns ------- - bool: + bool True if a default value was given. """ try: @@ -731,8 +739,8 @@ def set_path_in_dic(self, path): def get_path_in_dict(self): """Returns the path of this property in the config - Return - ------ + Returns + ------- path: list of str Path in config dictionary. """ @@ -742,7 +750,7 @@ def set_config_value(self, value): """Set a new config value. Parameters ---------- - value: + value New config value. """ self.__config_value = value @@ -752,9 +760,9 @@ def get_value(self): Returns the configuration value from the configuration. If the value specified in the configuration is invalid the default value is returned - Return - ------ - value: + Returns + ------- + value Config value. """ if (self.__config_value is not None): @@ -788,8 +796,8 @@ def get_container_dic(self): """ If this property is a container it returns the corresponding container dictionary - Return - ------ + Returns + ------- container dictionary: dict Container dictionary """ @@ -952,8 +960,8 @@ def parse_container_items(top_default, top_config, level_name, full_path): name(key) of the of the upper recursion level path: list of str path in the nested container dictionary from the main level to the current level - Return - ------ + Returns + ------- If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf the configured value and a configuration object is returned @@ -993,8 +1001,8 @@ def reduce_list(a, b): minuend b: list subtrahend - Return - ------ + Returns + ------- a: list difference """ @@ -1012,8 +1020,8 @@ def get_value_by_path(dict, path): nested source dictionary path: list of str path (composed of keys) in the dictionary - Return - ------ + Returns + ------- dict: str value corresponding to the given path """ @@ -1026,8 +1034,8 @@ def get_value_by_path(dict, path): def get_container_ob(self): """ Return the container configuration object - Return - ------ + Returns + ------- self.__container_ob: DefaultParser container configuration object """ @@ -1036,8 +1044,8 @@ def get_container_ob(self): def get_container_conf(self): """ Return the configuration - Return - ------ + Returns + ------- self.__container_ob: dict container configuration """ @@ -1085,8 +1093,8 @@ def __mandatory_key(self, path): ---------- path: list of str path (composed of keys) in the dictionary - Return - ------ + Returns + ------- mandatory_key: str corresponding key """ @@ -1118,8 +1126,8 @@ def deregister_mandatory(self, name, path): def is_mandatory_fulfilled(self): """ Check if all mandatory entries are deregistered. - Return - ------ + Returns + ------- mandatory: bool True if all mandatory entries are deregistered, otherwise False """ @@ -1148,8 +1156,8 @@ def find_item(dict, key): nested dictionary key: str key in the nested dictionary - Return - ------ + Returns + ------- item: object value corresponding to the specific key. """ @@ -1169,8 +1177,8 @@ def get_property_by_path(d, path): nested dictionary path: list of str chain of keys as list - Return - ------ + Returns + ------- item: object value in the nested dictionary at the specific path. """ @@ -1196,8 +1204,8 @@ def recursive_parser(top_default, configuration, path): configuration dictionary path: list of str path in the nested container dictionary from the main level to the current level - Return - ------ + Returns + ------- If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf, the configuration value and object are returned @@ -1257,8 +1265,8 @@ def __create_default_conf(self, default_coobjectsnf): ---------- default_conf: dict default configuration dictionary - Return - ------ + Returns + ------- default configuration values """ @@ -1270,8 +1278,8 @@ def recursive_default_parser(top_default, path): container default dictionary of the upper recursion level path: list of str path in the nested container dictionary from the main level to the current level - Return - ------ + Returns + ------- If the current recursion level is not a leaf, the function returns a dictionary with itself for each branch. If the current recursion level is a leaf, the default configuration value is returned @@ -1296,8 +1304,8 @@ def recursive_default_parser(top_default, path): def get_config(self): """Returns the parsed configuration as dictionary. - Return - ------ + Returns + ------- configuration: dict configuration values as dictionary """ @@ -1305,8 +1313,8 @@ def get_config(self): def get_default_config(self): """Returns the default configuration values as dictionary - Return - ------ + Returns + ------- default_configuration: dict default configuration values as dictionary """ @@ -1314,8 +1322,8 @@ def get_default_config(self): def get_config_object(self): """Returns the default configuration objects as dictionary - Return - ------ + Returns + ------- default_configuration: objects default configuration objects as dictionary """ From 5622a09697b73aa7245a53c021e4175ce1572954 Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 18:53:35 +0200 Subject: [PATCH 13/15] Special offer! Now with fixed numpy docstrings! --- tardis/io/default_config_parser.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index 165c876228e..39aebc6e646 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -5,11 +5,12 @@ import pprint import ast -from tardis.atomic import atomic_symbols_data from astropy import units from astropy.units.core import UnitsException import yaml +from tardis.atomic import atomic_symbols_data + logger = logging.getLogger(__name__) @@ -96,11 +97,16 @@ def __init__(self): @property def default(self): """ - + Geter for the default config value. + Returns + ------- + default + default config value. """ - return self._default +return self._default + - @default.setter +@default.setter def default(self, value): self._default = self.to_type(value) @@ -944,7 +950,6 @@ def __init__(self, container_default_dict, container_dict, container_path=None): if isinstance(self.__config_container, dict): self.__conf = self.__config_container else: - pdb.set_trace() self.__conf = {"No Name": self.__config_container} @@ -969,7 +974,6 @@ def parse_container_items(top_default, top_config, level_name, full_path): path = reduce_list(list(full_path), self.__container_path + [item]) tmp_conf_ob = {} tmp_conf_val = {} - #pdb.set_trace() if isinstance(top_default, dict): default_property = DefaultParser(top_default) if default_property.is_container(): @@ -1259,7 +1263,7 @@ def __check_items_in_conf(self, config_dict, default_dict): return list(default_dict.keys()) - def __create_default_conf(self, default_coobjectsnf): + def __create_default_conf(self, default_conf): """Returns the default configuration values as dictionary. Parameters ---------- From e2c35352234def1928617adcdcaecd35a5a3ea3f Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 19:12:40 +0200 Subject: [PATCH 14/15] arrg!1!! line 106 --- tardis/io/default_config_parser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index 39aebc6e646..c4fdba616cc 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -94,8 +94,11 @@ def __init__(self): self._upper = None pass - @property - def default(self): + +@property +def default(self): + + """ Geter for the default config value. Returns From 1537471597e02c3df67a46cccf08dcd599ceebd5 Mon Sep 17 00:00:00 2001 From: Michi Date: Wed, 30 Apr 2014 19:50:04 +0200 Subject: [PATCH 15/15] code clean up --- tardis/io/default_config_parser.py | 183 ++++++++++++++++------------- 1 file changed, 101 insertions(+), 82 deletions(-) diff --git a/tardis/io/default_config_parser.py b/tardis/io/default_config_parser.py index c4fdba616cc..790d1d59cc5 100644 --- a/tardis/io/default_config_parser.py +++ b/tardis/io/default_config_parser.py @@ -26,10 +26,10 @@ class ConfigTypeError(Error, ValueError): specified in the default configuration. """ - def __init__(self, value, expected_type, help): + def __init__(self, value, expected_type, _help): self.value = value self.expected_type = expected_type - self.help = help + self.help = _help def __str__(self): return "Expected type %s but found %s.\nHelp:%s " % \ @@ -83,8 +83,7 @@ class PropertyType(object): Base class for all property types containing all the basic methods. """ - -def __init__(self): + def __init__(self): self._default = None self._allowed_value = None self._allowed_type = None @@ -94,49 +93,73 @@ def __init__(self): self._upper = None pass - -@property -def default(self): - - - """ - Geter for the default config value. - Returns - ------- - default + @property + def default(self): + """ + Geter for the default config value. + Returns + ------- + default default config value. - """ -return self._default - + """ + return self._default -@default.setter + @default.setter def default(self, value): + """ + Sets the default value if the type is ok. + Parameters + ---------- + value + default value + """ self._default = self.to_type(value) @property def allowed_value(self): + """ + Returns the allowed value + Returns + ------- + allowed_value + allowed value + """ return self._allowed_value @allowed_value.setter def allowed_value(self, value): + """ + Sets the allowed values + Parameters + ---------- + value + allowed values + """ if isinstance(value, basestring): self._allowed_value = set(self.__list_dtype(value.split())) elif isinstance(value, list) or isinstance(value, set): self._allowed_value = set(self.__list_dtype(value)) elif isinstance(value, float) or isinstance(value, int): - self._allowed_type = set([value]) + self._allowed_type = {value} else: raise ValueError("Can not set allowed value.") - @property def allowed_type(self): + """ + Returns the allowed type + Returns + ------- + allowed_type + allowed type + + """ return self._allowed_value @allowed_type.setter def allowed_type(self, value): self._allowed_type = value - if '_parse_allowed_type' in (set(dir(self.__class__)) - set(dir(PropertyType))) and value != None: + if '_parse_allowed_type' in (set(dir(self.__class__)) - set(dir(PropertyType))) and value is not None: self._lower, self._upper = self._parse_allowed_type(value) @property @@ -161,7 +184,8 @@ def check_type(self, value): def to_type(self, value): return value - def __list_dtype(self, mixed_list): + @staticmethod + def __list_dtype(mixed_list): try: tmp = [str(a) for a in mixed_list] except ValueError: @@ -174,12 +198,11 @@ def __list_dtype(self, mixed_list): raise ValueError("Forbidden type in allowed_type") return tmp - def _check_allowed_value(self, _value): """ Returns True if the value is allowed or no allowed value is given. """ - if self._allowed_value != None: + if self._allowed_value is not None: atype = type(iter(self.allowed_value).next()) value = atype(_value) if value in self.allowed_value: @@ -191,9 +214,9 @@ def _check_allowed_value(self, _value): def __repr__(self): if hasattr(self, "_allowed_type"): - return "Type %s; Allowed type: %s" % (self.__class__.__name__, self._allowed_type) + return str("Type %s; Allowed type: %s" % (self.__class__.__name__, self._allowed_type)) else: - return "Type %s; " % (self.__class__.__name__) + return str("Type %s; " % self.__class__.__name__) class PropertyTypeContainer(PropertyType): @@ -206,7 +229,7 @@ def check_type(self, value): try: foo = bool(value) return True - except: + except ValueError: return False def to_type(self, value): @@ -229,7 +252,8 @@ def to_type(self, value): return int(value) #ToDo: use this if allowed type is specified - def _parse_allowed_type(self, allowed_type): + @staticmethod + def _parse_allowed_type(allowed_type): string = allowed_type.strip() upper = None lower = None @@ -256,17 +280,17 @@ def _parse_allowed_type(self, allowed_type): lower = float(value) return lower, upper - def __check_type(self, value, lower_lim, upper_lim): + @staticmethod + def __check_type(value, lower_lim, upper_lim): upper, lower = True, True - if upper_lim != None: + if upper_lim is not None: upper = value < upper_lim - if lower_lim != None: + if lower_lim is not None: lower = value > lower_lim return upper and lower - def _check_allowed_type(self, value): - if self._allowed_type != None: + if self._allowed_type is not None: if self.__check_type(value, self._lower, self._upper): return True else: @@ -277,7 +301,7 @@ def _check_allowed_type(self, value): def _is_valid(self, value): if not self.check_type(value): return False - if self.allowed_value != None: + if self.allowed_value is not None: return False if not self.__check_type(value, self._lower, self._upper): return False @@ -326,7 +350,8 @@ def to_type(self, value): class PropertyTypeQuantityRange(PropertyTypeQuantity): - def _to_units(self, los): + @staticmethod + def _to_units(los): if len(los) > 2: loq = [(lambda x: (units.Quantity(float(x[0]), x[1])))(x.split()) for x in los[:-1]] else: @@ -342,7 +367,7 @@ def _to_units(self, los): def check_type(self, value): if isinstance(value, dict): if (reduce((lambda a, b: a and b in value.keys()), [True, 'start', 'end'])) \ - or (reduce((lambda a, b: a and b in value.keys()), [True, 'start', 'stop'])): #for legacy support + or (reduce((lambda a, b: a and b in value.keys()), [True, 'start', 'stop'])): # for legacy support los = [value['start'], value['end']] loq = self._to_units(los) if abs(loq[0].value - loq[1].value) > 0: @@ -365,7 +390,7 @@ def check_type(self, value): return False else: return False - except (SyntaxError): + except SyntaxError: clist = value.split() if len(clist) == 2: loq = self._to_units(value) @@ -456,11 +481,10 @@ def check_type(self, value): try: value.split() return True - except: + except AttributeError: return False return False - def to_type(self, value): if isinstance(value, list): return value @@ -509,7 +533,7 @@ def to_type(self, value): class PropertyTypeRangeSampled(PropertyTypeRange): def check_type(self, value): if isinstance(value, dict): - if reduce((lambda a, b: a in value), \ + if reduce((lambda a, b: a in value), [True, 'start', 'stop', 'num']): if abs(value['start'] - value['stop']) > 0: return True @@ -541,10 +565,10 @@ def to_type(self, value): class PropertyTypeAbundances(PropertyType): - elements = dict([(x,y.lower()) for (x,y) in atomic_symbols_data]) + elements = dict([(x, y.lower()) for (x, y) in atomic_symbols_data]) def check_type(self, _value): - if isinstance(_value,dict): + if isinstance(_value, dict): value = dict((k.lower(), v) for k, v in _value.items()) if set(value).issubset(set(self.elements.values())): return True @@ -564,8 +588,9 @@ def to_type(self, _value): else: raise ConfigError + class PropertyTypeLegacyAbundances(PropertyType): - elements = dict([(x,y.lower()) for (x,y) in atomic_symbols_data]) + elements = dict([(x, y.lower()) for (x, y) in atomic_symbols_data]) types = ['uniform'] def check_type(self, _value): @@ -661,6 +686,8 @@ def __init__(self, default_dict, item_path=None): self.__config_value = None self.__path = None + self.__container_dic = None + self.__default_dict = default_dict if not 'property_type' in default_dict: @@ -678,7 +705,7 @@ def __init__(self, default_dict, item_path=None): self.__type.allowed_type = default_dict['allowed_type'] if 'default' in default_dict: - if default_dict['default'] != None and not default_dict['default'] in ['None', '']: + if default_dict['default'] is not None and not default_dict['default'] in ['None', '']: self.__type.default = default_dict['default'] if 'mandatory' in default_dict: @@ -730,7 +757,7 @@ def has_default(self): True if a default value was given. """ try: - if self.__type.default != None: + if self.__type.default is not None: return True else: return False @@ -774,7 +801,7 @@ def get_value(self): value Config value. """ - if (self.__config_value is not None): + if self.__config_value is not None: if self.__type.check_type(self.__config_value): return self.__type.to_type(self.__config_value) else: @@ -794,7 +821,6 @@ def get_value(self): str(self.get_path_in_dict()))) return None - def is_container(self): """ Returns True if this property is of type container. @@ -815,8 +841,8 @@ def get_container_dic(self): @classmethod def update_container_dic(cls, container_dic, current_entry_name): - if reduce(lambda a, b: a or b, \ - [container_dic.has_key(i) for i in ['and', 'or']], True): + if reduce(lambda a, b: a or b, + [(i in container_dic) for i in ['and', 'or']], True): if 'or' in container_dic: if current_entry_name in container_dic['or']: container_dic['or'] = [] @@ -826,7 +852,6 @@ def update_container_dic(cls, container_dic, current_entry_name): current_entry_name['and'].remove(current_entry_name) return container_dic - def __register_leaf(self, type_name): if not type_name in self.__list_of_leaf_types: self.__list_of_leaf_types.append(type_name) @@ -861,7 +886,6 @@ def __init__(self, container_default_dict, container_dict, container_path=None): Dictionary containing the configuration of the container. """ - self.__container_path = container_path self.__type = None self.__allowed_value = None @@ -924,6 +948,7 @@ def __init__(self, container_default_dict, container_dict, container_path=None): #look for additional items entry_name = '+' + self.__selected_container + self.__has_additional_items = False try: additional_items = container_default_dict['type'][entry_name] self.__has_additional_items = True @@ -936,15 +961,16 @@ def __init__(self, container_default_dict, container_dict, container_path=None): if not item in container_dict.keys(): raise ValueError('Entry %s is missing in container [%s]' % (str(item), self.__container_path)) else: - self.__default_container[item], self.__config_container[item] = parse_container_items( + self.__default_container[item], self.__config_container[item] = self.parse_container_items( container_default_dict[item], container_dict[item], item, self.__container_path + [item]) if self.__has_additional_items: - for item in additional_items: + for aitem in additional_items: try: - self.__default_container[item], self.__config_container[item] = parse_container_items( - container_default_dict[item], - container_dict[item], item, self.__container_path + [item]) + self.__default_container[aitem], self.__config_container[aitem] = \ + self.parse_container_items(container_default_dict[aitem], + container_dict[aitem], aitem, + self.__container_path + [aitem]) except KeyError: pass @@ -955,9 +981,10 @@ def __init__(self, container_default_dict, container_dict, container_path=None): else: self.__conf = {"No Name": self.__config_container} - def parse_container_items(top_default, top_config, level_name, full_path): - """Recursive parser for the container default dictionary and the container configuration dictionary. + """Recursive parser for the container default dictionary and the container configuration + dictionary. + Parameters ---------- top_default: dict @@ -1017,8 +1044,7 @@ def reduce_list(a, b): a.remove(k) return a - - def get_value_by_path(dict, path): + def get_value_by_path(_dict, path): """ Value from a nested dictionary specified by its path. Parameters @@ -1033,10 +1059,8 @@ def get_value_by_path(dict, path): value corresponding to the given path """ for key in path: - dict = dict[key] - return dict - - + dict = _dict[key] + return _dict def get_container_ob(self): """ @@ -1065,7 +1089,6 @@ class Config(object): An configuration object represents the parsed configuration. """ - def __init__(self, default_configuration, input_configuration): """Creates the configuration object. Parameters @@ -1082,6 +1105,7 @@ def __init__(self, default_configuration, input_configuration): self.__create_default_conf(default_configuration) self.__parse_config(default_configuration, input_configuration) self.__help_string = '' + self.__default_config = None @classmethod def from_yaml(cls, fname_config, fname_default): @@ -1093,8 +1117,8 @@ def from_yaml(cls, fname_config, fname_default): defa = yaml.safe_load(defaf) return cls(defa, conf) - - def __mandatory_key(self, path): + @staticmethod + def __mandatory_key(path): """Return the key string for dictionary of mandatory entries Parameters ---------- @@ -1107,7 +1131,6 @@ def __mandatory_key(self, path): """ return ':'.join(path) - def register_mandatory(self, name, path): """Register a mandatory entry Parameters @@ -1153,13 +1176,13 @@ def __parse_config(self, default_configuration, configuration): Configuration dictionary """ - def find_item(dict, key): + def find_item(_dict, key): """ Returns the value for a specific key in a nested dictionary note:: Deprecated, use get_property_by_path() Parameters ---------- - dict: dict + _dict: dict nested dictionary key: str key in the nested dictionary @@ -1168,14 +1191,14 @@ def find_item(dict, key): item: object value corresponding to the specific key. """ - if key in dict: return dict[key] - for k, v in dict.items(): - if isinstance(v, dict): + if key in _dict: + return _dict[key] + for k, v in _dict.items(): + if isinstance(v, _dict): item = find_item(v, key) if item is not None: return item - def get_property_by_path(d, path): """ Returns the value for a specific path(chain of keys) in a nested dictionary Parameters @@ -1255,17 +1278,15 @@ def recursive_parser(top_default, configuration, path): if conf_value is not None: default_property.set_config_value(conf_value) return default_property, default_property.get_value() - - self.__conf_o, self.__conf_v = recursive_parser(default_configuration, configuration, []) - def __check_items_in_conf(self, config_dict, default_dict): + @staticmethod + def __check_items_in_conf(config_dict, default_dict): if isinstance(config_dict, dict) and len(config_dict) > 0: return list(set(config_dict.keys()) - set(default_dict.keys())) else: return list(default_dict.keys()) - def __create_default_conf(self, default_conf): """Returns the default configuration values as dictionary. Parameters @@ -1308,7 +1329,6 @@ def recursive_default_parser(top_default, path): self.__default_config = recursive_default_parser(default_conf, []) - def get_config(self): """Returns the parsed configuration as dictionary. Returns @@ -1337,10 +1357,9 @@ def get_config_object(self): return self.__conf_o def get_help(self): - return (pprint.pformat(self.get_default_config())) - + return pprint.pformat(self.get_default_config()) def __repr__(self): - return (str(pprint.pformat(self.get_config()))) + return str(pprint.pformat(self.get_config()))