Commit eab9c087 authored by Martin Claus's avatar Martin Claus
Browse files

Merge branch '6-fix-index-assignment' into 'develop'

Resolve "Fix index assignment"

Closes #6

See merge request !8
parents 8b94fbba 7aa86d68
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,3 +4,4 @@ dist
namelist.egg-info
*.pyc
.coverage
.cache
+21 −0
Original line number Diff line number Diff line
from context import namelist

in_file_ref = "namelist_ref"
in_file_cfg = "namelist_cfg"

with open(in_file_ref) as f:
    ref_nmls = namelist.parse_namelist_file(f)

with open(in_file_cfg) as f:
    cfg_nmls = namelist.parse_namelist_file(f)

nmls = ref_nmls.copy()

for k in cfg_nmls:
    if k in nmls:
        nmls[k].update(cfg_nmls[k])
    else:
        nmls[k] = cfg_nmls[k]

for nml in nmls:
    print(str(nmls[nml]))
+48 −11
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ valueBool = re.compile(r"(\.(true|false|t|f)\.)", re.I)
quote = re.compile(r"([\']{1}[^\']*[\']{1}|[\"]{1}[^\"]*[\"]{1})",
                   re.MULTILINE)
namelistname = re.compile(r"&(" + varname + r")")
paramname = re.compile(r"^(" + varname + r")")
paramname = re.compile(r"^(" + varname + r")" + r"(\(([0-9]*)\))?" + r"$")
namlistend = re.compile(r'^(&(end)?|/)$', re.I)
comment = re.compile(r"!.*$", re.MULTILINE)
equalsign = re.compile(r"^=$")
@@ -62,8 +62,13 @@ class Namelist(DictClass):
        """
        retstr = "&%s\n" % str(self.name)
        for k, v in self.items():
            if hasattr(v, '__iter__'):
                retstr += "%s = (/ " % k
            if hasattr(v, 'islower'):  # is a string
                retstr += "{} = {}\n".format(k, repr(v))
            elif hasattr(v, 'items'):  # is a dictionary
                for i, ival in v.items():
                    retstr += "{}({}) = {}\n".format(k, i, repr(ival))
            elif hasattr(v, 'index'):  # is an array
                retstr += "{} = (/ ".format(k)
                tmpstr = ""
                for vv in v:
                    if isinstance(vv, bool):
@@ -151,53 +156,85 @@ def parse_namelist_string(in_string):
    """
    retlist = []
    content = _tokenize(in_string)
    index = 0
    for item in content:

        match = re.match(namelistname, item)
        if match:
            nmlname = match.group(1)
            nml = Namelist(nmlname)
            retlist.append(nml)
            continue

        match = re.match(paramname, item)
        if match:
            pname = match.group(1)
            index = match.group(3)
            try:  # index assignment
                index = int(index)
                if pname not in nml:
                    nml[pname] = DictClass()
            except TypeError:  # index is None
                nml[pname] = []
            continue
            continue  # pragma no cover

        if re.match(namlistend, item):
            continue

        if re.match(equalsign, item):
            continue

        match = re.match(valueBool, item)
        if match:
            nml[pname].append(match.group(1)[1].lower() == "t")
            _add_value(nml[pname], match.group(1)[1].lower() == "t", index)
            continue

        match = re.match(quote, item)
        if match:
            nml[pname].append(match.group(1)[1:-1])
            _add_value(nml[pname], match.group(1)[1:-1], index)
            continue

        try:
            nml[pname].append(int(item))
            i = int(item)
            _add_value(nml[pname], i, index)
        except ValueError:
            pass
        else:
            continue  # pragma: no cover

        try:
            nml[pname].append(float(item))
            f = float(item)
            _add_value(nml[pname], f, index)
        except ValueError:
            pass
        else:
            continue  # pragma: no cover

        match = re.match(computation, item)
        if match:
            nml[pname].append(eval(item))
            _add_value(nml[pname], eval(item), index)

    for nml in retlist:
        for k, v in nml.items():
            if len(v) == 1:
                try:
                    nml[k] = v[0]
                except KeyError:
                    pass

    ret_dict = DictClass(zip([nml.name for nml in retlist], retlist))
    return ret_dict


