From f0d5349e92a99e2edf000d35c41cb693d955e2ae Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 00:29:55 +0200 Subject: [PATCH 01/12] [ModelicaSystemCmd] use OMCPath for file system interactions --- OMPython/OMCSession.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index a7c67841..d0613445 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -461,18 +461,18 @@ class OMCPathCompatibilityWindows(pathlib.WindowsPath, OMCPathCompatibility): @dataclasses.dataclass class OMCSessionRunData: - # TODO: rename OMCExcecutableModelData """ Data class to store the command line data for running a model executable in the OMC environment. All data should be defined for the environment, where OMC is running (local, docker or WSL) """ - # cmd_path is the expected working directory + # cmd_path is based on the selected OMCProcess definition cmd_path: str cmd_model_name: str # command line arguments for the model executable cmd_args: list[str] # result file with the simulation output + # cmd_result_path is based on the selected OMCProcess definition cmd_result_path: str # command prefix data (as list of strings); needed for docker or WSL @@ -601,13 +601,13 @@ def omcpath_tempdir(self, tempdir_base: Optional[OMCPath] = None) -> OMCPath: return tempdir - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Modify data based on the selected OMCProcess implementation. Needs to be implemented in the subclasses. """ - return self.omc_process.omc_run_data_update(omc_run_data=omc_run_data) + return self.omc_process.omc_run_data_update(omc_run_data=omc_run_data, session=self) @staticmethod def run_model_executable(cmd_run_data: OMCSessionRunData) -> int: @@ -655,8 +655,11 @@ def execute(self, command: str): return self.sendExpression(command, parsed=False) def sendExpression(self, command: str, parsed: bool = True) -> Any: + """ + Send an expression to the OMC server and return the result. + """ if self.omc_zmq is None: - raise OMCSessionException("No OMC running. Create a new instance of OMCSessionZMQ!") + raise OMCSessionException("No OMC running. Create a new instance of OMCProcess!") logger.debug("sendExpression(%r, parsed=%r)", command, parsed) @@ -841,7 +844,7 @@ def _get_portfile_path(self) -> Optional[pathlib.Path]: return portfile_path @abc.abstractmethod - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. @@ -862,7 +865,7 @@ def __init__( super().__init__() self._omc_port = omc_port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -952,7 +955,7 @@ def _omc_port_get(self) -> str: return port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -1109,7 +1112,7 @@ def get_docker_container_id(self) -> str: return self._dockerCid - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -1430,7 +1433,7 @@ def _omc_port_get(self) -> str: return port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ From 0c7c0086f88ba9db5d23fac0a6dea6d04c5149c3 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 00:43:11 +0200 Subject: [PATCH 02/12] [OMCProcessDockerHelper] implement omc_run_data_update() --- OMPython/OMCSession.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index d0613445..a48fa47e 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -1116,7 +1116,24 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ - raise OMCSessionException("OMCProcessDocker* does not support omc_run_data_update()!") + omc_run_data_copy = dataclasses.replace(omc_run_data) + + omc_run_data_copy.cmd_prefix = ( + [ + "docker", "exec", + "--user", str(self._getuid()), + ] + + self._dockerExtraArgs + + [self._dockerCid] + ) + + cmd_path = session.omcpath(omc_run_data_copy.cmd_path) + cmd_model_executable = cmd_path / omc_run_data_copy.cmd_model_name + if not cmd_model_executable.is_file(): + raise OMCSessionException(f"Application file path not found: {cmd_model_executable}") + omc_run_data_copy.cmd_model_executable = cmd_model_executable.as_posix() + + return omc_run_data_copy class OMCProcessDocker(OMCProcessDockerHelper): From 24879ccde0924f6cb47ac711047500d04a683bc5 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 00:43:25 +0200 Subject: [PATCH 03/12] [OMCProcessWSL] implement omc_run_data_update() --- OMPython/OMCSession.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index a48fa47e..5bf7a8c5 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -1387,25 +1387,30 @@ def __init__( super().__init__(timeout=timeout) - # get wsl base command - self._wsl_cmd = ['wsl'] - if isinstance(wsl_distribution, str): - self._wsl_cmd += ['--distribution', wsl_distribution] - if isinstance(wsl_user, str): - self._wsl_cmd += ['--user', wsl_user] - self._wsl_cmd += ['--'] - # where to find OpenModelica self._wsl_omc = wsl_omc + # store WSL distribution and user + self._wsl_distribution = wsl_distribution + self._wsl_user = wsl_user # start up omc executable, which is waiting for the ZMQ connection self._omc_process = self._omc_process_get() # connect to the running omc instance using ZMQ self._omc_port = self._omc_port_get() + def _wsl_cmd(self) -> list[str]: # get wsl base command + wsl_cmd = ['wsl'] + if isinstance(self._wsl_distribution, str): + wsl_cmd += ['--distribution', self._wsl_distribution] + if isinstance(self._wsl_user, str): + wsl_cmd += ['--user', self._wsl_user] + wsl_cmd += ['--'] + + return wsl_cmd + def _omc_process_get(self) -> subprocess.Popen: my_env = os.environ.copy() - omc_command = self._wsl_cmd + [ + omc_command = self._wsl_cmd() + [ self._wsl_omc, "--locale=C", "--interactive=zmq", @@ -1428,7 +1433,7 @@ def _omc_port_get(self) -> str: omc_portfile_path = self._get_portfile_path() if omc_portfile_path is not None: output = subprocess.check_output( - args=self._wsl_cmd + ["cat", omc_portfile_path.as_posix()], + args=self._wsl_cmd() + ["cat", omc_portfile_path.as_posix()], stderr=subprocess.DEVNULL, ) port = output.decode().strip() @@ -1454,4 +1459,14 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ - raise OMCSessionException("OMCProcessWSL does not support omc_run_data_update()!") + omc_run_data_copy = dataclasses.replace(omc_run_data) + + omc_run_data_copy.cmd_prefix = self._wsl_cmd() + + cmd_path = session.omcpath(omc_run_data_copy.cmd_path) + cmd_model_executable = cmd_path / omc_run_data_copy.cmd_model_name + if not cmd_model_executable.is_file(): + raise OMCSessionException(f"Application file path not found: {cmd_model_executable}") + omc_run_data_copy.cmd_model_executable = cmd_model_executable.as_posix() + + return omc_run_data_copy From deca0b1c3557b65f92f7cfbabd583ded36d0cadf Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 12:57:34 +0200 Subject: [PATCH 04/12] [OMCProcessDockerHelper] define work directory in docker --- OMPython/OMCSession.py | 1 + 1 file changed, 1 insertion(+) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 5bf7a8c5..83d5c8ba 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -1122,6 +1122,7 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi [ "docker", "exec", "--user", str(self._getuid()), + "--workdir", omc_run_data_copy.cmd_path, ] + self._dockerExtraArgs + [self._dockerCid] From 998eab0577d0eb9f5f1ed64f56f01e4a01722ec2 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 12:58:41 +0200 Subject: [PATCH 05/12] [OMCProcessWSL] define work directory for WSL --- OMPython/OMCSession.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 83d5c8ba..95f177fc 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -1398,12 +1398,15 @@ def __init__( # connect to the running omc instance using ZMQ self._omc_port = self._omc_port_get() - def _wsl_cmd(self) -> list[str]: # get wsl base command + def _wsl_cmd(self, wsl_cwd: Optional[str] = None) -> list[str]: + # get wsl base command wsl_cmd = ['wsl'] if isinstance(self._wsl_distribution, str): wsl_cmd += ['--distribution', self._wsl_distribution] if isinstance(self._wsl_user, str): wsl_cmd += ['--user', self._wsl_user] + if isinstance(wsl_cwd, str): + wsl_cmd += ['--cd', wsl_cwd] wsl_cmd += ['--'] return wsl_cmd @@ -1462,7 +1465,7 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi """ omc_run_data_copy = dataclasses.replace(omc_run_data) - omc_run_data_copy.cmd_prefix = self._wsl_cmd() + omc_run_data_copy.cmd_prefix = self._wsl_cmd(wsl_cwd=omc_run_data.cmd_path) cmd_path = session.omcpath(omc_run_data_copy.cmd_path) cmd_model_executable = cmd_path / omc_run_data_copy.cmd_model_name From c4bb0b0dc45d0524aa0684e1a0eb38abe568cee8 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 12:59:57 +0200 Subject: [PATCH 06/12] [OMCSessionRunData] update docstring and comments --- OMPython/OMCSession.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 95f177fc..5fc6140a 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -466,13 +466,12 @@ class OMCSessionRunData: All data should be defined for the environment, where OMC is running (local, docker or WSL) """ - # cmd_path is based on the selected OMCProcess definition + # cmd_path is the expected working directory cmd_path: str cmd_model_name: str # command line arguments for the model executable cmd_args: list[str] # result file with the simulation output - # cmd_result_path is based on the selected OMCProcess definition cmd_result_path: str # command prefix data (as list of strings); needed for docker or WSL From e4be9fdf647a20443855ef91bab55cfa28123bc4 Mon Sep 17 00:00:00 2001 From: syntron Date: Sat, 12 Jul 2025 13:42:05 +0200 Subject: [PATCH 07/12] [test_ModelicaSystem] include test of ModelicaSystem using docker --- tests/test_ModelicaSystem.py | 46 +++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 05a0495a..62b8c616 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -2,20 +2,36 @@ import os import pathlib import pytest +import sys import tempfile import numpy as np +skip_on_windows = pytest.mark.skipif( + sys.platform.startswith("win"), + reason="OpenModelica Docker image is Linux-only; skipping on Windows.", +) + +skip_python_older_312 = pytest.mark.skipif( + sys.version_info < (3, 12), + reason="OMCPath(non-local) only working for Python >= 3.12.", +) + @pytest.fixture -def model_firstorder(tmp_path): - mod = tmp_path / "M.mo" - mod.write_text("""model M +def model_firstorder_content(): + return ("""model M Real x(start = 1, fixed = true); parameter Real a = -1; equation der(x) = x*a; end M; """) + + +@pytest.fixture +def model_firstorder(tmp_path, model_firstorder_content): + mod = tmp_path / "M.mo" + mod.write_text(model_firstorder_content) return mod @@ -113,9 +129,33 @@ def test_customBuildDirectory(tmp_path, model_firstorder): assert result_file.is_file() +@skip_on_windows +@skip_python_older_312 +def test_getSolutions_docker(model_firstorder_content): + omcp = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal") + omc = OMPython.OMCSessionZMQ(omc_process=omcp) + + modelpath = omc.omcpath_tempdir() / 'M.mo' + modelpath.write_text(model_firstorder_content) + + file_path = pathlib.Path(modelpath) + mod = OMPython.ModelicaSystem( + fileName=file_path, + modelName="M", + omc_process=omc.omc_process, + ) + + _run_getSolutions(mod) + + def test_getSolutions(model_firstorder): filePath = model_firstorder.as_posix() mod = OMPython.ModelicaSystem(filePath, "M") + + _run_getSolutions(mod) + + +def _run_getSolutions(mod): x0 = 1 a = -1 tau = -1 / a From 9fc17f4982a9a39ac747b19081459380dd07ee30 Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 27 Jul 2025 00:32:02 +0200 Subject: [PATCH 08/12] [OMCSessionZMQ] no session for omc_run_data_update() --- OMPython/OMCSession.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 5fc6140a..edfd616e 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -600,7 +600,7 @@ def omcpath_tempdir(self, tempdir_base: Optional[OMCPath] = None) -> OMCPath: return tempdir - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Modify data based on the selected OMCProcess implementation. From bae6cd89316ba92ae8fbe0af5bc209d7367c732b Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 27 Jul 2025 00:42:01 +0200 Subject: [PATCH 09/12] [OMCProcess] remove session argument for OMCProcess.omc_run_data_update() * no dependency loop OMCsessionZMQ => OMCProcess* => OMCSessionZMQ * check if model executable exists will be handled via ModelicaSystemCmd --- OMPython/OMCSession.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index edfd616e..b1097db6 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -606,7 +606,7 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunD Needs to be implemented in the subclasses. """ - return self.omc_process.omc_run_data_update(omc_run_data=omc_run_data, session=self) + return self.omc_process.omc_run_data_update(omc_run_data=omc_run_data) @staticmethod def run_model_executable(cmd_run_data: OMCSessionRunData) -> int: @@ -843,7 +843,7 @@ def _get_portfile_path(self) -> Optional[pathlib.Path]: return portfile_path @abc.abstractmethod - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. @@ -864,7 +864,7 @@ def __init__( super().__init__() self._omc_port = omc_port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -954,7 +954,7 @@ def _omc_port_get(self) -> str: return port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -1111,7 +1111,7 @@ def get_docker_container_id(self) -> str: return self._dockerCid - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -1127,10 +1127,8 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi + [self._dockerCid] ) - cmd_path = session.omcpath(omc_run_data_copy.cmd_path) + cmd_path = pathlib.PurePosixPath(omc_run_data_copy.cmd_path) cmd_model_executable = cmd_path / omc_run_data_copy.cmd_model_name - if not cmd_model_executable.is_file(): - raise OMCSessionException(f"Application file path not found: {cmd_model_executable}") omc_run_data_copy.cmd_model_executable = cmd_model_executable.as_posix() return omc_run_data_copy @@ -1458,7 +1456,7 @@ def _omc_port_get(self) -> str: return port - def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessionZMQ) -> OMCSessionRunData: + def omc_run_data_update(self, omc_run_data: OMCSessionRunData) -> OMCSessionRunData: """ Update the OMCSessionRunData object based on the selected OMCProcess implementation. """ @@ -1466,10 +1464,8 @@ def omc_run_data_update(self, omc_run_data: OMCSessionRunData, session: OMCSessi omc_run_data_copy.cmd_prefix = self._wsl_cmd(wsl_cwd=omc_run_data.cmd_path) - cmd_path = session.omcpath(omc_run_data_copy.cmd_path) + cmd_path = pathlib.PurePosixPath(omc_run_data_copy.cmd_path) cmd_model_executable = cmd_path / omc_run_data_copy.cmd_model_name - if not cmd_model_executable.is_file(): - raise OMCSessionException(f"Application file path not found: {cmd_model_executable}") omc_run_data_copy.cmd_model_executable = cmd_model_executable.as_posix() return omc_run_data_copy From b5879e4625b0ece170ced8cf933734764432a993 Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 3 Aug 2025 22:23:02 +0200 Subject: [PATCH 10/12] [ModelicaSystem.buildModel] check if executable exists via ModelicaSystemCmd --- OMPython/ModelicaSystem.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 22cecc1b..e80d9a9e 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -515,6 +515,20 @@ def buildModel(self, variableFilter: Optional[str] = None): buildModelResult = self._requestApi(apiName="buildModel", entity=self._model_name, properties=var_filter) logger.debug("OM model build result: %s", buildModelResult) + # check if the executable exists ... + om_cmd = ModelicaSystemCmd( + session=self._getconn, + runpath=self.getWorkDirectory(), + modelname=self._model_name, + timeout=5.0, + ) + # ... by running it - output help for command help + om_cmd.arg_set(key="help", val="help") + cmd_definition = om_cmd.definition() + returncode = self._getconn.run_model_executable(cmd_run_data=cmd_definition) + if returncode != 0: + raise ModelicaSystemError("Model executable not working!") + xml_file = self._getconn.omcpath(buildModelResult[0]).parent / buildModelResult[1] self._xmlparse(xml_file=xml_file) From 14629eb8c8a30653054c03c0aefc4bb1f0a7ea1f Mon Sep 17 00:00:00 2001 From: syntron Date: Thu, 30 Oct 2025 21:46:34 +0100 Subject: [PATCH 11/12] [ModelicaSystem*] rebase cleanup --- OMPython/ModelicaSystem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index e80d9a9e..723514e7 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -43,7 +43,7 @@ import warnings import xml.etree.ElementTree as ET -from OMPython.OMCSession import OMCSessionException, OMCSessionRunData, OMCSessionZMQ, OMCProcessLocal, OMCPath +from OMPython.OMCSession import OMCSessionException, OMCSessionRunData, OMCSessionZMQ, OMCProcess, OMCPath # define logger using the current module name as ID logger = logging.getLogger(__name__) @@ -262,7 +262,9 @@ def definition(self) -> OMCSessionRunData: cmd_timeout=self._timeout, ) - omc_run_data_updated = self._session.omc_run_data_update(omc_run_data=omc_run_data) + omc_run_data_updated = self._session.omc_run_data_update( + omc_run_data=omc_run_data, + ) return omc_run_data_updated @@ -315,7 +317,7 @@ def __init__( variableFilter: Optional[str] = None, customBuildDirectory: Optional[str | os.PathLike] = None, omhome: Optional[str] = None, - omc_process: Optional[OMCProcessLocal] = None, + omc_process: Optional[OMCProcess] = None, build: bool = True, ) -> None: """Initialize, load and build a model. @@ -380,8 +382,6 @@ def __init__( self._linearized_states: list[str] = [] # linearization states list if omc_process is not None: - if not isinstance(omc_process, OMCProcessLocal): - raise ModelicaSystemError("Invalid (local) omc process definition provided!") self._getconn = OMCSessionZMQ(omc_process=omc_process) else: self._getconn = OMCSessionZMQ(omhome=omhome) From 2d2aba16490dcc4e34cdec241d0597020611aeb8 Mon Sep 17 00:00:00 2001 From: syntron Date: Wed, 5 Nov 2025 15:16:28 +0100 Subject: [PATCH 12/12] [ModelicaSystem] add missing import --- OMPython/ModelicaSystem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 723514e7..b1f9a32e 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -43,7 +43,8 @@ import warnings import xml.etree.ElementTree as ET -from OMPython.OMCSession import OMCSessionException, OMCSessionRunData, OMCSessionZMQ, OMCProcess, OMCPath +from OMPython.OMCSession import (OMCSessionException, OMCSessionRunData, OMCSessionZMQ, + OMCProcess, OMCProcessLocal, OMCPath) # define logger using the current module name as ID logger = logging.getLogger(__name__)