Skip to content

Commit f16a61f

Browse files
authored
Make getters raise KeyError instead of returning "NotExist" (#299)
* Make getters raise KeyError ... instead of returning weird values like "NotExist" * Fix incorrect use of IOError When IOError constructor is called with two arguments, the first argument is interpreted as the error number: In [1]: str(IOError("/test1", "does not exist")) Out[1]: '[Errno /test1] does not exist' * Improve docstring for ModelicaSystem.getQuantities * Silence DeprecationWarning in tests
1 parent 2656786 commit f16a61f

File tree

4 files changed

+94
-37
lines changed

4 files changed

+94
-37
lines changed

OMPython/ModelicaSystem.py

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,12 @@ def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pa
472472
# create a unique temp directory for each session and build the model in that directory
473473
if customBuildDirectory is not None:
474474
if not os.path.exists(customBuildDirectory):
475-
raise IOError(customBuildDirectory, " does not exist")
475+
raise IOError(f"{customBuildDirectory} does not exist")
476476
tempdir = pathlib.Path(customBuildDirectory)
477477
else:
478478
tempdir = pathlib.Path(tempfile.mkdtemp())
479479
if not tempdir.is_dir():
480-
raise IOError(tempdir, " cannot be created")
480+
raise IOError(f"{tempdir} could not be created")
481481

482482
logger.info("Define tempdir as %s", tempdir)
483483
exp = f'cd("{tempdir.absolute().as_posix()}")'
@@ -565,19 +565,57 @@ def xmlparse(self):
565565

566566
self.quantitiesList.append(scalar)
567567

568-
def getQuantities(self, names=None): # 3
568+
def getQuantities(self, names: Optional[str | list[str]] = None) -> list[dict]:
569569
"""
570-
This method returns list of dictionaries. It displays details of quantities such as name, value, changeable, and description, where changeable means if value for corresponding quantity name is changeable or not. It can be called :
571-
usage:
572-
>>> getQuantities()
573-
>>> getQuantities("Name1")
574-
>>> getQuantities(["Name1","Name2"])
570+
This method returns list of dictionaries. It displays details of
571+
quantities such as name, value, changeable, and description.
572+
573+
Examples:
574+
>>> mod.getQuantities()
575+
[
576+
{
577+
'alias': 'noAlias',
578+
'aliasvariable': None,
579+
'causality': 'local',
580+
'changeable': 'true',
581+
'description': None,
582+
'max': None,
583+
'min': None,
584+
'name': 'x',
585+
'start': '1.0',
586+
'unit': None,
587+
'variability': 'continuous',
588+
},
589+
{
590+
'name': 'der(x)',
591+
# ...
592+
},
593+
# ...
594+
]
595+
596+
>>> getQuantities("y")
597+
[{
598+
'name': 'y', # ...
599+
}]
600+
601+
>>> getQuantities(["y","x"])
602+
[
603+
{
604+
'name': 'y', # ...
605+
},
606+
{
607+
'name': 'x', # ...
608+
}
609+
]
575610
"""
576611
if names is None:
577612
return self.quantitiesList
578613

579614
if isinstance(names, str):
580-
return [x for x in self.quantitiesList if x["name"] == names]
615+
r = [x for x in self.quantitiesList if x["name"] == names]
616+
if r == []:
617+
raise KeyError(names)
618+
return r
581619

582620
if isinstance(names, list):
583621
return [x for y in names for x in self.quantitiesList if x["name"] == y]
@@ -597,10 +635,10 @@ def getContinuous(self, names=None): # 4
597635
return self.continuouslist
598636

599637
if isinstance(names, str):
600-
return [self.continuouslist.get(names, "NotExist")]
638+
return [self.continuouslist[names]]
601639

602640
if isinstance(names, list):
603-
return [self.continuouslist.get(x, "NotExist") for x in names]
641+
return [self.continuouslist[x] for x in names]
604642
else:
605643
if names is None:
606644
for i in self.continuouslist:
@@ -615,7 +653,7 @@ def getContinuous(self, names=None): # 4
615653
if names in self.continuouslist:
616654
value = self.getSolutions(names)
617655
self.continuouslist[names] = value[0][-1]
618-
return [self.continuouslist.get(names)]
656+
return [self.continuouslist[names]]
619657
else:
620658
raise ModelicaSystemError(f"{names} is not continuous")
621659

@@ -657,9 +695,9 @@ def getParameters(self, names: Optional[str | list[str]] = None) -> dict[str, st
657695
if names is None:
658696
return self.paramlist
659697
elif isinstance(names, str):
660-
return [self.paramlist.get(names, "NotExist")]
698+
return [self.paramlist[names]]
661699
elif isinstance(names, list):
662-
return [self.paramlist.get(x, "NotExist") for x in names]
700+
return [self.paramlist[x] for x in names]
663701

664702
raise ModelicaSystemError("Unhandled input for getParameters()")
665703

@@ -687,15 +725,13 @@ def getInputs(self, names: Optional[str | list[str]] = None) -> dict | list: #
687725
[[(0.0, 0.0), (1.0, 1.0)]]
688726
>>> mod.getInputs(["Name1","Name2"])
689727
[[(0.0, 0.0), (1.0, 1.0)], None]
690-
>>> mod.getInputs("ThisInputDoesNotExist")
691-
['NotExist']
692728
"""
693729
if names is None:
694730
return self.inputlist
695731
elif isinstance(names, str):
696-
return [self.inputlist.get(names, "NotExist")]
732+
return [self.inputlist[names]]
697733
elif isinstance(names, list):
698-
return [self.inputlist.get(x, "NotExist") for x in names]
734+
return [self.inputlist[x] for x in names]
699735

700736
raise ModelicaSystemError("Unhandled input for getInputs()")
701737

@@ -725,8 +761,6 @@ def getOutputs(self, names: Optional[str | list[str]] = None): # 7
725761
['-0.4']
726762
>>> mod.getOutputs(["out1","out2"])
727763
['-0.4', '1.2']
728-
>>> mod.getOutputs("ThisOutputDoesNotExist")
729-
['NotExist']
730764
731765
After simulate():
732766
>>> mod.getOutputs()
@@ -740,9 +774,9 @@ def getOutputs(self, names: Optional[str | list[str]] = None): # 7
740774
if names is None:
741775
return self.outputlist
742776
elif isinstance(names, str):
743-
return [self.outputlist.get(names, "NotExist")]
777+
return [self.outputlist[names]]
744778
else:
745-
return [self.outputlist.get(x, "NotExist") for x in names]
779+
return [self.outputlist[x] for x in names]
746780
else:
747781
if names is None:
748782
for i in self.outputlist:
@@ -753,9 +787,9 @@ def getOutputs(self, names: Optional[str | list[str]] = None): # 7
753787
if names in self.outputlist:
754788
value = self.getSolutions(names)
755789
self.outputlist[names] = value[0][-1]
756-
return [self.outputlist.get(names)]
790+
return [self.outputlist[names]]
757791
else:
758-
return names, " is not Output"
792+
raise KeyError(names)
759793
elif isinstance(names, list):
760794
valuelist = []
761795
for i in names:
@@ -764,7 +798,7 @@ def getOutputs(self, names: Optional[str | list[str]] = None): # 7
764798
self.outputlist[i] = value[0][-1]
765799
valuelist.append(value[0][-1])
766800
else:
767-
return i, "is not Output"
801+
raise KeyError(i)
768802
return valuelist
769803

770804
raise ModelicaSystemError("Unhandled input for getOutputs()")
@@ -781,9 +815,9 @@ def getSimulationOptions(self, names=None): # 8
781815
if names is None:
782816
return self.simulateOptions
783817
elif isinstance(names, str):
784-
return [self.simulateOptions.get(names, "NotExist")]
818+
return [self.simulateOptions[names]]
785819
elif isinstance(names, list):
786-
return [self.simulateOptions.get(x, "NotExist") for x in names]
820+
return [self.simulateOptions[x] for x in names]
787821

788822
raise ModelicaSystemError("Unhandled input for getSimulationOptions()")
789823

@@ -799,9 +833,9 @@ def getLinearizationOptions(self, names=None): # 9
799833
if names is None:
800834
return self.linearOptions
801835
elif isinstance(names, str):
802-
return [self.linearOptions.get(names, "NotExist")]
836+
return [self.linearOptions[names]]
803837
elif isinstance(names, list):
804-
return [self.linearOptions.get(x, "NotExist") for x in names]
838+
return [self.linearOptions[x] for x in names]
805839

806840
raise ModelicaSystemError("Unhandled input for getLinearizationOptions()")
807841

@@ -815,9 +849,9 @@ def getOptimizationOptions(self, names=None): # 10
815849
if names is None:
816850
return self.optimizeOptions
817851
elif isinstance(names, str):
818-
return [self.optimizeOptions.get(names, "NotExist")]
852+
return [self.optimizeOptions[names]]
819853
elif isinstance(names, list):
820-
return [self.optimizeOptions.get(x, "NotExist") for x in names]
854+
return [self.optimizeOptions[x] for x in names]
821855

822856
raise ModelicaSystemError("Unhandled input for getOptimizationOptions()")
823857

@@ -1236,8 +1270,10 @@ def load_module_from_path(module_name, file_path):
12361270
return module_def
12371271

12381272
if self.xmlFile is None:
1239-
raise IOError("Linearization cannot be performed as the model is not build, "
1240-
"use ModelicaSystem() to build the model first")
1273+
raise ModelicaSystemError(
1274+
"Linearization cannot be performed as the model is not build, "
1275+
"use ModelicaSystem() to build the model first"
1276+
)
12411277

12421278
om_cmd = ModelicaSystemCmd(runpath=self.tempdir, modelname=self.modelName, timeout=timeout)
12431279

tests/test_ModelicaSystem.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def test_setParameters():
4343
"e": "1.234",
4444
"g": "321.0",
4545
}
46+
with pytest.raises(KeyError):
47+
mod.getParameters("thisParameterDoesNotExist")
4648

4749
# method 2
4850
mod.setParameters(["e=21.3", "g=0.12"])
@@ -52,6 +54,8 @@ def test_setParameters():
5254
}
5355
assert mod.getParameters(["e", "g"]) == ["21.3", "0.12"]
5456
assert mod.getParameters(["g", "e"]) == ["0.12", "21.3"]
57+
with pytest.raises(KeyError):
58+
mod.getParameters(["g", "thisParameterDoesNotExist"])
5559

5660

5761
def test_setSimulationOptions():
@@ -69,6 +73,8 @@ def test_setSimulationOptions():
6973
assert isinstance(d, dict)
7074
assert d["stopTime"] == "1.234"
7175
assert d["tolerance"] == "1.1e-08"
76+
with pytest.raises(KeyError):
77+
mod.getSimulationOptions("thisOptionDoesNotExist")
7278

7379
# method 2
7480
mod.setSimulationOptions(["stopTime=2.1", "tolerance=1.2e-08"])
@@ -125,7 +131,7 @@ def test_getSolutions(model_firstorder):
125131
assert "x" in sol_names
126132
assert "der(x)" in sol_names
127133
with pytest.raises(OMPython.ModelicaSystemError):
128-
mod.getSolutions("t") # variable 't' does not exist
134+
mod.getSolutions("thisVariableDoesNotExist")
129135
assert np.isclose(t[0], 0), "time does not start at 0"
130136
assert np.isclose(t[-1], stopTime), "time does not end at stopTime"
131137
x_analytical = x0 * np.exp(a*t)
@@ -262,11 +268,18 @@ def test_getters(tmp_path):
262268
},
263269
]
264270

271+
with pytest.raises(KeyError):
272+
mod.getQuantities("thisQuantityDoesNotExist")
273+
265274
assert mod.getInputs() == {}
275+
with pytest.raises(KeyError):
276+
mod.getInputs("thisInputDoesNotExist")
266277
# getOutputs before simulate()
267278
assert mod.getOutputs() == {'y': '-0.4'}
268279
assert mod.getOutputs("y") == ["-0.4"]
269280
assert mod.getOutputs(["y", "y"]) == ["-0.4", "-0.4"]
281+
with pytest.raises(KeyError):
282+
mod.getOutputs("thisOutputDoesNotExist")
270283

271284
# getContinuous before simulate():
272285
assert mod.getContinuous() == {
@@ -276,7 +289,8 @@ def test_getters(tmp_path):
276289
}
277290
assert mod.getContinuous("y") == ['-0.4']
278291
assert mod.getContinuous(["y", "x"]) == ['-0.4', '1.0']
279-
assert mod.getContinuous("a") == ["NotExist"] # a is a parameter
292+
with pytest.raises(KeyError):
293+
mod.getContinuous("a") # a is a parameter
280294

281295
stopTime = 1.0
282296
a = -0.5
@@ -293,6 +307,8 @@ def test_getters(tmp_path):
293307
assert np.isclose(d["y"], dx_analytical, 1e-4)
294308
assert mod.getOutputs("y") == [d["y"]]
295309
assert mod.getOutputs(["y", "y"]) == [d["y"], d["y"]]
310+
with pytest.raises(KeyError):
311+
mod.getOutputs("thisOutputDoesNotExist")
296312

297313
# getContinuous after simulate() should return values at end of simulation:
298314
with pytest.raises(OMPython.ModelicaSystemError):
@@ -307,6 +323,9 @@ def test_getters(tmp_path):
307323
assert mod.getContinuous("x") == [d["x"]]
308324
assert mod.getContinuous(["y", "x"]) == [d["y"], d["x"]]
309325

326+
with pytest.raises(OMPython.ModelicaSystemError):
327+
mod.getContinuous("a") # a is a parameter
328+
310329
with pytest.raises(OMPython.ModelicaSystemError):
311330
mod.setSimulationOptions("thisOptionDoesNotExist=3")
312331

tests/test_ModelicaSystemCmd.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def test_simflags(model_firstorder):
2323
"noRestart": None,
2424
"override": {'b': 2}
2525
})
26-
mscmd.args_set(args=mscmd.parse_simflags(simflags="-noEventEmit -noRestart -override=a=1,x=3"))
26+
with pytest.deprecated_call():
27+
mscmd.args_set(args=mscmd.parse_simflags(simflags="-noEventEmit -noRestart -override=a=1,x=3"))
2728

2829
assert mscmd.get_cmd() == [
2930
mscmd.get_exe().as_posix(),

tests/test_ZMQ.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def test_Simulate(om, model_time_str):
3737

3838

3939
def test_execute(om):
40-
assert om.execute('"HelloWorld!"') == '"HelloWorld!"\n'
40+
with pytest.deprecated_call():
41+
assert om.execute('"HelloWorld!"') == '"HelloWorld!"\n'
4142
assert om.sendExpression('"HelloWorld!"', parsed=False) == '"HelloWorld!"\n'
4243
assert om.sendExpression('"HelloWorld!"', parsed=True) == 'HelloWorld!'

0 commit comments

Comments
 (0)