def _add_value(container, value, key):
    try:
        # test if container is a dict like object
        container.keys()
        container[key] = value
    except AttributeError:  # container is a list
        container.append(value)


def _tokenize(text):
    """Extract syntax tokens."""
    fs = "$$$FS$$$"
+68 −1
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ def test_parse_file(string):
     "&nml\nval1 = .FALSE.\n/\n",
     "&nml\nval1 = (/ 1,2,3,4,5,6 /)\n/\n",
     "&nml\nval1 = (/ .TRUE.,.FALSE.,.TRUE.,.TRUE. /)\n/\n",
     "&nml\nval1 = 3\nval2 = 5\n/\n",
     ]
)
def test_string_out(string):
@@ -189,6 +190,7 @@ def test_var_bool(string, val):
)
def test_var_string(string, val):
    nml = namelist.parse_namelist_string(string)["nml"]
    print(str(nml))
    assert nml["val"] == val


@@ -215,6 +217,71 @@ def test_var_array(string, arr):
        assert type(a) == type(b)


@pytest.mark.parametrize("string", ["&nml {} /", "&nml {} val2=34 /"])
@pytest.mark.parametrize("val1", ["lala", "((1 + 2) + 3)", 3, 3.0, 3e6, ".T."])
@pytest.mark.parametrize("d", [{1: None, 2: 35},{1: None}])
def test_index_assignment(string, val1, d):
    val_str = ""
    try:
        int(eval(val1))
        is_expression = True
    except:
        is_expression = False
    is_bool = (val1 == ".T.")
    d[1] = val1
    for k, v in d.items():
        if is_expression | is_bool:
            val_str += "val({}) = {} ".format(k, v)
        else:
            val_str += "val({}) = {} ".format(k, repr(v))
    if is_expression:
        d[1] = eval(d[1])
    if is_bool:
        d[1] = (val1 == ".T.")
    nml_string = string.format(val_str)
    nml = namelist.parse_namelist_string(nml_string)["nml"]
    print(nml_string)
    print (repr(nml), d)
    assert nml["val"] == d


@pytest.mark.parametrize("string", ["&nml\n{}/\n", "&nml\n{}val2 = 34\n/\n"])
@pytest.mark.parametrize(
    "val1",
    ["some_string", "((1 + 2) + 3)", 3, 3.0, 3e6, ".T."]
)
@pytest.mark.parametrize("d", [{1: None, 2: 35}, {1: None}])
def test_index_assignment_to_str(string, d, val1):
    try:
        int(eval(val1))
        is_expression = True
    except (NameError, SyntaxError, TypeError):
        is_expression = False
    is_bool = (val1 == ".T.")
    d[1] = val1
    val_str = ""
    for k, v in d.items():
        if is_expression | is_bool:
            val_str += "val({}) = {}\n".format(k, v)
        else:
            val_str += "val({}) = {}\n".format(k, repr(v))
    nml_string = string.format(val_str)
    nml = namelist.parse_namelist_string(nml_string)["nml"]

    if is_expression:
        d[1] = eval(d[1])
    if is_bool:
        d[1] = (val1 == ".T.")
    valid_String = ""
    for k, v in d.items():
        valid_String += "val({}) = {}\n".format(k, repr(v))
    valid_String = string.format(valid_String)

    print(valid_String, nml_string, str(nml))
    print(is_expression, is_bool)
    assert valid_String == str(nml)


@pytest.mark.parametrize("string", ["&nml val= {}, val2='lsl'/"])
@pytest.mark.parametrize("op", ["+", "-", "/", "*", "**"])
@pytest.mark.parametrize(