From a4876b82497bd180f91fbc188bde32fb37084364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 08:25:00 +0200 Subject: [PATCH 01/12] Fix inconsistent indentation in tests --- tests/test_FMIExport.py | 34 +++++++++++----------- tests/test_ModelicaSystem.py | 33 ++++++++++----------- tests/test_ZMQ.py | 56 +++++++++++++++++++----------------- tests/test_docker.py | 24 +++++++++------- tests/test_linearization.py | 37 ++++++++++++------------ 5 files changed, 95 insertions(+), 89 deletions(-) diff --git a/tests/test_FMIExport.py b/tests/test_FMIExport.py index 2837a01ab..80376ca0c 100644 --- a/tests/test_FMIExport.py +++ b/tests/test_FMIExport.py @@ -3,28 +3,28 @@ import tempfile, shutil, os class testFMIExport(unittest.TestCase): - def __init__(self, *args, **kwargs): - super(testFMIExport, self).__init__(*args, **kwargs) - self.tmp = "" + def __init__(self, *args, **kwargs): + super(testFMIExport, self).__init__(*args, **kwargs) + self.tmp = "" - def __del__(self): - shutil.rmtree(self.tmp, ignore_errors=True) + def __del__(self): + shutil.rmtree(self.tmp, ignore_errors=True) - def testCauerLowPassAnalog(self): - print("testing Cauer") - mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", lmodel="Modelica") - self.tmp = mod.getWorkDirectory() + def testCauerLowPassAnalog(self): + print("testing Cauer") + mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", lmodel="Modelica") + self.tmp = mod.getWorkDirectory() - fmu = mod.convertMo2Fmu(fileNamePrefix="CauerLowPassAnalog") - self.assertEqual(True, os.path.exists(fmu)) + fmu = mod.convertMo2Fmu(fileNamePrefix="CauerLowPassAnalog") + self.assertEqual(True, os.path.exists(fmu)) - def testDrumBoiler(self): - print("testing DrumBoiler") - mod = OMPython.ModelicaSystem(modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", lmodel="Modelica") - self.tmp = mod.getWorkDirectory() + def testDrumBoiler(self): + print("testing DrumBoiler") + mod = OMPython.ModelicaSystem(modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", lmodel="Modelica") + self.tmp = mod.getWorkDirectory() - fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler") - self.assertEqual(True, os.path.exists(fmu)) + fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler") + self.assertEqual(True, os.path.exists(fmu)) if __name__ == '__main__': unittest.main() diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 8c9678c95..9648610bf 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -3,28 +3,29 @@ import tempfile, shutil, os class ModelicaSystemTester(unittest.TestCase): - def __init__(self, *args, **kwargs): - super(ModelicaSystemTester, self).__init__(*args, **kwargs) - self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') - with open("%s/M.mo" % self.tmp, "w") as fout: - fout.write("""model M + def __init__(self, *args, **kwargs): + super(ModelicaSystemTester, self).__init__(*args, **kwargs) + self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') + with open("%s/M.mo" % self.tmp, "w") as fout: + fout.write("""model M Real x(start = 1); parameter Real a = -1; equation der(x) = x*a; end M; -""") - def __del__(self): - shutil.rmtree(self.tmp, ignore_errors=True) + """) - def testModelicaSystemLoop(self): - def worker(): - filePath = os.path.join(self.tmp,"M.mo").replace("\\", "/") - m = OMPython.ModelicaSystem(filePath, "M") - m.simulate() - m.convertMo2Fmu(fmuType="me") - for _ in range(10): - worker() + def __del__(self): + shutil.rmtree(self.tmp, ignore_errors=True) + + def testModelicaSystemLoop(self): + def worker(): + filePath = os.path.join(self.tmp,"M.mo").replace("\\", "/") + m = OMPython.ModelicaSystem(filePath, "M") + m.simulate() + m.convertMo2Fmu(fmuType="me") + for _ in range(10): + worker() if __name__ == '__main__': unittest.main() diff --git a/tests/test_ZMQ.py b/tests/test_ZMQ.py index 410bacb42..545da61c5 100644 --- a/tests/test_ZMQ.py +++ b/tests/test_ZMQ.py @@ -3,35 +3,39 @@ import tempfile, shutil, os class ZMQTester(unittest.TestCase): - def __init__(self, *args, **kwargs): - super(ZMQTester, self).__init__(*args, **kwargs) - self.simpleModel = """model M + def __init__(self, *args, **kwargs): + super(ZMQTester, self).__init__(*args, **kwargs) + self.simpleModel = """model M Real r = time; end M;""" - self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') - self.origDir = os.getcwd() - os.chdir(self.tmp) - self.om = OMPython.OMCSessionZMQ() - os.chdir(self.origDir) - def __del__(self): - shutil.rmtree(self.tmp, ignore_errors=True) - del(self.om) - def clean(self): - del(self.om) - self.om = None + self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') + self.origDir = os.getcwd() + os.chdir(self.tmp) + self.om = OMPython.OMCSessionZMQ() + os.chdir(self.origDir) - def testHelloWorld(self): - self.assertEqual("HelloWorld!", self.om.sendExpression('"HelloWorld!"')) - self.clean() - def testTranslate(self): - self.assertEqual(("M",), self.om.sendExpression(self.simpleModel)) - self.assertEqual(True, self.om.sendExpression('translateModel(M)')) - self.clean() - def testSimulate(self): - self.assertEqual(True, self.om.sendExpression('loadString("%s")' % self.simpleModel)) - self.om.sendExpression('res:=simulate(M, stopTime=2.0)') - self.assertNotEqual("", self.om.sendExpression('res.resultFile')) - self.clean() + def __del__(self): + shutil.rmtree(self.tmp, ignore_errors=True) + del(self.om) + + def clean(self): + del(self.om) + self.om = None + + def testHelloWorld(self): + self.assertEqual("HelloWorld!", self.om.sendExpression('"HelloWorld!"')) + self.clean() + + def testTranslate(self): + self.assertEqual(("M",), self.om.sendExpression(self.simpleModel)) + self.assertEqual(True, self.om.sendExpression('translateModel(M)')) + self.clean() + + def testSimulate(self): + self.assertEqual(True, self.om.sendExpression('loadString("%s")' % self.simpleModel)) + self.om.sendExpression('res:=simulate(M, stopTime=2.0)') + self.assertNotEqual("", self.om.sendExpression('res.resultFile')) + self.clean() if __name__ == '__main__': unittest.main() diff --git a/tests/test_docker.py b/tests/test_docker.py index 1db6deaf3..df2816671 100644 --- a/tests/test_docker.py +++ b/tests/test_docker.py @@ -4,16 +4,18 @@ import pytest class DockerTester(unittest.TestCase): - @pytest.mark.skip(reason="This test would fail") - def testDocker(self): - om = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal") - assert(om.sendExpression("getVersion()") == "OpenModelica 1.16.1") - omInner = OMPython.OMCSessionZMQ(dockerContainer=om._dockerCid) - assert(omInner.sendExpression("getVersion()") == "OpenModelica 1.16.1") - om2 = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal", port=11111) - assert(om2.sendExpression("getVersion()") == "OpenModelica 1.16.1") - del(om2) - del(omInner) - del(om) + @pytest.mark.skip(reason="This test would fail") + def testDocker(self): + om = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal") + assert(om.sendExpression("getVersion()") == "OpenModelica 1.16.1") + omInner = OMPython.OMCSessionZMQ(dockerContainer=om._dockerCid) + assert(omInner.sendExpression("getVersion()") == "OpenModelica 1.16.1") + om2 = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal", port=11111) + assert(om2.sendExpression("getVersion()") == "OpenModelica 1.16.1") + del(om2) + del(omInner) + del(om) + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_linearization.py b/tests/test_linearization.py index c35979d2c..93dceebf7 100644 --- a/tests/test_linearization.py +++ b/tests/test_linearization.py @@ -3,10 +3,10 @@ import pytest class Test_Linearization: - def loadModel(self): - self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') - with open("%s/linearTest.mo" % self.tmp, "w") as fout: - fout.write(""" + def loadModel(self): + self.tmp = tempfile.mkdtemp(prefix='tmpOMPython.tests') + with open("%s/linearTest.mo" % self.tmp, "w") as fout: + fout.write(""" model linearTest Real x1(start=1); Real x2(start=-2); @@ -19,20 +19,19 @@ def loadModel(self): f*x4 - e*x3 - der(x3) = x1; der(x4) = x1 + x2 + der(x3) + x4; end linearTest; -""") + """) - def __del__(self): - shutil.rmtree(self.tmp, ignore_errors=True) - - def test_example(self): - self.loadModel() - filePath = os.path.join(self.tmp,"linearTest.mo").replace("\\", "/") - print(filePath) - mod = OMPython.ModelicaSystem(filePath, "linearTest") - [A, B, C, D] = mod.linearize() - expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]] - assert A == expected_matrixA, f"Matrix does not match the expected value. Got: {A}, Expected: {expected_matrixA}" - assert B == [], f"Matrix does not match the expected value. Got: {B}, Expected: {[]}" - assert C == [], f"Matrix does not match the expected value. Got: {C}, Expected: {[]}" - assert D == [], f"Matrix does not match the expected value. Got: {D}, Expected: {[]}" + def __del__(self): + shutil.rmtree(self.tmp, ignore_errors=True) + def test_example(self): + self.loadModel() + filePath = os.path.join(self.tmp,"linearTest.mo").replace("\\", "/") + print(filePath) + mod = OMPython.ModelicaSystem(filePath, "linearTest") + [A, B, C, D] = mod.linearize() + expected_matrixA = [[-3, 2, 0, 0], [-7, 0, -5, 1], [-1, 0, -1, 4], [0, 1, -1, 5]] + assert A == expected_matrixA, f"Matrix does not match the expected value. Got: {A}, Expected: {expected_matrixA}" + assert B == [], f"Matrix does not match the expected value. Got: {B}, Expected: {[]}" + assert C == [], f"Matrix does not match the expected value. Got: {C}, Expected: {[]}" + assert D == [], f"Matrix does not match the expected value. Got: {D}, Expected: {[]}" From 4b4f9f3827c5bd6438ec7bdf04eb56b90568ad53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 09:10:00 +0200 Subject: [PATCH 02/12] Fix flake8 warnings in tests --- tests/test_ArrayDimension.py | 21 +++++++++------------ tests/test_FMIExport.py | 5 ++++- tests/test_FMIRegression.py | 21 ++++++++++----------- tests/test_ModelicaSystem.py | 8 ++++++-- tests/test_ZMQ.py | 10 +++++++--- tests/test_docker.py | 14 +++++++------- tests/test_linearization.py | 8 +++++--- 7 files changed, 48 insertions(+), 39 deletions(-) diff --git a/tests/test_ArrayDimension.py b/tests/test_ArrayDimension.py index 0987727b6..abb368cb5 100644 --- a/tests/test_ArrayDimension.py +++ b/tests/test_ArrayDimension.py @@ -1,30 +1,28 @@ import OMPython -import tempfile, shutil, os -import pytest +import tempfile +import shutil +import os -""" -do not change the prefix class name, the class name should have prefix "Test" -according to the documenation of pytest -""" +# do not change the prefix class name, the class name should have prefix "Test" +# according to the documenation of pytest class Test_ArrayDimension: - def test_ArrayDimension(self): omc = OMPython.OMCSessionZMQ() - ## create a temp dir for each session + # create a temp dir for each session tempdir = tempfile.mkdtemp() if not os.path.exists(tempdir): return print(tempdir, " cannot be created") - tempdirExp="".join(["cd(","\"",tempdir,"\"",")"]).replace("\\","/") + tempdirExp = "".join(["cd(", "\"", tempdir, "\"", ")"]).replace("\\", "/") omc.sendExpression(tempdirExp) omc.sendExpression("loadString(\"model A Integer x[5+1,1+6]; end A;\")") omc.sendExpression("getErrorString()") result = omc.sendExpression("getComponents(A)") - assert result[0][-1] == (6,7), f"array dimension does not match the expected value. Got: {result[0][-1]}, Expected: {(6, 7)}" + assert result[0][-1] == (6, 7), f"array dimension does not match the expected value. Got: {result[0][-1]}, Expected: {(6, 7)}" omc.sendExpression("loadString(\"model A Integer y = 5; Integer x[y+1,1+9]; end A;\")") omc.sendExpression("getErrorString()") @@ -33,5 +31,4 @@ def test_ArrayDimension(self): assert result[-1][-1] == ('y+1', 10), f"array dimension does not match the expected value. Got: {result[-1][-1]}, Expected: {('y+1', 10)}" omc.__del__() - shutil.rmtree(tempdir, ignore_errors= True) - + shutil.rmtree(tempdir, ignore_errors=True) diff --git a/tests/test_FMIExport.py b/tests/test_FMIExport.py index 80376ca0c..15e94227e 100644 --- a/tests/test_FMIExport.py +++ b/tests/test_FMIExport.py @@ -1,6 +1,8 @@ import OMPython import unittest -import tempfile, shutil, os +import shutil +import os + class testFMIExport(unittest.TestCase): def __init__(self, *args, **kwargs): @@ -26,5 +28,6 @@ def testDrumBoiler(self): fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler") self.assertEqual(True, os.path.exists(fmu)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_FMIRegression.py b/tests/test_FMIRegression.py index 95435b85d..b39fdf1a2 100644 --- a/tests/test_FMIRegression.py +++ b/tests/test_FMIRegression.py @@ -1,36 +1,35 @@ import OMPython -import tempfile, shutil, os -import pytest +import tempfile +import shutil +import os -""" -do not change the prefix class name, the class name should have prefix "Test" -according to the documenation of pytest -""" +# do not change the prefix class name, the class name should have prefix "Test" +# according to the documenation of pytest class Test_FMIRegression: def buildModelFMU(self, modelName): omc = OMPython.OMCSessionZMQ() - ## create a temp dir for each session + # create a temp dir for each session tempdir = tempfile.mkdtemp() if not os.path.exists(tempdir): return print(tempdir, " cannot be created") - tempdirExp="".join(["cd(","\"",tempdir,"\"",")"]).replace("\\","/") + tempdirExp = "".join(["cd(", "\"", tempdir, "\"", ")"]).replace("\\", "/") omc.sendExpression(tempdirExp) omc.sendExpression("loadModel(Modelica)") omc.sendExpression("getErrorString()") fileNamePrefix = modelName.split(".")[-1] - exp = "buildModelFMU(" + modelName + ", fileNamePrefix=\"" + fileNamePrefix + "\"" + ")" + exp = "buildModelFMU(" + modelName + ", fileNamePrefix=\"" + fileNamePrefix + "\"" + ")" fmu = omc.sendExpression(exp) - assert True == os.path.exists(fmu) + assert os.path.exists(fmu) omc.__del__() - shutil.rmtree(tempdir, ignore_errors= True) + shutil.rmtree(tempdir, ignore_errors=True) def test_Modelica_Blocks_Examples_Filter(self): self.buildModelFMU("Modelica.Blocks.Examples.Filter") diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 9648610bf..d8ee57b02 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -1,6 +1,9 @@ import OMPython import unittest -import tempfile, shutil, os +import tempfile +import shutil +import os + class ModelicaSystemTester(unittest.TestCase): def __init__(self, *args, **kwargs): @@ -20,12 +23,13 @@ def __del__(self): def testModelicaSystemLoop(self): def worker(): - filePath = os.path.join(self.tmp,"M.mo").replace("\\", "/") + filePath = os.path.join(self.tmp, "M.mo").replace("\\", "/") m = OMPython.ModelicaSystem(filePath, "M") m.simulate() m.convertMo2Fmu(fmuType="me") for _ in range(10): worker() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_ZMQ.py b/tests/test_ZMQ.py index 545da61c5..e13ea421a 100644 --- a/tests/test_ZMQ.py +++ b/tests/test_ZMQ.py @@ -1,6 +1,9 @@ import OMPython import unittest -import tempfile, shutil, os +import tempfile +import shutil +import os + class ZMQTester(unittest.TestCase): def __init__(self, *args, **kwargs): @@ -16,10 +19,10 @@ def __init__(self, *args, **kwargs): def __del__(self): shutil.rmtree(self.tmp, ignore_errors=True) - del(self.om) + del self.om def clean(self): - del(self.om) + del self.om self.om = None def testHelloWorld(self): @@ -37,5 +40,6 @@ def testSimulate(self): self.assertNotEqual("", self.om.sendExpression('res.resultFile')) self.clean() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_docker.py b/tests/test_docker.py index df2816671..fc518f260 100644 --- a/tests/test_docker.py +++ b/tests/test_docker.py @@ -1,20 +1,20 @@ import OMPython import unittest -import tempfile, shutil, os import pytest + class DockerTester(unittest.TestCase): @pytest.mark.skip(reason="This test would fail") def testDocker(self): om = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal") - assert(om.sendExpression("getVersion()") == "OpenModelica 1.16.1") + assert om.sendExpression("getVersion()") == "OpenModelica 1.16.1" omInner = OMPython.OMCSessionZMQ(dockerContainer=om._dockerCid) - assert(omInner.sendExpression("getVersion()") == "OpenModelica 1.16.1") + assert omInner.sendExpression("getVersion()") == "OpenModelica 1.16.1" om2 = OMPython.OMCSessionZMQ(docker="openmodelica/openmodelica:v1.16.1-minimal", port=11111) - assert(om2.sendExpression("getVersion()") == "OpenModelica 1.16.1") - del(om2) - del(omInner) - del(om) + assert om2.sendExpression("getVersion()") == "OpenModelica 1.16.1" + del om2 + del omInner + del om if __name__ == '__main__': diff --git a/tests/test_linearization.py b/tests/test_linearization.py index 93dceebf7..151f05658 100644 --- a/tests/test_linearization.py +++ b/tests/test_linearization.py @@ -1,6 +1,8 @@ import OMPython -import tempfile, shutil, os -import pytest +import tempfile +import shutil +import os + class Test_Linearization: def loadModel(self): @@ -26,7 +28,7 @@ def __del__(self): def test_example(self): self.loadModel() - filePath = os.path.join(self.tmp,"linearTest.mo").replace("\\", "/") + filePath = os.path.join(self.tmp, "linearTest.mo").replace("\\", "/") print(filePath) mod = OMPython.ModelicaSystem(filePath, "linearTest") [A, B, C, D] = mod.linearize() From 53fc10ded9a89d33238c529352bc01f989a80e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 11:13:41 +0200 Subject: [PATCH 03/12] Add test for ModelicaSystem.setParameters() This test is currently failing, because getParameters() returns str instead of float. However, the documentation https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/ompython.html#simulation says it should return floats. --- tests/test_ModelicaSystem.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index d8ee57b02..54bfe7560 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -30,6 +30,39 @@ def worker(): for _ in range(10): worker() + def test_setParameters(self): + omc = OMPython.OMCSessionZMQ() + model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" + mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall", raiseerrors=True) + + # method 1 + mod.setParameters("e=1.234") + mod.setParameters("g=321.0") + assert mod.getParameters("e") == [1.234] + assert mod.getParameters("g") == [321.0] + assert mod.getParameters() == { + "e": 1.234, + "g": 321.0, + } + + # method 2 + mod.setParameters(["e=21.3", "g=0.12"]) + assert mod.getParameters() == { + "e": 21.3, + "g": 0.12, + } + assert mod.getParameters(["e", "g"]) == [21.3, 0.12] + assert mod.getParameters(["g", "e"]) == [0.12, 21.3] + + # method 3 + mod.setParameters({ + "e": 2.13, + "g": 0.21, + }) + assert mod.getParameters() == { + "e": 2.13, + "g": 0.21, + } if __name__ == '__main__': unittest.main() From d85e41e4576f527800994bcceae3a47188734687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 12:10:40 +0200 Subject: [PATCH 04/12] Change test_setParameters to match current behavior The documentation is wrong, as discussed in https://github.com/OpenModelica/OMPython/issues/244 --- tests/test_ModelicaSystem.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 54bfe7560..c7b8c584c 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -38,31 +38,22 @@ def test_setParameters(self): # method 1 mod.setParameters("e=1.234") mod.setParameters("g=321.0") - assert mod.getParameters("e") == [1.234] - assert mod.getParameters("g") == [321.0] + assert mod.getParameters("e") == ["1.234"] + assert mod.getParameters("g") == ["321.0"] assert mod.getParameters() == { - "e": 1.234, - "g": 321.0, + "e": "1.234", + "g": "321.0", } # method 2 mod.setParameters(["e=21.3", "g=0.12"]) assert mod.getParameters() == { - "e": 21.3, - "g": 0.12, + "e": "21.3", + "g": "0.12", } - assert mod.getParameters(["e", "g"]) == [21.3, 0.12] - assert mod.getParameters(["g", "e"]) == [0.12, 21.3] + assert mod.getParameters(["e", "g"]) == ["21.3", "0.12"] + assert mod.getParameters(["g", "e"]) == ["0.12", "21.3"] - # method 3 - mod.setParameters({ - "e": 2.13, - "g": 0.21, - }) - assert mod.getParameters() == { - "e": 2.13, - "g": 0.21, - } if __name__ == '__main__': unittest.main() From d086190be98409d7f4259f96fd17d3f112fc50ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 12:14:43 +0200 Subject: [PATCH 05/12] Add test for ModelicaSystem.setSimulationOptions() --- tests/test_ModelicaSystem.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index c7b8c584c..eb095d29c 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -54,6 +54,28 @@ def test_setParameters(self): assert mod.getParameters(["e", "g"]) == ["21.3", "0.12"] assert mod.getParameters(["g", "e"]) == ["0.12", "21.3"] + def test_setSimulationOptions(self): + omc = OMPython.OMCSessionZMQ() + model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" + mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall", raiseerrors=True) + + # method 1 + mod.setSimulationOptions("stopTime=1.234") + mod.setSimulationOptions("tolerance=1.1e-08") + assert mod.getSimulationOptions("stopTime") == ["1.234"] + assert mod.getSimulationOptions("tolerance") == ["1.1e-08"] + assert mod.getSimulationOptions(["tolerance", "stopTime"]) == ["1.1e-08", "1.234"] + d = mod.getSimulationOptions() + assert isinstance(d, dict) + assert d["stopTime"] == "1.234" + assert d["tolerance"] == "1.1e-08" + + # method 2 + mod.setSimulationOptions(["stopTime=2.1", "tolerance=1.2e-08"]) + d = mod.getSimulationOptions() + assert d["stopTime"] == "2.1" + assert d["tolerance"] == "1.2e-08" + if __name__ == '__main__': unittest.main() From 6311507b883837daff7bac0f94e83fa00ae56ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 16:05:49 +0200 Subject: [PATCH 06/12] Fix flake8 warnings in __init__.py --- OMPython/__init__.py | 228 ++++++++++++++++++++++--------------------- setup.cfg | 2 + 2 files changed, 118 insertions(+), 112 deletions(-) create mode 100644 setup.cfg diff --git a/OMPython/__init__.py b/OMPython/__init__.py index c817657c5..b0b65180f 100644 --- a/OMPython/__init__.py +++ b/OMPython/__init__.py @@ -12,7 +12,6 @@ from __future__ import print_function from future.utils import with_metaclass from builtins import int, range -from copy import deepcopy import shutil import abc @@ -32,12 +31,11 @@ import time import uuid import xml.etree.ElementTree as ET -from collections import OrderedDict import numpy as np import pyparsing import importlib import zmq -import warnings + if sys.platform == 'darwin': # On Mac let's assume omc is installed here and there might be a broken omniORB installed in a bad place @@ -91,17 +89,21 @@ logger.addHandler(logger_console_handler) logger.setLevel(logging.WARNING) + class DummyPopen(): - def __init__(self, pid): - self.pid = pid - self.process = psutil.Process(pid) - self.returncode = 0 - def poll(self): - return None if self.process.is_running() else True - def kill(self): - return os.kill(self.pid, signal.SIGKILL) - def wait(self, timeout): - return self.process.wait(timeout=timeout) + def __init__(self, pid): + self.pid = pid + self.process = psutil.Process(pid) + self.returncode = 0 + + def poll(self): + return None if self.process.is_running() else True + + def kill(self): + return os.kill(self.pid, signal.SIGKILL) + + def wait(self, timeout): + return self.process.wait(timeout=timeout) class OMCSessionHelper: @@ -163,25 +165,25 @@ def __init__(self, readonly=False): def __del__(self): try: - self.sendExpression("quit()") - except: - pass + self.sendExpression("quit()") + except Exception: + pass self._omc_log_file.close() if sys.version_info.major >= 3: - try: - self._omc_process.wait(timeout=2.0) - except: - if self._omc_process: - self._omc_process.kill() + try: + self._omc_process.wait(timeout=2.0) + except Exception: + if self._omc_process: + self._omc_process.kill() else: - for i in range(0,100): - time.sleep(0.02) - if self._omc_process and (self._omc_process.poll() is not None): - break + for i in range(0, 100): + time.sleep(0.02) + if self._omc_process and (self._omc_process.poll() is not None): + break # kill self._omc_process process if it is still running/exists if self._omc_process is not None and self._omc_process.returncode is None: print("OMC did not exit after being sent the quit() command; killing the process with pid=%s" % str(self._omc_process.pid)) - if sys.platform=="win32": + if sys.platform == "win32": self._omc_process.kill() self._omc_process.wait() else: @@ -209,52 +211,52 @@ def _start_omc_process(self, timeout): # Because we spawned a shell, and we need to be able to kill OMC, create a new process group for this self._omc_process = subprocess.Popen(self._omc_command, shell=True, stdout=self._omc_log_file, stderr=self._omc_log_file, env=my_env, preexec_fn=os.setsid) if self._docker: - for i in range(0,40): + for i in range(0, 40): + try: + with open(self._dockerCidFile, "r") as fin: + self._dockerCid = fin.read().strip() + except Exception: + pass + if self._dockerCid: + break + time.sleep(timeout / 40.0) try: - with open(self._dockerCidFile, "r") as fin: - self._dockerCid = fin.read().strip() - except: - pass - if self._dockerCid: - break - time.sleep(timeout / 40.0) - try: - os.remove(self._dockerCidFile) - except: - pass - if self._dockerCid is None: - logger.error("Docker did not start. Log-file says:\n%s" % (open(self._omc_log_file.name).read())) - raise Exception("Docker did not start (timeout=%f might be too short especially if you did not docker pull the image before this command)." % timeout) + os.remove(self._dockerCidFile) + except Exception: + pass + if self._dockerCid is None: + logger.error("Docker did not start. Log-file says:\n%s" % (open(self._omc_log_file.name).read())) + raise Exception("Docker did not start (timeout=%f might be too short especially if you did not docker pull the image before this command)." % timeout) if self._docker or self._dockerContainer: - if self._dockerNetwork == "separate": - self._serverIPAddress = json.loads(subprocess.check_output(["docker", "inspect", self._dockerCid]).decode().strip())[0]["NetworkSettings"]["IPAddress"] - for i in range(0,40): - if sys.platform == 'win32': - break - dockerTop = subprocess.check_output(["docker", "top", self._dockerCid]).decode().strip() - self._omc_process = None - for line in dockerTop.split("\n"): - columns = line.split() - if self._random_string in line: - try: - self._omc_process = DummyPopen(int(columns[1])) - except psutil.NoSuchProcess: - raise Exception("Could not find PID %d - is this a docker instance spawned without --pid=host?\nLog-file says:\n%s" % (self._random_string, dockerTop, open(self._omc_log_file.name).read())) - break - if self._omc_process is not None: - break - time.sleep(timeout / 40.0) - if self._omc_process is None: - raise Exception("Docker top did not contain omc process %s:\n%s\nLog-file says:\n%s" % (self._random_string, dockerTop, open(self._omc_log_file.name).read())) + if self._dockerNetwork == "separate": + self._serverIPAddress = json.loads(subprocess.check_output(["docker", "inspect", self._dockerCid]).decode().strip())[0]["NetworkSettings"]["IPAddress"] + for i in range(0, 40): + if sys.platform == 'win32': + break + dockerTop = subprocess.check_output(["docker", "top", self._dockerCid]).decode().strip() + self._omc_process = None + for line in dockerTop.split("\n"): + columns = line.split() + if self._random_string in line: + try: + self._omc_process = DummyPopen(int(columns[1])) + except psutil.NoSuchProcess: + raise Exception(f"Could not find PID {dockerTop} - is this a docker instance spawned without --pid=host?\nLog-file says:\n{open(self._omc_log_file.name).read()}") + break + if self._omc_process is not None: + break + time.sleep(timeout / 40.0) + if self._omc_process is None: + raise Exception("Docker top did not contain omc process %s:\n%s\nLog-file says:\n%s" % (self._random_string, dockerTop, open(self._omc_log_file.name).read())) return self._omc_process def _getuid(self): - """ - The uid to give to docker. - On Windows, volumes are mapped with all files are chmod ugo+rwx, - so uid does not matter as long as it is not the root user. - """ - return 1000 if sys.platform == 'win32' else os.getuid() + """ + The uid to give to docker. + On Windows, volumes are mapped with all files are chmod ugo+rwx, + so uid does not matter as long as it is not the root user. + """ + return 1000 if sys.platform == 'win32' else os.getuid() def _set_omc_command(self, omc_path_and_args_list): """Define the command that will be called by the subprocess module. @@ -272,7 +274,7 @@ def _set_omc_command(self, omc_path_and_args_list): if self._docker: if sys.platform == "win32": p = int(self._interactivePort) - dockerNetworkStr = ["-p", "127.0.0.1:%d:%d" % (p,p)] + dockerNetworkStr = ["-p", "127.0.0.1:%d:%d" % (p, p)] elif self._dockerNetwork == "host" or self._dockerNetwork is None: dockerNetworkStr = ["--network=host"] elif self._dockerNetwork == "separate": @@ -533,11 +535,12 @@ def getClassNames(self, className=None, recursive=False, qualified=False, sort=F str(builtin).lower(), str(showProtected).lower())) return value + class OMCSessionZMQ(OMCSessionHelper, OMCSessionBase): - def __init__(self, readonly=False, timeout = 10.00, - docker = None, dockerContainer = None, dockerExtraArgs = None, dockerOpenModelicaPath = "omc", - dockerNetwork = None, port = None, omhome: str = None): + def __init__(self, readonly=False, timeout=10.00, + docker=None, dockerContainer=None, dockerExtraArgs=None, dockerOpenModelicaPath="omc", + dockerNetwork=None, port=None, omhome: str = None): if dockerExtraArgs is None: dockerExtraArgs = [] @@ -581,7 +584,7 @@ def _connect_to_omc(self, timeout): try: self._port = subprocess.check_output(["docker", "exec", self._dockerCid, "cat", self._port_file], stderr=subprocess.DEVNULL if (sys.version_info > (3, 0)) else subprocess.STDOUT).decode().strip() break - except: + except Exception: pass else: if os.path.isfile(self._port_file): @@ -596,7 +599,7 @@ def _connect_to_omc(self, timeout): name = self._omc_log_file.name self._omc_log_file.close() logger.error("OMC Server did not start. Please start it! Log-file says:\n%s" % open(name).read()) - raise Exception("OMC Server did not start (timeout=%f). Could not open file %s" % (timeout,self._port_file)) + raise Exception("OMC Server did not start (timeout=%f). Could not open file %s" % (timeout, self._port_file)) time.sleep(timeout / 80.0) self._port = self._port.replace("0.0.0.0", self._serverIPAddress) @@ -605,18 +608,18 @@ def _connect_to_omc(self, timeout): # Create the ZeroMQ socket and connect to OMC server context = zmq.Context.instance() self._omc = context.socket(zmq.REQ) - self._omc.setsockopt(zmq.LINGER, 0) # Dismisses pending messages if closed - self._omc.setsockopt(zmq.IMMEDIATE, True) # Queue messages only to completed connections + self._omc.setsockopt(zmq.LINGER, 0) # Dismisses pending messages if closed + self._omc.setsockopt(zmq.IMMEDIATE, True) # Queue messages only to completed connections self._omc.connect(self._port) def execute(self, command): - ## check for process is running + # check for process is running return self.sendExpression(command, parsed=False) def sendExpression(self, command, parsed=True): - ## check for process is running - p=self._omc_process.poll() - if (p == None): + # check for process is running + p = self._omc_process.poll() + if p is None: attempts = 0 while True: try: @@ -644,9 +647,11 @@ def sendExpression(self, command, parsed=True): else: raise Exception("Process Exited, No connection with OMC. Create a new instance of OMCSessionZMQ") + class ModelicaSystemError(Exception): pass + class ModelicaSystem(object): def __init__(self, fileName=None, modelName=None, lmodel=None, commandLineOptions=None, variableFilter=None, customBuildDirectory=None, verbose=True, raiseerrors=False, @@ -688,11 +693,11 @@ def __init__(self, fileName=None, modelName=None, lmodel=None, commandLineOption else: self.getconn = OMCSessionZMQ(omhome=omhome) - ## needed for properly deleting the session + # needed for properly deleting the session self._omc_log_file = self.getconn._omc_log_file self._omc_process = self.getconn._omc_process - ## set commandLineOptions if provided by users + # set commandLineOptions if provided by users self.setCommandLineOptions(commandLineOptions=commandLineOptions) if lmodel is None: @@ -714,9 +719,9 @@ def __init__(self, fileName=None, modelName=None, lmodel=None, commandLineOption if fileName is not None and not os.path.exists(self.fileName): # if file does not exist raise IOError("File Error:" + os.path.abspath(self.fileName) + " does not exist!!!") - ## set default command Line Options for linearization as - ## linearize() will use the simulation executable and runtime - ## flag -l to perform linearization + # set default command Line Options for linearization as + # linearize() will use the simulation executable and runtime + # flag -l to perform linearization self.sendExpression("setCommandLineOptions(\"--linearizationDumpLanguage=python\")") self.sendExpression("setCommandLineOptions(\"--generateSymbolicLinearization\")") @@ -726,14 +731,14 @@ def __init__(self, fileName=None, modelName=None, lmodel=None, commandLineOption self.loadLibrary() self.loadFile() - ## allow directly loading models from MSL without fileName + # allow directly loading models from MSL without fileName if fileName is None and modelName is not None: self.loadLibrary() self.buildModel(variableFilter) def setCommandLineOptions(self, commandLineOptions: str): - ## set commandLineOptions if provided by users + # set commandLineOptions if provided by users if commandLineOptions is not None: exp = "".join(["setCommandLineOptions(", "\"", commandLineOptions, "\"", ")"]) cmdexp = self.sendExpression(exp) @@ -744,7 +749,7 @@ def loadFile(self): # load file loadFileExp = "".join(["loadFile(", "\"", self.fileName, "\"", ")"]).replace("\\", "/") loadMsg = self.sendExpression(loadFileExp) - ## Show notification or warnings to the user when verbose=True OR if some error occurred i.e., not result + # Show notification or warnings to the user when verbose=True OR if some error occurred i.e., not result if self._verbose or not loadMsg: self._check_error() @@ -771,7 +776,7 @@ def loadLibrary(self): "The following patterns are supported:\n" + "1)[\"Modelica\"]\n" + "2)[(\"Modelica\",\"3.2.3\"), \"PowerSystems\"]\n") - ## Show notification or warnings to the user when verbose=True OR if some error occurred i.e., not result + # Show notification or warnings to the user when verbose=True OR if some error occurred i.e., not result if self._verbose or not result: self._check_error() @@ -799,7 +804,7 @@ def _run_cmd(self, cmd: list): if platform.system() == "Windows": dllPath = "" - ## set the process environment from the generated .bat file in windows which should have all the dependencies + # set the process environment from the generated .bat file in windows which should have all the dependencies batFilePath = os.path.join(self.tempdir, '{}.{}'.format(self.modelName, "bat")).replace("\\", "/") if (not os.path.exists(batFilePath)): print("Error: bat does not exist " + batFilePath) @@ -950,7 +955,7 @@ def getQuantities(self, names=None): # 3 >>> getQuantities("Name1") >>> getQuantities(["Name1","Name2"]) """ - if (names == None): + if names is None: return self.quantitiesList elif (isinstance(names, str)): return [x for x in self.quantitiesList if x["name"] == names] @@ -1010,7 +1015,7 @@ def getParameters(self, names=None): # 5 >>> getParameters("Name1") >>> getParameters(["Name1","Name2"]) """ - if (names == None): + if names is None: return self.paramlist elif (isinstance(names, str)): return [self.paramlist.get(names, "NotExist")] @@ -1036,7 +1041,7 @@ def getInputs(self, names=None): # 6 If *name is None then the function will return dict which contain all input names as key and value as corresponding values. eg., getInputs() Otherwise variable number of arguments can be passed as input name in string format separated by commas. eg., getInputs('iName1', 'iName2') """ - if (names == None): + if names is None: return self.inputlist elif (isinstance(names, str)): return [self.inputlist.get(names, "NotExist")] @@ -1053,14 +1058,14 @@ def getOutputs(self, names=None): # 7 >>> getOutputs(["Name1","Name2"]) """ if not self.simulationFlag: - if (names == None): + if names is None: return self.outputlist elif (isinstance(names, str)): return [self.outputlist.get(names, "NotExist")] else: return ([self.outputlist.get(x, "NotExist") for x in names]) else: - if (names == None): + if names is None: for i in self.outputlist: value = self.getSolutions(i) self.outputlist[i] = value[0][-1] @@ -1092,7 +1097,7 @@ def getSimulationOptions(self, names=None): # 8 >>> getSimulationOptions("Name1") >>> getSimulationOptions(["Name1","Name2"]) """ - if (names == None): + if names is None: return self.simulateOptions elif (isinstance(names, str)): return [self.simulateOptions.get(names, "NotExist")] @@ -1108,7 +1113,7 @@ def getLinearizationOptions(self, names=None): # 9 >>> getLinearizationOptions("Name1") >>> getLinearizationOptions(["Name1","Name2"]) """ - if (names == None): + if names is None: return self.linearOptions elif (isinstance(names, str)): return [self.linearOptions.get(names, "NotExist")] @@ -1122,7 +1127,7 @@ def getOptimizationOptions(self, names=None): # 10 >>> getOptimizationOptions("Name1") >>> getOptimizationOptions(["Name1","Name2"]) """ - if (names == None): + if names is None: return self.optimizeOptions elif (isinstance(names, str)): return [self.optimizeOptions.get(names, "NotExist")] @@ -1173,7 +1178,7 @@ def simulate(self, resultfile=None, simflags=None): # 11 if (self.inputFlag): # if model has input quantities for i in self.inputlist: val = self.inputlist[i] - if (val == None): + if val is None: val = [(float(self.simulateOptions["startTime"]), 0.0), (float(self.simulateOptions["stopTime"]), 0.0)] self.inputlist[i] = [(float(self.simulateOptions["startTime"]), 0.0), @@ -1222,7 +1227,7 @@ def getSolutions(self, varList=None, resultfile=None): # 12 >>> getSolutions("Name1",resultfile=""c:/a.mat"") >>> getSolutions(["Name1","Name2"],resultfile=""c:/a.mat"") """ - if (resultfile == None): + if resultfile is None: resFile = self.resultfile else: resFile = resultfile @@ -1236,7 +1241,7 @@ def getSolutions(self, varList=None, resultfile=None): # 12 else: resultVars = self.sendExpression("readSimulationResultVars(\"" + resFile + "\")") self.sendExpression("closeSimulationResultFile()") - if (varList == None): + if varList is None: return resultVars elif (isinstance(varList, str)): if (varList not in resultVars and varList != "time"): @@ -1284,13 +1289,13 @@ def apply_single(args1): args1 = self.strip_space(args1) value = args1.split("=") if value[0] in args2: - if (args3 == "parameter" and self.isParameterChangeable(value[0], value[1])): + if args3 == "parameter" and self.isParameterChangeable(value[0], value[1]): args2[value[0]] = value[1] - if (args4 != None): + if args4 is not None: args4[value[0]] = value[1] - elif (args3 != "parameter"): + elif args3 != "parameter": args2[value[0]] = value[1] - if (args4 != None): + if args4 is not None: args4[value[0]] = value[1] return True @@ -1431,7 +1436,7 @@ def createCSVData(self): sl = list() # Actual timestamps skip = False - ## check for NONE in input list and replace with proper data (e.g) [(startTime, 0.0), (stopTime, 0.0)] + # check for NONE in input list and replace with proper data (e.g) [(startTime, 0.0), (stopTime, 0.0)] tmpinputlist = {} for (key, value) in self.inputlist.items(): if (value is None): @@ -1526,7 +1531,7 @@ def createCSVData(self): l = [] l.append(name) for i in range(0, len(sl)): - a = ("%s,%s" % (str(float(sl[i])), ",".join(list(str(float(inppp[i])) \ + a = ("%s,%s" % (str(float(sl[i])), ",".join(list(str(float(inppp[i])) for inppp in interpolated_inputs_all)))) + ',0' l.append(a) @@ -1558,7 +1563,7 @@ def convertMo2Fmu(self, version="2.0", fmuType="me_cs", fileNamePrefix=" Date: Mon, 7 Apr 2025 16:15:55 +0200 Subject: [PATCH 07/12] Fix flake8 warnings in OMTypedParser.py --- OMPython/OMTypedParser.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OMPython/OMTypedParser.py b/OMPython/OMTypedParser.py index b4f0d249f..7a9d79b42 100644 --- a/OMPython/OMTypedParser.py +++ b/OMPython/OMTypedParser.py @@ -59,6 +59,7 @@ import sys + def convertNumbers(s, l, toks): n = toks[0] try: @@ -75,7 +76,8 @@ def convertString2(s, s2): tmp = tmp.replace("\n", "\\n") tmp = tmp.replace("\r", "\\r") tmp = tmp.replace("\t", "\\t") - return "'"+tmp+"'"; + return "'"+tmp+"'" + def convertString(s, s2): return s2[0].replace("\\\"", '"') @@ -89,7 +91,6 @@ def convertTuple(t): return tuple(t[0]) - def evaluateExpression(s, loc, toks): # Convert the tokens (ParseResults) into a string expression flat_list = [item for sublist in toks[0] for item in sublist] @@ -100,6 +101,7 @@ def evaluateExpression(s, loc, toks): except Exception: return expr + # Number parsing (supports arithmetic expressions in dimensions) (e.g., {1 + 1, 1}) arrayDimension = infixNotation( Word(alphas + "_", alphanums + "_") | Word(nums), @@ -123,7 +125,7 @@ def evaluateExpression(s, loc, toks): Optional('.' + Word(nums)) + Optional(Word('eE', exact=1) + Word(nums + '+-', nums))) -#ident = Word(alphas + "_", alphanums + "_") | Combine("'" + Word(alphanums + "!#$%&()*+,-./:;<>=?@[]^{}|~ ") + "'") +# ident = Word(alphas + "_", alphanums + "_") | Combine("'" + Word(alphanums + "!#$%&()*+,-./:;<>=?@[]^{}|~ ") + "'") ident = Word(alphas + "_", alphanums + "_") | QuotedString(quoteChar='\'', escChar='\\').setParseAction(convertString2) fqident = Forward() fqident << ((ident + "." + fqident) | ident) @@ -143,7 +145,7 @@ def evaluateExpression(s, loc, toks): def parseString(string): res = omcGrammar.parseString(string) if len(res) == 0: - return + return return res[0] From df5507434dcc60792c4ba6827f0053ecdc478d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 16:24:29 +0200 Subject: [PATCH 08/12] Fix flake8 warnings in OMParser/__init__.py --- OMPython/OMParser/__init__.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/OMPython/OMParser/__init__.py b/OMPython/OMParser/__init__.py index 9bfa7688a..345bc5e4c 100755 --- a/OMPython/OMParser/__init__.py +++ b/OMPython/OMParser/__init__.py @@ -207,8 +207,6 @@ def delete_elements(strings): def make_subset_sets(strings, name): - index = 0 - anchor = 0 main_set_name = "SET1" subset_name = "Subset1" set_name = "Set1" @@ -285,8 +283,6 @@ def make_subset_sets(strings, name): def make_sets(strings, name): if strings == "{}": return - index = 0 - anchor = 0 main_set_name = "SET1" set_name = "Set1" @@ -415,7 +411,6 @@ def get_inner_sets(strings, for_this, name): def make_elements(strings): - original_string = strings index = 0 main_set_name = "SET1" @@ -563,7 +558,6 @@ def skip_all_inner_sets(position): max_count = main_count last_set = 0 last_subset = 0 - last_brace = 0 pos = position while pos < len(string): @@ -616,7 +610,6 @@ def skip_all_inner_sets(position): break elif ch == "(": brace_count += 1 - brace_start = position position += 1 while position < end_of_main_set: s = string[position] @@ -625,7 +618,6 @@ def skip_all_inner_sets(position): elif s == ")": brace_count -= 1 if brace_count == 0: - last_brace = position break elif s == "=" and string[position + 1] == "{": indx = position + 2 @@ -672,7 +664,6 @@ def skip_all_inner_sets(position): break elif ch == "(": brace_count += 1 - brace_start = position position += 1 while position < end_of_main_set: s = string[position] @@ -681,13 +672,11 @@ def skip_all_inner_sets(position): elif s == ")": brace_count -= 1 if brace_count == 0: - last_brace = position break position += 1 position += 1 elif char == "(": brace_count += 1 - brace_start = position position += 1 while position < end_of_main_set: s = string[position] @@ -696,7 +685,6 @@ def skip_all_inner_sets(position): elif s == ")": brace_count -= 1 if brace_count == 0: - last_brace = position break position += 1 From 5da54fc8a57bbb26afe6f4e3fcccb0c8625b1aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 16:31:11 +0200 Subject: [PATCH 09/12] Remove dependency on future I don't think this is needed now that python_requires is >=3.8. --- OMPython/OMParser/__init__.py | 5 ----- OMPython/OMTypedParser.py | 5 ----- OMPython/__init__.py | 10 ++-------- setup.py | 1 - tests/test_OMParser.py | 6 ------ tests/test_typedParser.py | 6 ------ 6 files changed, 2 insertions(+), 31 deletions(-) diff --git a/OMPython/OMParser/__init__.py b/OMPython/OMParser/__init__.py index 345bc5e4c..f1708947d 100755 --- a/OMPython/OMParser/__init__.py +++ b/OMPython/OMParser/__init__.py @@ -32,11 +32,6 @@ Version: 1.0 """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from builtins import int, range - import sys result = dict() diff --git a/OMPython/OMTypedParser.py b/OMPython/OMTypedParser.py index 7a9d79b42..28807a920 100644 --- a/OMPython/OMTypedParser.py +++ b/OMPython/OMTypedParser.py @@ -1,10 +1,5 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from builtins import int, range - __author__ = "Anand Kalaiarasi Ganeson, ganan642@student.liu.se, 2012-03-19, and Martin Sjölund" __license__ = """ This file is part of OpenModelica. diff --git a/OMPython/__init__.py b/OMPython/__init__.py index b0b65180f..f4a59334b 100644 --- a/OMPython/__init__.py +++ b/OMPython/__init__.py @@ -7,13 +7,7 @@ omc.sendExpression("command") """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from future.utils import with_metaclass -from builtins import int, range import shutil - import abc import csv import getpass @@ -138,7 +132,7 @@ def _get_omc_path(self): raise -class OMCSessionBase(with_metaclass(abc.ABCMeta, object)): +class OMCSessionBase(metaclass=abc.ABCMeta): def __init__(self, readonly=False): self.readonly = readonly @@ -652,7 +646,7 @@ class ModelicaSystemError(Exception): pass -class ModelicaSystem(object): +class ModelicaSystem: def __init__(self, fileName=None, modelName=None, lmodel=None, commandLineOptions=None, variableFilter=None, customBuildDirectory=None, verbose=True, raiseerrors=False, omhome: str = None, session: OMCSessionBase = None): # 1 diff --git a/setup.py b/setup.py index c5eb6ce69..b57d5165a 100755 --- a/setup.py +++ b/setup.py @@ -15,7 +15,6 @@ url='http://openmodelica.org/', packages=OMPython_packages, install_requires=[ - 'future', 'numpy', 'psutil', 'pyparsing', diff --git a/tests/test_OMParser.py b/tests/test_OMParser.py index 79ba83b18..74aba7896 100644 --- a/tests/test_OMParser.py +++ b/tests/test_OMParser.py @@ -1,10 +1,4 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from builtins import int - from OMPython import OMParser - import unittest typeCheck = OMParser.typeCheck diff --git a/tests/test_typedParser.py b/tests/test_typedParser.py index fe76fef53..4024285e6 100644 --- a/tests/test_typedParser.py +++ b/tests/test_typedParser.py @@ -1,10 +1,4 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from builtins import int - from OMPython import OMTypedParser - import unittest typeCheck = OMTypedParser.parseString From 380c1fa6585f76412e8bd9f7b201a3c368b52a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 17:12:03 +0200 Subject: [PATCH 10/12] Switch from setup.py to pyproject.toml pyproject.toml is preferred over setup.py for situations like this: https://packaging.python.org/en/latest/guides/modernize-setup-py-project/ --- pyproject.toml | 34 ++++++++++++++++++++++++++++++++++ setup.py | 31 ------------------------------- 2 files changed, 34 insertions(+), 31 deletions(-) create mode 100644 pyproject.toml delete mode 100755 setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..fa5129805 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,34 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "OMPython" +version = "3.6.0" +description = "OpenModelica-Python API Interface" +readme = "README.md" +authors = [ + {name = "Anand Kalaiarasi Ganeson", email = "ganan642@student.liu.se"}, +] +maintainers = [ + {name = "Adeel Asghar", email = "adeel.asghar@liu.se"}, +] +license = "BSD-3-Clause OR LicenseRef-OSMC-PL-1.2 OR GPL-3.0-only" +requires-python = ">=3.8" +dependencies = [ + "numpy", + "psutil", + "pyparsing", + "pyzmq", +] + +[tool.setuptools] +packages = ["OMPython", "OMPython.OMParser"] + +[project.urls] +Homepage = "http://openmodelica.org/" +Documentation = "https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/ompython.html" +"Source Code" = "https://github.com/OpenModelica/OMPython" +Issues = "https://github.com/OpenModelica/OMPython/issues" +"Release Notes" = "https://github.com/OpenModelica/OMPython/releases" +Download = "https://pypi.org/project/OMPython/#files" diff --git a/setup.py b/setup.py deleted file mode 100755 index b57d5165a..000000000 --- a/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -from setuptools import setup - -OMPython_packages = ['OMPython', 'OMPython.OMParser'] - -setup(name='OMPython', - version='3.6.0', - description='OpenModelica-Python API Interface', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - author='Anand Kalaiarasi Ganeson', - author_email='ganan642@student.liu.se', - maintainer='Adeel Asghar', - maintainer_email='adeel.asghar@liu.se', - license="BSD, OSMC-PL 1.2, GPL (user's choice)", - url='http://openmodelica.org/', - packages=OMPython_packages, - install_requires=[ - 'numpy', - 'psutil', - 'pyparsing', - 'pyzmq' - ], - python_requires='>=3.8', - project_urls={ - 'documentation': 'https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/ompython.html', - 'source': 'https://github.com/OpenModelica/OMPython', - 'download': 'https://pypi.org/project/OMPython/#files', - 'tracker': 'https://github.com/OpenModelica/OMPython/issues', - 'release notes': 'https://github.com/OpenModelica/OMPython/releases', - }, - ) From 4f3c4a02f95ce4ea46a74fb5dc39ffc761f33adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 17:18:24 +0200 Subject: [PATCH 11/12] Use dependency list from pyproject.toml in CI --- .github/workflows/FMITest.yml | 2 +- .github/workflows/Test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/FMITest.yml b/.github/workflows/FMITest.yml index 60d4e3788..633b79cbc 100644 --- a/.github/workflows/FMITest.yml +++ b/.github/workflows/FMITest.yml @@ -38,7 +38,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install future pyparsing numpy psutil pyzmq pytest pytest-md pytest-emoji + pip install . pytest pytest-md pytest-emoji - name: Set timezone uses: szenius/set-timezone@v2.0 diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index 66f404e53..d93a9fb2c 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -38,7 +38,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install future pyparsing numpy psutil pyzmq pytest pytest-md pytest-emoji + pip install . pytest pytest-md pytest-emoji - name: Set timezone uses: szenius/set-timezone@v2.0 From 15e42604f9f7fd14e12f88cb07725bdce6554e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sluka?= Date: Mon, 7 Apr 2025 17:24:48 +0200 Subject: [PATCH 12/12] Run flake8 in CI --- .github/workflows/Test.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index d93a9fb2c..0490b77df 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -38,13 +38,17 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install . pytest pytest-md pytest-emoji + pip install . pytest pytest-md pytest-emoji flake8 - name: Set timezone uses: szenius/set-timezone@v2.0 with: timezoneLinux: 'Europe/Berlin' + - name: Lint with flake8 + run: | + flake8 . --count --statistics + - name: Run pytest uses: pavelzw/pytest-action@v2 with: