Skip to content

Commit 7e33893

Browse files
committed
Handle the usage of Python keywords in MiniZinc
1 parent 3fbe220 commit 7e33893

4 files changed

Lines changed: 30 additions & 0 deletions

File tree

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Fixed
2020
usage of generated solver configurations on Windows.
2121
- The DZN parser now constructs correct range objects. The parser was off by one due to
2222
the exclusive upper bound in Python range objects.
23+
- Rewrite MiniZinc fields that are keywords in Python. These names cannot be used
24+
directly as members of a dataclass. Python keywords used in MiniZinc are rewritten to
25+
``"mzn_" + {keyword}`` and a warning is thrown.
2326

2427
0.2.2_ - 2020-02-17
2528
-------------------

src/minizinc/CLI/instance.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import re
1010
import sys
1111
import tempfile
12+
import warnings
1213
from dataclasses import field, make_dataclass
1314
from datetime import datetime, timedelta
1415
from enum import EnumMeta
16+
from keyword import iskeyword
1517
from numbers import Number
1618
from pathlib import Path
1719
from typing import Any, Dict, Iterator, List, Optional, Type, cast
@@ -207,6 +209,13 @@ def analyse(self):
207209
for k, v in self._output.items():
208210
if k in ["_output_item", "_checker"]:
209211
fields.append((k, str, field(default="")))
212+
elif iskeyword(k):
213+
warnings.warn(
214+
f"MiniZinc field '{k}' is a Python keyword. It has been "
215+
f"renamed to 'mzn_{k}'",
216+
SyntaxWarning,
217+
)
218+
fields.append(("mzn_" + k, v))
210219
else:
211220
fields.append((k, v))
212221

src/minizinc/result.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from dataclasses import dataclass
88
from datetime import timedelta
99
from enum import Enum, auto
10+
from keyword import kwlist
1011
from typing import Any, Dict, Optional, Tuple, Type, Union
1112

1213
from .instance import Method
@@ -336,6 +337,10 @@ def parse_solution(
336337
tmp["objective"] = tmp.pop("_objective")
337338
if "_output" in tmp:
338339
tmp["_output_item"] = tmp.pop("_output")
340+
for k in kwlist:
341+
if k in tmp:
342+
tmp["mzn_" + k] = tmp.pop(k)
343+
339344
solution = output_type(**tmp)
340345

341346
return solution, statistics

tests/test_instance.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ def test_reassign(self):
3030
self.instance["n"] = 15
3131

3232

33+
class TestPythonConflict(InstanceTestCase):
34+
code = """
35+
include "globals.mzn";
36+
var 1..2: return;
37+
constraint return > 1;
38+
"""
39+
40+
def test_rename(self):
41+
with pytest.warns(SyntaxWarning):
42+
result = self.instance.solve()
43+
assert result.solution.mzn_return == 2
44+
45+
3346
class TestBranch(InstanceTestCase):
3447
code = """
3548
include "globals.mzn";

0 commit comments

Comments
 (0)