Source code for mpas_analysis.configuration.mpas_analysis_config_parser

# This software is open source software available under the BSD-3 license.
#
# Copyright (c) 2020 Triad National Security, LLC. All rights reserved.
# Copyright (c) 2020 Lawrence Livermore National Security, LLC. All rights
# reserved.
# Copyright (c) 2020 UT-Battelle, LLC. All rights reserved.
#
# Additional copyright and license information can be found in the LICENSE file
# distributed with this code, or at
# https://raw.githubusercontent.com/MPAS-Dev/MPAS-Analysis/master/LICENSE
"""
A configuratin parser class for MPAS analysis.  MpasAnalysisConfigParser adds
the capabilities to get an option including a default value
(``getWithDefault(section, option, default, ...)``) and to get options
that are lists, tuples, dicts, etc (``getExpression(section, option)``).
"""
# Authors
# -------
# Xylar Asay-Davis, Phillip J. Wolfram

from __future__ import absolute_import, division, print_function, \
    unicode_literals

import numbers
import ast
import six
import numpy as np

from six.moves.configparser import ConfigParser

if six.PY3:
    xrange = range

npallow = dict(linspace=np.linspace, xrange=xrange, range=range, array=np.array,
               arange=np.arange, pi=np.pi, Pi=np.pi, int=int, __builtins__=None)


class MpasAnalysisConfigParser(ConfigParser):

[docs] def getWithDefault(self, section, option, default): """ Get an option, using the supplied default value if the option is not present. Parameters ---------- section : str The section in the config file option : str The option in the config file default : {bool, int, float, list, tuple, dict, str} The default value if the option and/or section is not found, used to determine the type of the option if it *is* found. If ``default`` is a list, tuple, or dict, ``getExpression(...)`` is used if the option is present in the config file. """ # Authors # ------- # Xylar Asay-Davis if self.has_section(section): if self.has_option(section, option): if isinstance(default, bool): return self.getboolean(section, option) elif isinstance(default, numbers.Integral): return self.getint(section, option) elif isinstance(default, numbers.Real): return self.getfloat(section, option) elif isinstance(default, (list, tuple, dict)): return self.getExpression(section, option) else: return self.get(section, option) # we didn't find the entry so set it to the default if not self.has_section(section): self.add_section(section) self.set(section, option, str(default)) return default
[docs] def getExpression(self, section, option, elementType=None, usenumpyfunc=False): """ Get an option as an expression (typically a list, though tuples and dicts are also available). The expression is required to have valid python syntax, so that string entries are required to be in single or double quotes. Parameters ---------- section : str The section in the config file option : str The option in the config file elementType : {bool, int, float, list, tuple, str}, optional If supplied, each element in a list or tuple, or each value in a dictionary are cast to this type. This is likely most useful for ensuring that all elements in a list of numbers are of type float, rather than int, when the distinction is important. usenumpyfunc : bool, optional If ``True``, the expression is evaluated including functionality from the numpy package (which can be referenced either as ``numpy`` or ``np``). """ # Authors # ------- # Xylar Asay-Davis, Phillip J. Wolfram expressionString = self.get(section, option) if usenumpyfunc: assert '__' not in expressionString, \ "'__' is not allowed in {} "\ "for `usenumpyfunc=True`".format(expressionString) sanitizedstr = expressionString.replace('np.', '')\ .replace('numpy.', '')\ .replace('__', '') result = eval(sanitizedstr, npallow) else: result = ast.literal_eval(expressionString) if elementType is not None: if isinstance(result, (list, tuple)): result = [elementType(element) for element in result] elif isinstance(result, dict): for key in result: result[key] = elementType(result[key]) return result