Skip to content

Commit e86154c

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 #326
1 parent 0d5d002 commit e86154c

2 files changed

Lines changed: 83 additions & 54 deletions

File tree

OMPython/ModelicaSystem.py

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

11981198
@staticmethod
11991199
def _prepare_input_data(
1200-
raw_input: str | list[str] | dict[str, Any],
1200+
input_args: Any,
1201+
input_kwargs: dict[str, Any],
12011202
) -> dict[str, str]:
12021203
"""
12031204
Convert raw input to a structured dictionary {'key1': 'value1', 'key2': 'value2'}.
@@ -1215,38 +1216,42 @@ def prepare_str(str_in: str) -> dict[str, str]:
12151216

12161217
input_data: dict[str, str] = {}
12171218

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

1247-
return input_data
1248-
1249-
raise ModelicaSystemError(f"Invalid type of input: {type(raw_input)}")
1254+
return input_data
12501255

12511256
def _set_method_helper(
12521257
self,
@@ -1278,8 +1283,7 @@ def _set_method_helper(
12781283

12791284
for key, val in inputdata.items():
12801285
if key not in classdata:
1281-
raise ModelicaSystemError("Unhandled case in setMethodHelper.apply_single() - "
1282-
f"{repr(key)} is not a {repr(datatype)} variable")
1286+
raise ModelicaSystemError(f"Invalid variable for type {repr(datatype)}: {repr(key)}")
12831287

12841288
if datatype == "parameter" and not self.isParameterChangeable(key):
12851289
raise ModelicaSystemError(f"It is not possible to set the parameter {repr(key)}. It seems to be "
@@ -1307,17 +1311,21 @@ def isParameterChangeable(
13071311

13081312
def setContinuous(
13091313
self,
1310-
cvals: str | list[str] | dict[str, Any],
1314+
*args: Any,
1315+
**kwargs: dict[str, Any],
13111316
) -> bool:
13121317
"""
13131318
This method is used to set continuous values. It can be called:
13141319
with a sequence of continuous name and assigning corresponding values as arguments as show in the example below:
13151320
usage
13161321
>>> setContinuous("Name=value") # depreciated
13171322
>>> setContinuous(["Name1=value1","Name2=value2"]) # depreciated
1318-
>>> setContinuous(cvals={"Name1": "value1", "Name2": "value2"})
1323+
1324+
>>> setContinuous(Name1="value1", Name2="value2")
1325+
>>> param = {"Name1": "value1", "Name2": "value2"}
1326+
>>> setContinuous(**param)
13191327
"""
1320-
inputdata = self._prepare_input_data(raw_input=cvals)
1328+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13211329

13221330
return self._set_method_helper(
13231331
inputdata=inputdata,
@@ -1327,17 +1335,21 @@ def setContinuous(
13271335

13281336
def setParameters(
13291337
self,
1330-
pvals: str | list[str] | dict[str, Any],
1338+
*args: Any,
1339+
**kwargs: dict[str, Any],
13311340
) -> bool:
13321341
"""
13331342
This method is used to set parameter values. It can be called:
13341343
with a sequence of parameter name and assigning corresponding value as arguments as show in the example below:
13351344
usage
13361345
>>> setParameters("Name=value") # depreciated
13371346
>>> setParameters(["Name1=value1","Name2=value2"]) # depreciated
1338-
>>> setParameters(pvals={"Name1": "value1", "Name2": "value2"})
1347+
1348+
>>> setParameters(Name1="value1", Name2="value2")
1349+
>>> param = {"Name1": "value1", "Name2": "value2"}
1350+
>>> setParameters(**param)
13391351
"""
1340-
inputdata = self._prepare_input_data(raw_input=pvals)
1352+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13411353

13421354
return self._set_method_helper(
13431355
inputdata=inputdata,
@@ -1347,17 +1359,21 @@ def setParameters(
13471359

13481360
def setSimulationOptions(
13491361
self,
1350-
simOptions: str | list[str] | dict[str, Any],
1362+
*args: Any,
1363+
**kwargs: dict[str, Any],
13511364
) -> bool:
13521365
"""
13531366
This method is used to set simulation options. It can be called:
13541367
with a sequence of simulation options name and assigning corresponding values as arguments as show in the example below:
13551368
usage
13561369
>>> setSimulationOptions("Name=value") # depreciated
13571370
>>> setSimulationOptions(["Name1=value1","Name2=value2"]) # depreciated
1358-
>>> setSimulationOptions(simOptions={"Name1": "value1", "Name2": "value2"})
1371+
1372+
>>> setSimulationOptions(Name1="value1", Name2="value2")
1373+
>>> param = {"Name1": "value1", "Name2": "value2"}
1374+
>>> setSimulationOptions(**param)
13591375
"""
1360-
inputdata = self._prepare_input_data(raw_input=simOptions)
1376+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13611377

13621378
return self._set_method_helper(
13631379
inputdata=inputdata,
@@ -1367,17 +1383,21 @@ def setSimulationOptions(
13671383

13681384
def setLinearizationOptions(
13691385
self,
1370-
linearizationOptions: str | list[str] | dict[str, Any],
1386+
*args: Any,
1387+
**kwargs: dict[str, Any],
13711388
) -> bool:
13721389
"""
13731390
This method is used to set linearization options. It can be called:
13741391
with a sequence of linearization options name and assigning corresponding value as arguments as show in the example below
13751392
usage
13761393
>>> setLinearizationOptions("Name=value") # depreciated
13771394
>>> setLinearizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1378-
>>> setLinearizationOptions(linearizationOtions={"Name1": "value1", "Name2": "value2"})
1395+
1396+
>>> setLinearizationOptions(Name1="value1", Name2="value2")
1397+
>>> param = {"Name1": "value1", "Name2": "value2"}
1398+
>>> setLinearizationOptions(**param)
13791399
"""
1380-
inputdata = self._prepare_input_data(raw_input=linearizationOptions)
1400+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
13811401

13821402
return self._set_method_helper(
13831403
inputdata=inputdata,
@@ -1387,17 +1407,21 @@ def setLinearizationOptions(
13871407

13881408
def setOptimizationOptions(
13891409
self,
1390-
optimizationOptions: str | list[str] | dict[str, Any],
1410+
*args: Any,
1411+
**kwargs: dict[str, Any],
13911412
) -> bool:
13921413
"""
13931414
This method is used to set optimization options. It can be called:
13941415
with a sequence of optimization options name and assigning corresponding values as arguments as show in the example below:
13951416
usage
13961417
>>> setOptimizationOptions("Name=value") # depreciated
13971418
>>> setOptimizationOptions(["Name1=value1","Name2=value2"]) # depreciated
1398-
>>> setOptimizationOptions(optimizationOptions={"Name1": "value1", "Name2": "value2"})
1419+
1420+
>>> setOptimizationOptions(Name1="value1", Name2="value2")
1421+
>>> param = {"Name1": "value1", "Name2": "value2"}
1422+
>>> setOptimizationOptions(**param)
13991423
"""
1400-
inputdata = self._prepare_input_data(raw_input=optimizationOptions)
1424+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
14011425

14021426
return self._set_method_helper(
14031427
inputdata=inputdata,
@@ -1407,7 +1431,8 @@ def setOptimizationOptions(
14071431

14081432
def setInputs(
14091433
self,
1410-
name: str | list[str] | dict[str, Any],
1434+
*args: Any,
1435+
**kwargs: dict[str, Any],
14111436
) -> bool:
14121437
"""
14131438
This method is used to set input values. It can be called with a sequence of input name and assigning
@@ -1417,9 +1442,12 @@ def setInputs(
14171442
14181443
>>> setInputs("Name=value") # depreciated
14191444
>>> setInputs(["Name1=value1","Name2=value2"]) # depreciated
1420-
>>> setInputs(name={"Name1": "value1", "Name2": "value2"})
1445+
1446+
>>> setInputs(Name1="value1", Name2="value2")
1447+
>>> param = {"Name1": "value1", "Name2": "value2"}
1448+
>>> setInputs(**param)
14211449
"""
1422-
inputdata = self._prepare_input_data(raw_input=name)
1450+
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
14231451

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