Skip to content

Commit 9e48ba5

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 abcae09 commit 9e48ba5

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
@@ -1115,7 +1115,8 @@ def getSolutions(self, varList: Optional[str | list[str]] = None, resultfile: Op
11151115

11161116
@staticmethod
11171117
def _prepare_input_data(
1118-
raw_input: str | list[str] | dict[str, Any],
1118+
input_args: Any,
1119+
input_kwargs: dict[str, Any],
11191120
) -> dict[str, str]:
11201121
"""
11211122
Convert raw input to a structured dictionary {'key1': 'value1', 'key2': 'value2'}.
@@ -1133,38 +1134,42 @@ def prepare_str(str_in: str) -> dict[str, str]:
11331134

11341135
input_data: dict[str, str] = {}
11351136

1136-
if isinstance(raw_input, str):
1137-
warnings.warn(message="The definition of values to set should use a dictionary, "
1138-
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1139-
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1140-
category=DeprecationWarning,
1141-
stacklevel=3)
1142-
return prepare_str(raw_input)
1143-
1144-
if isinstance(raw_input, list):
1145-
warnings.warn(message="The definition of values to set should use a dictionary, "
1146-
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1147-
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1148-
category=DeprecationWarning,
1149-
stacklevel=3)
1150-
1151-
for item in raw_input:
1152-
input_data |= prepare_str(item)
1153-
1154-
return input_data
1155-
1156-
if isinstance(raw_input, dict):
1157-
for key, val in raw_input.items():
1158-
# convert all values to strings to align it on one type: dict[str, str]
1159-
# spaces have to be removed as setInput() could take list of tuples as input and spaces would
1160-
str_val = str(val).replace(' ', '')
1137+
for input_arg in input_args:
1138+
if isinstance(input_arg, str):
1139+
warnings.warn(message="The definition of values to set should use a dictionary, "
1140+
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1141+
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1142+
category=DeprecationWarning,
1143+
stacklevel=3)
1144+
input_data = input_data | prepare_str(input_arg)
1145+
elif isinstance(input_arg, list):
1146+
warnings.warn(message="The definition of values to set should use a dictionary, "
1147+
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
1148+
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
1149+
category=DeprecationWarning,
1150+
stacklevel=3)
1151+
1152+
for item in input_arg:
1153+
if not isinstance(item, str):
1154+
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(item)}!")
1155+
input_data = input_data | prepare_str(item)
1156+
else:
1157+
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(input_arg)}!")
1158+
1159+
if len(input_kwargs):
1160+
for key, val in input_kwargs.items():
1161+
# ensure all values are strings to align it on one type: dict[str, str]
1162+
if not isinstance(val, str):
1163+
# spaces have to be removed as setInput() could take list of tuples as input and spaces would
1164+
# result in an error on recreating the input data
1165+
str_val = str(val).replace(' ', '')
1166+
else:
1167+
str_val = val
11611168
if ' ' in key or ' ' in str_val:
11621169
raise ModelicaSystemError(f"Spaces not allowed in key/value pairs: {repr(key)} = {repr(val)}!")
11631170
input_data[key] = str_val
11641171

1165-
return input_data
1166-
1167-
raise ModelicaSystemError(f"Invalid type of input: {type(raw_input)}")
1172+
return input_data
11681173

11691174
def _set_method_helper(
11701175
self,
@@ -1196,8 +1201,7 @@ def _set_method_helper(
11961201

11971202
for key, val in inputdata.items():
11981203
if key not in classdata:
1199-
raise ModelicaSystemError("Unhandled case in setMethodHelper.apply_single() - "
1200-
f"{repr(key)} is not a {repr(datatype)} variable")
1204+
raise ModelicaSystemError(f"Invalid variable for type {repr(datatype)}: {repr(key)}")
12011205

12021206
if datatype == "parameter" and not self.isParameterChangeable(key):
12031207
raise ModelicaSystemError(f"It is not possible to set the parameter {repr(key)}. It seems to be "
@@ -1225,17 +1229,21 @@ def isParameterChangeable(
12251229

12261230
def setContinuous(
12271231
self,
1228-
cvals: str | list[str] | dict[str, Any],
1232+
*args: Any,
1233+
**kwargs: dict[str, Any],
12291234
) -> bool:
12301235
"""
12311236
This method is used to set continuous values. It can be called:
12321237
with a sequence of continuous name and assigning corresponding values as arguments as show in the example below:
12331238
usage
12341239
>>> setContinuous("Name=value") # depreciated
12351240
>>> setContinuous(["Name1=value1","Name2=value2"]) # depreciated
1236-
>>> setContinuous(cvals={"Name1": "value1", "Name2": "value2"})
1241+
1242+
>>> setContinuous(Name1="value1", Name2="value2")
1243+
>>> param = {"Name1": "value1", "Name2": "value2"}
1244+
>>> setContinuous(**param)
12371245
"""
1238-
inputdata = self._prepare_input_data(raw_input=cvals)
1246+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
12391247

12401248
return self._set_method_helper(
12411249
inputdata=inputdata,
@@ -1245,17 +1253,21 @@ def setContinuous(
12451253

12461254
def setParameters(
12471255
self,
1248-
pvals: str | list[str] | dict[str, Any],
1256+
*args: Any,
1257+
**kwargs: dict[str, Any],
12491258
) -> bool:
12501259
"""
12511260
This method is used to set parameter values. It can be called:
12521261
with a sequence of parameter name and assigning corresponding value as arguments as show in the example below:
12531262
usage
12541263
>>> setParameters("Name=value") # depreciated
12551264
>>> setParameters(["Name1=value1","Name2=value2"]) # depreciated
1256-
>>> setParameters(pvals={"Name1": "value1", "Name2": "value2"})
1265+
1266+
>>> setParameters(Name1="value1", Name2="value2")
1267+
>>> param = {"Name1": "value1", "Name2": "value2"}
1268+
>>> setParameters(**param)
12571269
"""
1258-
inputdata = self._prepare_input_data(raw_input=pvals)
1270+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
12591271

12601272
return self._set_method_helper(
12611273
inputdata=inputdata,
@@ -1265,17 +1277,21 @@ def setParameters(
12651277

12661278
def setSimulationOptions(
12671279
self,
1268-
simOptions: str | list[str] | dict[str, Any],
1280+
*args: Any,
1281+
**kwargs: dict[str, Any],
12691282
) -> bool:
12701283
"""
12711284
This method is used to set simulation options. It can be called:
12721285
with a sequence of simulation options name and assigning corresponding values as arguments as show in the example below:
12731286
usage
12741287
>>> setSimulationOptions("Name=value") # depreciated
12751288
>>> setSimulationOptions(["Name1=value1","Name2=value2"]) # depreciated
1276-
>>> setSimulationOptions(simOptions={"Name1": "value1", "Name2": "value2"})
1289+
1290+
>>> setSimulationOptions(Name1="value1", Name2="value2")
1291+
>>> param = {"Name1": "value1", "Name2": "value2"}
1292+
>>> setSimulationOptions(**param)
12771293
"""
1278-
inputdata = self._prepare_input_data(raw_input=simOptions)
1294+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
12791295

12801296
return self._set_method_helper(
12811297
inputdata=inputdata,
@@ -1285,17 +1301,21 @@ def setSimulationOptions(
12851301

12861302
def setLinearizationOptions(
12871303
self,
1288-
linearizationOptions: str | list[str] | dict[str, Any],
1304+
*args: Any,
1305+
**kwargs: dict[str, Any],
12891306
) -> bool:
12901307
"""
12911308
This method is used to set linearization options. It can be called:
12921309
with a sequence of linearization options name and assigning corresponding value as arguments as show in the example below
12931310
usage
12941311
>>> setLinearizationOptions("Name=value") # depreciated
12951312
>>> setLinearizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1296-
>>> setLinearizationOptions(linearizationOtions={"Name1": "value1", "Name2": "value2"})
1313+
1314+
>>> setLinearizationOptions(Name1="value1", Name2="value2")
1315+
>>> param = {"Name1": "value1", "Name2": "value2"}
1316+
>>> setLinearizationOptions(**param)
12971317
"""
1298-
inputdata = self._prepare_input_data(raw_input=linearizationOptions)
1318+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
12991319

13001320
return self._set_method_helper(
13011321
inputdata=inputdata,
@@ -1305,17 +1325,21 @@ def setLinearizationOptions(
13051325

13061326
def setOptimizationOptions(
13071327
self,
1308-
optimizationOptions: str | list[str] | dict[str, Any],
1328+
*args: Any,
1329+
**kwargs: dict[str, Any],
13091330
) -> bool:
13101331
"""
13111332
This method is used to set optimization options. It can be called:
13121333
with a sequence of optimization options name and assigning corresponding values as arguments as show in the example below:
13131334
usage
13141335
>>> setOptimizationOptions("Name=value") # depreciated
13151336
>>> setOptimizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1316-
>>> setOptimizationOptions(optimizationOptions={"Name1": "value1", "Name2": "value2"})
1337+
1338+
>>> setOptimizationOptions(Name1="value1", Name2="value2")
1339+
>>> param = {"Name1": "value1", "Name2": "value2"}
1340+
>>> setOptimizationOptions(**param)
13171341
"""
1318-
inputdata = self._prepare_input_data(raw_input=optimizationOptions)
1342+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13191343

13201344
return self._set_method_helper(
13211345
inputdata=inputdata,
@@ -1325,7 +1349,8 @@ def setOptimizationOptions(
13251349

13261350
def setInputs(
13271351
self,
1328-
name: str | list[str] | dict[str, Any],
1352+
*args: Any,
1353+
**kwargs: dict[str, Any],
13291354
) -> bool:
13301355
"""
13311356
This method is used to set input values. It can be called with a sequence of input name and assigning
@@ -1335,9 +1360,12 @@ def setInputs(
13351360
13361361
>>> setInputs("Name=value") # depreciated
13371362
>>> setInputs(["Name1=value1","Name2=value2"]) # depreciated
1338-
>>> setInputs(name={"Name1": "value1", "Name2": "value2"})
1363+
1364+
>>> setInputs(Name1="value1", Name2="value2")
1365+
>>> param = {"Name1": "value1", "Name2": "value2"}
1366+
>>> setInputs(**param)
13391367
"""
1340-
inputdata = self._prepare_input_data(raw_input=name)
1368+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13411369

13421370
for key, val in inputdata.items():
13431371
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)