def register_from_cfg(self, cfg): """"Register new elements from a :class:`ConfigObj` instance or a config file""" if isinstance(cfg, dict) and self.category not in cfg.keys(): cfg = {self.category:cfg} local_cfg = CF_CFGM.load(cfg)[self.category] self._dict = dict_merge(self._dict, local_cfg, cls=OrderedDict, **CF_DICT_MERGE_KWARGS) self._post_process_()
def load_formula_terms(self, formula_terms=None, at=None, mode='noerr'): """Read formula terms at T and W points and store them in the dictionary attribute :attr:`formula_terms` whose keys are 't' and 'w' """ # String from file formula_terms_from_file = {} for at_, levelvar in list(self.levelvars.items()): if at and at!=at_: continue formula_terms_from_file[at_] = getattr(levelvar, "formula_terms", {}) # Specified if not formula_terms: formula_terms = {} elif (isinstance(formula_terms, (str, list, tuple)) or (isinstance(formula_terms, dict) and 't' not in formula_terms and 'w' not in formula_terms)): formula_terms = {'t':formula_terms} # Scan formulas self.formula_terms = {} for at_ in 'wt': # Check position if at and at!=at_: continue # To dicts file_formula_terms = self._ft_to_dict_(formula_terms.get(at_, {})) spec_formula_terms = self._ft_to_dict_(formula_terms_from_file.get(at_, {})) # Merge self.formula_terms[at_] = dict_merge(spec_formula_terms, file_formula_terms) # Check if empty when required if at and not self.formula_terms[at_]: vcwarn('No formula term for {} position'.format(at_)) # Patch names for eta and depth into self.names for name in self.horiz_terms: if name in self.formula_terms[at_]: self.names[name] = self.formula_terms[at_][name] # Final check if (not self.formula_terms or not any([bool(ct) for ct in list(self.formula_terms.values())])): vcwarn('No formula term currently loaded')
def dupl_loc_specs(all_specs, fromname, toloc): """Duplicate the specification for a variable or an axis to another or several locations The following rules apply: - If the original specifications are from a name without a specific location (generic), new specs (located) are appended (merged) with original specs. - If the specifications at target location already exist, it merges new specs with old specs. - Generic specification are systematically created or updated by merging of specialized ones. :Example: >>> dupl_loc_specs(CF_VAR_SPECS, 'corio', 'u') # Create the 'corio_u' entry in CF_VAR_SPECS and update 'corio' >>> dupl_loc_specs(CF_VAR_SPECS, 'corio_t', 'u') # Create 'corio_u' and 'corio_t' """ if not fromname in all_specs: raise KeyError('No such entry in specifications: ' + fromname) single = not isinstance(toloc, (list, tuple)) if single: toloc = [toloc] tonames = [] tomerge = [] fromnoloc = no_loc_single(fromname, 'id') == fromname for loc in toloc: # New name (id) toname = change_loc_single(fromname, 'id', loc) tonames.append(toname) # New specs tospecs = change_loc_specs(loc, **all_specs[fromname]) # Add a version of standard_name and long_name for T loc without location spec if loc == 't': # 'toto_at_t_location' -> ['toto_at_t_location','toto'] for spname in 'standard_name', 'long_name': if spname not in tospecs: continue addspecs = change_loc_specs(None, **{spname: tospecs[spname]}) for dd in tospecs, addspecs: # to lists if not isinstance(dd[spname], list): dd[spname] = [dd[spname]] tospecs[spname].extend(addspecs[spname]) # For merging specs back with old specs if old has no location # if fromnoloc: # generic tomerge.append(tospecs) # Merge with old spec if existing if toname in all_specs: tospecs = dict_merge( tospecs, all_specs[toname], mergelists=True, cls=dict, mergedicts=True, ) # # Default location -> add its generic version ('_t' -> + '') # if loc==DEFAULT_LOCATION: # genspecs = change_loc_specs(None, **tospecs) # tospecs = dict_merge(tospecs, genspecs, mergelists=True) # Remove atlocs attribute if 'atlocs' in tospecs: tospecs.pop('atlocs') # Store it all_specs[toname] = tospecs # Make a generic entry that merges all specialized ones if fromnoloc: genspecs = all_specs[fromname] # existing generic specs else: genspecs = change_loc_specs( None, **all_specs[fromname]) # remove location info tomerge.insert(0, genspecs) genname = genspecs['id'][0] all_specs[genname] = dict_merge(*tomerge, **CF_DICT_MERGE_KWARGS) if single: return tonames[0] return tonames
def _check_entry_(self, name): """Validate an entry - Makes sure to have lists, except for 'axis' and 'inherit' - Check geo axes - Check inheritance - Makes sure that axes specs have no 'axes' key - Makes sure that specs key is the first entry of 'names' - add standard_name to list of names - Check duplication to other locations ('toto' -> 'toto_u') """ # Wrong entry! if name not in self: return # Entry already generated with the atlocs key if name in self._from_atlocs: return # Get the specs if hasattr(self._dict[name], 'dict'): self._dict[name] = self._dict[name].dict() specs = self._dict[name] # Ids if name in specs['id']: specs['id'].remove(name) specs['id'].insert(0, name) if name == 'mld': pass # Long name if not specs['long_name']: specs['long_name'].append(name.title().replace('_', ' ')) # Physloc must be the first atlocs if 'physloc' in specs and 'atlocs' in specs: p = specs['physloc'] if p: if p in specs['atlocs']: specs['atlocs'].remove(p) specs['atlocs'].insert(0, p) # Geo axes (variables only) if 'axes' in specs: specs['axes'].setdefault('t', ['time']) suffixes = [('_' + s) for s in 'rftuv'] specs['axes'].setdefault( 'y', [cp_suffix(name, 'lat', suffixes=suffixes)]) specs['axes'].setdefault( 'x', [cp_suffix(name, 'lon', suffixes=suffixes)]) for l, n in ('t', 'time'), ('y', 'lat'), ('x', 'lon'): if isinstance(specs['axes'][l], list) and n not in specs['axes'][l]: specs['axes'][l].append(n) # Inherits from other specs (merge specs with dict_merge) if name == 'mld': pass if specs['inherit']: from_name = specs['inherit'] from_specs = None to_scan = [] if self._inherit: to_scan.append(self._inherit) to_scan.append(self) for from_specs in to_scan: if from_name in from_specs: # Merge self._dict[name] = specs = dict_merge( specs, from_specs[from_name], cls=dict, **CF_DICT_MERGE_KWARGS) # Validate # if from_specs is not self: for key in specs.keys(): if key not in self._cfgspec: del specs[key] # break # Standard_names in ids if name == 'mld': pass if specs['standard_name']: for standard_name in specs['standard_name']: if standard_name not in specs['id']: specs['id'].append(standard_name) # Duplicate at other locations if specs['atlocs']: tonames = dupl_loc_specs(self._dict, name, specs['atlocs']) self._from_atlocs.extend(tonames) specs = self._dict[name]
def dupl_loc_specs(all_specs, fromname, toloc): """Duplicate the specification for a variable or an axis to another or several locations The following rules apply: - If the original specifications are from a name without a specific location (generic), new specs (located) are appended (merged) with original specs. - If the specifications at target location already exist, it merges new specs with old specs. - Generic specification are systematically created or updated by merging of specialized ones. :Example: >>> dupl_loc_specs(VAR_SPECS, 'corio', 'u') # Create the 'corio_u' entry in VAR_SPECS and update 'corio' >>> dupl_loc_specs(VAR_SPECS, 'corio_t', 'u') # Create 'corio_u' and 'corio_t' """ if not fromname in all_specs: raise KeyError('No such entry in specifications: '+fromname) single = not isinstance(toloc, (list, tuple)) if single: toloc = [toloc] tonames = [] tomerge = [] fromnoloc = no_loc_single(fromname, 'name')==fromname for loc in toloc: # New name (id) toname = change_loc_single(fromname, 'name', loc) tonames.append(toname) # New specs tospecs = change_loc_specs(loc, **all_specs[fromname]) # Add a version of standard_name and long_name for T loc without location spec if loc=='t': # 'toto_at_t_location' -> ['toto_at_t_location','toto'] for spname in 'standard_names', 'long_names': if spname not in tospecs: continue addspecs = change_loc_specs(None, **{spname:tospecs[spname]}) for dd in tospecs, addspecs: # to lists if not isinstance(dd[spname], list): dd[spname] = [dd[spname]] tospecs[spname].extend(addspecs[spname]) # For merging specs back with old specs if old has no location # if fromnoloc: # generic tomerge.append(tospecs) # Merge with old spec if existing if toname in all_specs: tospecs = dict_merge(tospecs, all_specs[toname], mergelists=True) # # Default location -> add its generic version ('_t' -> + '') # if loc==DEFAULT_LOCATION: # genspecs = change_loc_specs(None, **tospecs) # tospecs = dict_merge(tospecs, genspecs, mergelists=True) # Remove atlocs attribute if 'atlocs' in tospecs: tospecs.pop('atlocs') # Store it all_specs[toname] = tospecs # Make a generic entry that merges all specialized ones if fromnoloc: genspecs = all_specs[fromname] # existing generic specs else: genspecs = change_loc_specs(None, **all_specs[fromname]) # remove location info tomerge.insert(0, genspecs) kw = dict(mergelists=True) genname = genspecs['names'][0] all_specs[genname] = dict_merge(*tomerge, **kw) if single: return tonames[0] return tonames
# Inherits from other specs (merge specs with dict_merge) if 'inherit' in specs: objname = specs['inherit'] obj_specs = None if name==objname: # same name if all_specs is VAR_SPECS and objname in AXIS_SPECS: obj_specs = AXIS_SPECS elif all_specs is AXIS_SPECS and objname in VAR_SPECS: obj_specs = VAR_SPECS elif objname in VAR_SPECS: # check in VAR_SPECS first obj_specs = VAR_SPECS elif objname in AXIS_SPECS: # then in AXIS_SPECS obj_specs = AXIS_SPECS if obj_specs is not None: all_specs[name] = specs = dict_merge(specs, obj_specs[objname]) # No geo axes for axes! if all_specs is AXIS_SPECS and 'axes' in specs: del specs['axes'] # Key = first name (id) if name in specs['names']: specs['names'].remove(name) specs['names'].insert(0, name) # Standard_names in names if ('standard_names' in specs and specs['standard_names']): for standard_name in specs['standard_names']: if standard_name not in specs['names']: specs['names'].append(standard_name)