Skip to content

Commit 4c61916

Browse files
committed
[ModelicaSystem] update input handling for set*() functions
* use a Pythonic way for input: setParameters(a=123) param = {'a': 123} setParameters(**param) see input by SengerM in PR OpenModelica#326
1 parent 63139e9 commit 4c61916

File tree

2 files changed

+83
-54
lines changed

2 files changed

+83
-54
lines changed

OMPython/ModelicaSystem.py

Lines changed: 77 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,8 @@ def getSolutions(self, varList: Optional[str | list[str]] = None, resultfile: Op
12001200

12011201
@staticmethod
12021202
def _prepare_input_data(
1203-
raw_input: str | list[str] | dict[str, Any],
1203+
input_args: Any,
1204+
input_kwargs: dict[str, Any],
12041205
) -> dict[str, str]:
12051206
"""
12061207
Convert raw input to a structured dictionary {'key1': 'value1', 'key2': 'value2'}.
@@ -1218,38 +1219,42 @@ def prepare_str(str_in: str) -> dict[str, str]:
12181219

12191220
input_data: dict[str, str] = {}
12201221

1221-
if isinstance(raw_input, str):
1222-
warnings.warn(message="The definition of values to set should use a dictionary, "
1223-
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1224-
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1225-
category=DeprecationWarning,
1226-
stacklevel=3)
1227-
return prepare_str(raw_input)
1228-
1229-
if isinstance(raw_input, list):
1230-
warnings.warn(message="The definition of values to set should use a dictionary, "
1231-
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1232-
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1233-
category=DeprecationWarning,
1234-
stacklevel=3)
1235-
1236-
for item in raw_input:
1237-
input_data |= prepare_str(item)
1238-
1239-
return input_data
1240-
1241-
if isinstance(raw_input, dict):
1242-
for key, val in raw_input.items():
1243-
# convert all values to strings to align it on one type: dict[str, str]
1244-
# spaces have to be removed as setInput() could take list of tuples as input and spaces would
1245-
str_val = str(val).replace(' ', '')
1222+
for input_arg in input_args:
1223+
if isinstance(input_arg, str):
1224+
warnings.warn(message="The definition of values to set should use a dictionary, "
1225+
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1226+
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1227+
category=DeprecationWarning,
1228+
stacklevel=3)
1229+
input_data = input_data | prepare_str(input_arg)
1230+
elif isinstance(input_arg, list):
1231+
warnings.warn(message="The definition of values to set should use a dictionary, "
1232+
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1233+
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1234+
category=DeprecationWarning,
1235+
stacklevel=3)
1236+
1237+
for item in input_arg:
1238+
if not isinstance(item, str):
1239+
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(item)}!")
1240+
input_data = input_data | prepare_str(item)
1241+
else:
1242+
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(input_arg)}!")
1243+
1244+
if len(input_kwargs):
1245+
for key, val in input_kwargs.items():
1246+
# ensure all values are strings to align it on one type: dict[str, str]
1247+
if not isinstance(val, str):
1248+
# spaces have to be removed as setInput() could take list of tuples as input and spaces would
1249+
# result in an error on recreating the input data
1250+
str_val = str(val).replace(' ', '')
1251+
else:
1252+
str_val = val
12461253
if ' ' in key or ' ' in str_val:
12471254
raise ModelicaSystemError(f"Spaces not allowed in key/value pairs: {repr(key)} = {repr(val)}!")
12481255
input_data[key] = str_val
12491256

1250-
return input_data
1251-
1252-
raise ModelicaSystemError(f"Invalid type of input: {type(raw_input)}")
1257+
return input_data
12531258

12541259
def _set_method_helper(
12551260
self,
@@ -1281,8 +1286,7 @@ def _set_method_helper(
12811286

12821287
for key, val in inputdata.items():
12831288
if key not in classdata:
1284-
raise ModelicaSystemError("Unhandled case in setMethodHelper.apply_single() - "
1285-
f"{repr(key)} is not a {repr(datatype)} variable")
1289+
raise ModelicaSystemError(f"Invalid variable for type {repr(datatype)}: {repr(key)}")
12861290

12871291
if datatype == "parameter" and not self.isParameterChangeable(key):
12881292
raise ModelicaSystemError(f"It is not possible to set the parameter {repr(key)}. It seems to be "
@@ -1310,17 +1314,21 @@ def isParameterChangeable(
13101314

13111315
def setContinuous(
13121316
self,
1313-
cvals: str | list[str] | dict[str, Any],
1317+
*args: Any,
1318+
**kwargs: dict[str, Any],
13141319
) -> bool:
13151320
"""
13161321
This method is used to set continuous values. It can be called:
13171322
with a sequence of continuous name and assigning corresponding values as arguments as show in the example below:
13181323
usage
13191324
>>> setContinuous("Name=value") # depreciated
13201325
>>> setContinuous(["Name1=value1","Name2=value2"]) # depreciated
1321-
>>> setContinuous(cvals={"Name1": "value1", "Name2": "value2"})
1326+
1327+
>>> setContinuous(Name1="value1", Name2="value2")
1328+
>>> param = {"Name1": "value1", "Name2": "value2"}
1329+
>>> setContinuous(**param)
13221330
"""
1323-
inputdata = self._prepare_input_data(raw_input=cvals)
1331+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13241332

13251333
return self._set_method_helper(
13261334
inputdata=inputdata,
@@ -1330,17 +1338,21 @@ def setContinuous(
13301338

13311339
def setParameters(
13321340
self,
1333-
pvals: str | list[str] | dict[str, Any],
1341+
*args: Any,
1342+
**kwargs: dict[str, Any],
13341343
) -> bool:
13351344
"""
13361345
This method is used to set parameter values. It can be called:
13371346
with a sequence of parameter name and assigning corresponding value as arguments as show in the example below:
13381347
usage
13391348
>>> setParameters("Name=value") # depreciated
13401349
>>> setParameters(["Name1=value1","Name2=value2"]) # depreciated
1341-
>>> setParameters(pvals={"Name1": "value1", "Name2": "value2"})
1350+
1351+
>>> setParameters(Name1="value1", Name2="value2")
1352+
>>> param = {"Name1": "value1", "Name2": "value2"}
1353+
>>> setParameters(**param)
13421354
"""
1343-
inputdata = self._prepare_input_data(raw_input=pvals)
1355+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13441356

13451357
return self._set_method_helper(
13461358
inputdata=inputdata,
@@ -1350,17 +1362,21 @@ def setParameters(
13501362

13511363
def setSimulationOptions(
13521364
self,
1353-
simOptions: str | list[str] | dict[str, Any],
1365+
*args: Any,
1366+
**kwargs: dict[str, Any],
13541367
) -> bool:
13551368
"""
13561369
This method is used to set simulation options. It can be called:
13571370
with a sequence of simulation options name and assigning corresponding values as arguments as show in the example below:
13581371
usage
13591372
>>> setSimulationOptions("Name=value") # depreciated
13601373
>>> setSimulationOptions(["Name1=value1","Name2=value2"]) # depreciated
1361-
>>> setSimulationOptions(simOptions={"Name1": "value1", "Name2": "value2"})
1374+
1375+
>>> setSimulationOptions(Name1="value1", Name2="value2")
1376+
>>> param = {"Name1": "value1", "Name2": "value2"}
1377+
>>> setSimulationOptions(**param)
13621378
"""
1363-
inputdata = self._prepare_input_data(raw_input=simOptions)
1379+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13641380

13651381
return self._set_method_helper(
13661382
inputdata=inputdata,
@@ -1370,17 +1386,21 @@ def setSimulationOptions(
13701386

13711387
def setLinearizationOptions(
13721388
self,
1373-
linearizationOptions: str | list[str] | dict[str, Any],
1389+
*args: Any,
1390+
**kwargs: dict[str, Any],
13741391
) -> bool:
13751392
"""
13761393
This method is used to set linearization options. It can be called:
13771394
with a sequence of linearization options name and assigning corresponding value as arguments as show in the example below
13781395
usage
13791396
>>> setLinearizationOptions("Name=value") # depreciated
13801397
>>> setLinearizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1381-
>>> setLinearizationOptions(linearizationOtions={"Name1": "value1", "Name2": "value2"})
1398+
1399+
>>> setLinearizationOptions(Name1="value1", Name2="value2")
1400+
>>> param = {"Name1": "value1", "Name2": "value2"}
1401+
>>> setLinearizationOptions(**param)
13821402
"""
1383-
inputdata = self._prepare_input_data(raw_input=linearizationOptions)
1403+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13841404

13851405
return self._set_method_helper(
13861406
inputdata=inputdata,
@@ -1390,17 +1410,21 @@ def setLinearizationOptions(
13901410

13911411
def setOptimizationOptions(
13921412
self,
1393-
optimizationOptions: str | list[str] | dict[str, Any],
1413+
*args: Any,
1414+
**kwargs: dict[str, Any],
13941415
) -> bool:
13951416
"""
13961417
This method is used to set optimization options. It can be called:
13971418
with a sequence of optimization options name and assigning corresponding values as arguments as show in the example below:
13981419
usage
13991420
>>> setOptimizationOptions("Name=value") # depreciated
14001421
>>> setOptimizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1401-
>>> setOptimizationOptions(optimizationOptions={"Name1": "value1", "Name2": "value2"})
1422+
1423+
>>> setOptimizationOptions(Name1="value1", Name2="value2")
1424+
>>> param = {"Name1": "value1", "Name2": "value2"}
1425+
>>> setOptimizationOptions(**param)
14021426
"""
1403-
inputdata = self._prepare_input_data(raw_input=optimizationOptions)
1427+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
14041428

14051429
return self._set_method_helper(
14061430
inputdata=inputdata,
@@ -1410,7 +1434,8 @@ def setOptimizationOptions(
14101434

14111435
def setInputs(
14121436
self,
1413-
name: str | list[str] | dict[str, Any],
1437+
*args: Any,
1438+
**kwargs: dict[str, Any],
14141439
) -> bool:
14151440
"""
14161441
This method is used to set input values. It can be called with a sequence of input name and assigning
@@ -1420,9 +1445,12 @@ def setInputs(
14201445
14211446
>>> setInputs("Name=value") # depreciated
14221447
>>> setInputs(["Name1=value1","Name2=value2"]) # depreciated
1423-
>>> setInputs(name={"Name1": "value1", "Name2": "value2"})
1448+
1449+
>>> setInputs(Name1="value1", Name2="value2")
1450+
>>> param = {"Name1": "value1", "Name2": "value2"}
1451+
>>> setInputs(**param)
14241452
"""
1425-
inputdata = self._prepare_input_data(raw_input=name)
1453+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
14261454

14271455
for key, val in inputdata.items():
14281456
if key not in self._inputs:

tests/test_ModelicaSystem.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ def test_setParameters():
3434
model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/"
3535
mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall")
3636

37-
# method 1
38-
mod.setParameters(pvals={"e": 1.234})
39-
mod.setParameters(pvals={"g": 321.0})
37+
# method 1 (test depreciated variants)
38+
mod.setParameters("e=1.234")
39+
mod.setParameters(["g=321.0"])
4040
assert mod.getParameters("e") == ["1.234"]
4141
assert mod.getParameters("g") == ["321.0"]
4242
assert mod.getParameters() == {
@@ -46,8 +46,9 @@ def test_setParameters():
4646
with pytest.raises(KeyError):
4747
mod.getParameters("thisParameterDoesNotExist")
4848

49-
# method 2
50-
mod.setParameters(pvals={"e": 21.3, "g": 0.12})
49+
# method 2 (new style)
50+
pvals = {"e": 21.3, "g": 0.12}
51+
mod.setParameters(**pvals)
5152
assert mod.getParameters() == {
5253
"e": "21.3",
5354
"g": "0.12",

0 commit comments

Comments
 (0)