diff --git a/mpas_analysis/configuration/MpasAnalysisConfigParser.py b/mpas_analysis/configuration/MpasAnalysisConfigParser.py index fe1cd7ddf..63c2dad98 100644 --- a/mpas_analysis/configuration/MpasAnalysisConfigParser.py +++ b/mpas_analysis/configuration/MpasAnalysisConfigParser.py @@ -1,18 +1,20 @@ -import numbers -import ast - """ 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)`). -Author: Xylar Asay-Davis -Last Modified: 12/07/2016 +Author: Xylar Asay-Davis, Phillip J. Wolfram +Last Modified: 01/31/2017 """ +import numbers +import ast +import numpy as np from ConfigParser import ConfigParser +npallow = dict(linspace=np.linspace, xrange=xrange, range=range, arange=np.arange, + pi=np.pi, Pi=np.pi, __builtins__=None) class MpasAnalysisConfigParser(ConfigParser): @@ -44,7 +46,7 @@ def getWithDefault(self, section, option, default): self.set(section, option, str(default)) return default - def getExpression(self, section, option, elementType=None): + def getExpression(self, section, option, elementType=None, usenumpyfunc=False): """ Get an option as an expression (typically a list, though tuples and dicts should also work). `section` and `option` work as in `get(...)`. @@ -56,11 +58,18 @@ def getExpression(self, section, option, elementType=None): useful for ensuring that all elements in a list of numbers are of type float, rather than int, when the distinction is important. - Author: Xylar Asay-Davis - Last Modified: 12/0y/2016 + If `usenumpyfunc` is True, expression is evaluated within the context of + having selected numpy and / or np functionality available. + + Author: Xylar Asay-Davis, Phillip J. Wolfram + Last Modified: 01/31/2017 """ expressionString = self.get(section, option) - result = ast.literal_eval(expressionString) + if usenumpyfunc: + sanitizedstr = expressionString.replace('np.', '').replace('numpy.','') + result = eval(sanitizedstr, npallow) + else: + result = ast.literal_eval(expressionString) if elementType is not None: if isinstance(result, (list, tuple)): diff --git a/mpas_analysis/test/test_mpas_config_parser.py b/mpas_analysis/test/test_mpas_config_parser.py index 4cb09cb1c..0365dbdeb 100644 --- a/mpas_analysis/test/test_mpas_config_parser.py +++ b/mpas_analysis/test/test_mpas_config_parser.py @@ -1,14 +1,15 @@ """ Unit test infrastructure for MpasAnalysisConfigParser -Xylar Asay-Davis -12/05/2016 +Xylar Asay-Davis, Phillip J. Wolfram +01/31/2017 """ import pytest from mpas_analysis.test import TestCase, loaddatadir from mpas_analysis.configuration.MpasAnalysisConfigParser \ import MpasAnalysisConfigParser +from . import requires_numpy @pytest.mark.usefixtures("loaddatadir") @@ -64,5 +65,19 @@ def test_read_config(self): 'key2': -12, 'key3': False}) + @requires_numpy + def test_read_config_numpy(self): + self.setup_config() + + # tests numpy evaluation capability + import numpy as np + for testname in ['testNumpyarange' + str(ii) for ii in np.arange(3)]: + self.assertArrayEqual(self.config.getExpression('TestNumpy', testname, usenumpyfunc=True), + np.arange(0, 1, 10)) + for testname in ['testNumpylinspace' + str(ii) for ii in np.arange(3)]: + self.assertArrayEqual(self.config.getExpression('TestNumpy', testname, usenumpyfunc=True), + np.linspace(0, 1, 10)) + for testNumpy in ['testNumpypi' + str(ii) for ii in np.arange(3)] + ['testNumpyPi']: + self.assertEqual(self.config.getExpression('TestNumpy', testNumpy, usenumpyfunc=True), np.pi) # vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/mpas_analysis/test/test_mpas_config_parser/config.analysis b/mpas_analysis/test/test_mpas_config_parser/config.analysis index 18071dae5..2fd5ed0cb 100644 --- a/mpas_analysis/test/test_mpas_config_parser/config.analysis +++ b/mpas_analysis/test/test_mpas_config_parser/config.analysis @@ -32,3 +32,14 @@ testDict = {'key1': 'string', 'key2': -12, 'key3': False} +[TestNumpy] +testNumpyarange0 = arange(0, 1, 10) +testNumpyarange1 = np.arange(0, 1, 10) +testNumpyarange2 = numpy.arange(0, 1, 10) +testNumpylinspace0 = linspace(0, 1, 10) +testNumpylinspace1 = np.linspace(0, 1, 10) +testNumpylinspace2 = numpy.linspace(0, 1, 10) +testNumpypi0 = pi +testNumpypi1 = np.pi +testNumpypi2 = numpy.pi +testNumpyPi = Pi