Source code for isofit.configs.base_config

#! /usr/bin/env python3
#
#  Copyright 2018 California Institute of Technology
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
# ISOFIT: Imaging Spectrometer Optimal FITting
# Author: Philip G. Brodrick, philip.brodrick@jpl.nasa.gov

import logging
from collections import OrderedDict
from typing import Dict, List, Type

import numpy as np


[docs] class BaseConfigSection(object): """ Base Configuration Section from which all Configuration Sections inherit. Handles shared functionality like getting, setting, and cleaning configuration options. """ def __init__(self) -> None: return
[docs] def set_config_options(self, configdict: dict = None) -> None: """Read dictionary and assign to attributes, leaning on _set_callable_attributes Args: configdict: dictionary-style config for parsing """ for key in self._get_nontype_attributes(): keytype = getattr(self, "_" + key + "_type") if key in configdict and configdict[key] is not None: if callable(keytype): sub_config = keytype(configdict[key]) setattr(self, key, sub_config) else: setattr(self, key, configdict[key]) return
[docs] def check_config_validity(self) -> List[str]: errors = list() message_type = ( "Invalid type for config option {} in config section {}. The provided value" " {} is a {}, " + "but the required value should be a {}." ) # First check typing for key in self._get_nontype_attributes(): # get the actual parameter value value = getattr(self, key) # None assignments are fine if value is None: continue # check it against expected type_expected = self._get_expected_type_for_option_key(key) # Unknown types just skip if type_expected is None: continue # Lists are complicated, retype if isinstance(type_expected, List): type_expected = List if isinstance(value, type_expected): continue # At this point, we have a type mismatch, add to error list errors.append( message_type.format( key, self.__class__.__name__, value, type(value), type_expected ) ) errors.extend(self._check_config_validity()) # Now do a full check on each submodule for key in self._get_nontype_attributes(): value = getattr(self, key) if hasattr(value, "check_config_validity"): logging.debug(f"Configuration check of: {key}") errors.extend(value.check_config_validity()) return errors
[docs] def get_config_options_as_dict(self) -> Dict[str, Dict[str, any]]: config_options = OrderedDict() for key in self._get_nontype_attributes(): value = getattr(self, key) if type(value) is tuple: value = list( value ) # Lists look nicer in config files and seem friendlier config_options[key] = value return config_options
[docs] def get_config_as_dict(self): data = {} for key, val in self.__dict__.items(): if not key.startswith("_"): if issubclass(type(val), BaseConfigSection): data[key] = val.get_config_as_dict() else: data[key] = val return data
[docs] def _check_config_validity(self) -> List[str]: return list()
[docs] def _get_expected_type_for_option_key(self, option_key: str) -> type: key = f"_{option_key}_type" if hasattr(self, key): return getattr(self, key)
[docs] def _get_nontype_attributes(self) -> List[str]: keys = [] for key in self.__dict__.keys(): if key[0] == "_": continue keys.append(key) return keys
[docs] def _get_type_attributes(self) -> List[str]: keys = [] for key in self.__dict__.keys(): if key[0] == "_" and key[-5:] == "_type": keys.append(key) return keys
[docs] def _get_hidden_attributes(self) -> List[str]: keys = [] for key in self.__dict__.keys(): if key[0] == "_" and key[-5:] != "_type": keys.append(key) return keys
[docs] def get_all_elements(self): return [getattr(self, x) for x in self._get_nontype_attributes()]
[docs] def get_all_element_names(self): return self._get_nontype_attributes()
[docs] def get_elements(self): elements = self.get_all_elements() element_names = self._get_nontype_attributes() valid = [x is not None for x in elements] elements = [elements[x] for x in range(len(elements)) if valid[x]] element_names = [ element_names[x] for x in range(len(element_names)) if valid[x] ] order = np.argsort(element_names) elements = [elements[idx] for idx in order] element_names = [element_names[idx] for idx in order] return elements, element_names
[docs] def get_element_names(self): elements, element_names = self.get_elements() return element_names
[docs] def get_single_element_by_name(self, name): elements, element_names = self.get_elements() return elements[element_names.index(name)]