Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions mpas_analysis/configuration/MpasAnalysisConfigParser.py
Original file line number Diff line number Diff line change
@@ -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):

Expand Down Expand Up @@ -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(...)`.
Expand All @@ -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)):
Expand Down
19 changes: 17 additions & 2 deletions mpas_analysis/test/test_mpas_config_parser.py
Original file line number Diff line number Diff line change
@@ -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")
Expand Down Expand Up @@ -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
11 changes: 11 additions & 0 deletions mpas_analysis/test/test_mpas_config_parser/config.analysis
Original file line number Diff line number Diff line change
Expand Up @@ -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