From 5b670ae60ead3aa6b1f343cfde5aed2783bdd4ce Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 8 Feb 2026 21:05:21 +0100 Subject: [PATCH 1/4] (D006) small fixes in ModelicaSystem [ModelicaSystemABC] reorder code in __init__() [ModelicaSystem*] linter fixes --- OMPython/ModelicaSystem.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 0eea5f15..07b5b5a2 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -383,22 +383,21 @@ def __init__( self._linearized_outputs: list[str] = [] # linearization output list self._linearized_states: list[str] = [] # linearization states list - self._session = session - - # get OpenModelica version - version_str = self._session.get_version() - self._version = self._parse_om_version(version=version_str) - self._simulated = False # True if the model has already been simulated self._result_file: Optional[OMPathABC] = None # for storing result file - self._work_dir: OMPathABC = self.setWorkDirectory(work_directory) - self._model_name: Optional[str] = None self._libraries: Optional[list[str | tuple[str, str]]] = None self._file_name: Optional[OMPathABC] = None self._variable_filter: Optional[str] = None + self._session = session + # get OpenModelica version + version_str = self._session.get_version() + self._version = self._parse_om_version(version=version_str) + + self._work_dir: OMPathABC = self.setWorkDirectory(work_directory) + def get_session(self) -> OMSessionABC: """ Return the OMC session used for this class. @@ -468,6 +467,8 @@ def _xmlparse(self, xml_file: OMPathABC): xml_content = xml_file.read_text() tree = ET.ElementTree(ET.fromstring(xml_content)) root = tree.getroot() + if root is None: + raise ModelicaSystemError(f"Cannot read XML file: {xml_file}") for attr in root.iter('DefaultExperiment'): for key in ("startTime", "stopTime", "stepSize", "tolerance", "solver", "outputFormat"): @@ -1935,7 +1936,7 @@ def getSolutions( self, varList: Optional[str | list[str]] = None, resultfile: Optional[str | os.PathLike] = None, - ) -> tuple[str] | np.ndarray: + ) -> tuple[str, ...] | np.ndarray: """Extract simulation results from a result data file. Args: @@ -1984,7 +1985,8 @@ def getSolutions( result_vars = self.sendExpression(expr=f'readSimulationResultVars("{result_file.as_posix()}")') self.sendExpression(expr="closeSimulationResultFile()") if varList is None: - return result_vars + var_list = [str(var) for var in result_vars] + return tuple(var_list) if isinstance(varList, str): var_list_checked = [varList] @@ -2064,6 +2066,8 @@ def convertFmu2Mo( raise ModelicaSystemError(f"Missing FMU file: {fmu_path.as_posix()}") filename = self._requestApi(apiName='importFMU', entity=fmu_path.as_posix()) + if not isinstance(filename, str): + raise ModelicaSystemError(f"Invalid return value for the FMU filename: {filename}") filepath = self.getWorkDirectory() / filename # report proper error message @@ -2106,7 +2110,9 @@ def optimize(self) -> dict[str, Any]: """ properties = ','.join(f"{key}={val}" for key, val in self._optimization_options.items()) self.set_command_line_options("-g=Optimica") - return self._requestApi(apiName='optimize', entity=self._model_name, properties=properties) + retval = self._requestApi(apiName='optimize', entity=self._model_name, properties=properties) + retval = cast(dict, retval) + return retval class ModelicaSystem(ModelicaSystemOMC): From b477a94cadcc1637b0171b8ca2ab4293864cf5a8 Mon Sep 17 00:00:00 2001 From: syntron Date: Mon, 9 Feb 2026 21:23:45 +0100 Subject: [PATCH 2/4] (D008) add v4.0.0 compatibility layer [OMTypedParser] compatibility layer [__init__/OMCSession] prepare compatibility layer [ModelicaSystem] define as compatibility layer [ModelicaSystemCmd] define as compatibility layer --- OMPython/ModelicaSystem.py | 179 +++++++++++++++++++++++++++++ OMPython/OMCSession.py | 8 ++ OMPython/OMTypedParser.py | 3 + OMPython/__init__.py | 13 +++ tests/test_ModelicaSystemRunner.py | 2 +- 5 files changed, 204 insertions(+), 1 deletion(-) diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index 07b5b5a2..03fd060b 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -2120,6 +2120,138 @@ class ModelicaSystem(ModelicaSystemOMC): Compatibility class. """ + def __init__( + self, + fileName: Optional[str | os.PathLike | pathlib.Path] = None, + modelName: Optional[str] = None, + lmodel: Optional[list[str | tuple[str, str]]] = None, + commandLineOptions: Optional[list[str]] = None, + variableFilter: Optional[str] = None, + customBuildDirectory: Optional[str | os.PathLike] = None, + omhome: Optional[str] = None, + omc_process: Optional[OMCSessionLocal] = None, + build: bool = True, + ) -> None: + super().__init__( + command_line_options=commandLineOptions, + work_directory=customBuildDirectory, + omhome=omhome, + session=omc_process, + ) + self.model( + model_name=modelName, + model_file=fileName, + libraries=lmodel, + variable_filter=variableFilter, + build=build, + ) + self._getconn = self._session + + def setCommandLineOptions(self, commandLineOptions: str): + super().set_command_line_options(command_line_option=commandLineOptions) + + def setContinuous( # type: ignore[override] + self, + cvals: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(cvals, dict): + return super().setContinuous(**cvals) + raise ModelicaSystemError("Only dict input supported for setContinuous()") + + def setParameters( # type: ignore[override] + self, + pvals: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(pvals, dict): + return super().setParameters(**pvals) + raise ModelicaSystemError("Only dict input supported for setParameters()") + + def setOptimizationOptions( # type: ignore[override] + self, + optimizationOptions: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(optimizationOptions, dict): + return super().setOptimizationOptions(**optimizationOptions) + raise ModelicaSystemError("Only dict input supported for setOptimizationOptions()") + + def setInputs( # type: ignore[override] + self, + name: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(name, dict): + return super().setInputs(**name) + raise ModelicaSystemError("Only dict input supported for setInputs()") + + def setSimulationOptions( # type: ignore[override] + self, + simOptions: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(simOptions, dict): + return super().setSimulationOptions(**simOptions) + raise ModelicaSystemError("Only dict input supported for setSimulationOptions()") + + def setLinearizationOptions( # type: ignore[override] + self, + linearizationOptions: str | list[str] | dict[str, Any], + ) -> bool: + if isinstance(linearizationOptions, dict): + return super().setLinearizationOptions(**linearizationOptions) + raise ModelicaSystemError("Only dict input supported for setLinearizationOptions()") + + def getContinuous( + self, + names: Optional[str | list[str]] = None, + ): + retval = super().getContinuous(names=names) + if self._simulated: + return retval + + if isinstance(retval, dict): + retval2: dict = {} + for key, val in retval.items(): + if np.isnan(val): + retval2[key] = None + else: + retval2[key] = str(val) + return retval2 + if isinstance(retval, list): + retval3: list[str | None] = [] + for val in retval: + if np.isnan(val): + retval3.append(None) + else: + retval3.append(str(val)) + return retval3 + + raise ModelExecutionException("Invalid data!") + + def getOutputs( + self, + names: Optional[str | list[str]] = None, + ): + retval = super().getOutputs(names=names) + if self._simulated: + return retval + + if isinstance(retval, dict): + retval2: dict = {} + for key, val in retval.items(): + if np.isnan(val): + retval2[key] = None + else: + retval2[key] = str(val) + return retval2 + if isinstance(retval, list): + retval3: list[str | None] = [] + for val in retval: + if np.isnan(val): + retval3.append(None) + else: + retval3.append(str(val)) + return retval3 + + raise ModelExecutionException("Invalid data!") + class ModelicaDoEABC(metaclass=abc.ABCMeta): """ @@ -2691,3 +2823,50 @@ def _prepare_structure_parameters( "pre-compiled binary of model.") return {} + + +class ModelicaSystemCmd(ModelExecutionCmd): + # TODO: docstring + + def __init__( + self, + runpath: pathlib.Path, + modelname: str, + timeout: float = 10.0, + ) -> None: + super().__init__( + runpath=runpath, + timeout=timeout, + cmd_prefix=[], + model_name=modelname, + ) + + def get_exe(self) -> pathlib.Path: + """Get the path to the compiled model executable.""" + # TODO: move to the top + import platform + + path_run = pathlib.Path(self._runpath) + if platform.system() == "Windows": + path_exe = path_run / f"{self._model_name}.exe" + else: + path_exe = path_run / self._model_name + + if not path_exe.exists(): + raise ModelicaSystemError(f"Application file path not found: {path_exe}") + + return path_exe + + def get_cmd(self) -> list: + """Get a list with the path to the executable and all command line args. + + This can later be used as an argument for subprocess.run(). + """ + + cmdl = [self.get_exe().as_posix()] + self.get_cmd_args() + + return cmdl + + def run(self): + cmd_definition = self.definition() + return cmd_definition.run() diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index 83b5bb32..731005f1 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -2154,3 +2154,11 @@ def omcpath_tempdir(self, tempdir_base: Optional[OMPathABC] = None) -> OMPathABC def sendExpression(self, expr: str, parsed: bool = True) -> Any: raise OMCSessionException(f"{self.__class__.__name__} does not uses an OMC server!") + + +DummyPopen = DockerPopen +OMCProcessLocal = OMCSessionLocal +OMCProcessPort = OMCSessionPort +OMCProcessDocker = OMCSessionDocker +OMCProcessDockerContainer = OMCSessionDockerContainer +OMCProcessWSL = OMCSessionWSL diff --git a/OMPython/OMTypedParser.py b/OMPython/OMTypedParser.py index 06912221..9fe810e0 100644 --- a/OMPython/OMTypedParser.py +++ b/OMPython/OMTypedParser.py @@ -161,3 +161,6 @@ def om_parser_typed(string) -> Any: if len(res) == 0: return None return res[0] + + +parseString = om_parser_typed diff --git a/OMPython/__init__.py b/OMPython/__init__.py index 4dc2f974..c12f8524 100644 --- a/OMPython/__init__.py +++ b/OMPython/__init__.py @@ -23,6 +23,8 @@ ModelicaDoERunner, doe_get_solutions, + + ModelicaSystemCmd, ) from OMPython.OMCSession import ( OMPathABC, @@ -47,6 +49,11 @@ OMCSessionWSL, OMCSessionZMQ, + + OMCProcessLocal, + OMCProcessPort, + OMCProcessDocker, + OMCProcessDockerContainer, ) # global names imported if import 'from OMPython import *' is used @@ -58,6 +65,7 @@ 'ModelicaSystem', 'ModelicaSystemOMC', + 'ModelicaSystemCmd', 'ModelExecutionCmd', 'ModelicaSystemDoE', 'ModelicaDoEOMC', @@ -87,4 +95,9 @@ 'OMCSessionWSL', 'OMCSessionZMQ', + + 'OMCProcessLocal', + 'OMCProcessPort', + 'OMCProcessDocker', + 'OMCProcessDockerContainer', ] diff --git a/tests/test_ModelicaSystemRunner.py b/tests/test_ModelicaSystemRunner.py index 35541c99..ec9d734d 100644 --- a/tests/test_ModelicaSystemRunner.py +++ b/tests/test_ModelicaSystemRunner.py @@ -39,7 +39,7 @@ def param(): def test_runner(model_firstorder, param): # create a model using ModelicaSystem - mod = OMPython.ModelicaSystem() + mod = OMPython.ModelicaSystemOMC() mod.model( model_file=model_firstorder, model_name="M", From e568703c8c518257b6d3efde05cfd748521e8dcd Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 8 Feb 2026 20:48:16 +0100 Subject: [PATCH 3/4] (D007) define unittest / workflow for v4.0.0 add workflow to run unittests in ./tests tests from v4.0.0 fix test_linearization from v4.0.0 flake8 error: test_linearization.py:71:5: E741 ambiguous variable name 'l' this was fixed in: 'update usage of flake8 (#357)' (SHA1: 70cb446f537345c33f024aa44bc107548970ebc4) fix test_ModelicaSystem - needed adaptions: * convert OMCPath to pathlib.Path * use correct exceptions define test workflows for v400 --- .github/workflows/Test_v400.yml | 73 +++++ .github/workflows/Test_v400_py310.yml | 70 +++++ .github/workflows/Test_v4xx.yml | 73 +++++ .pre-commit-config.yaml | 2 +- tests_v400/__init__.py | 0 tests_v400/test_ArrayDimension.py | 19 ++ tests_v400/test_FMIExport.py | 24 ++ tests_v400/test_ModelicaSystem.py | 411 ++++++++++++++++++++++++++ tests_v400/test_ModelicaSystemCmd.py | 51 ++++ tests_v400/test_OMParser.py | 43 +++ tests_v400/test_OMSessionCmd.py | 17 ++ tests_v400/test_ZMQ.py | 70 +++++ tests_v400/test_docker.py | 32 ++ tests_v400/test_linearization.py | 102 +++++++ tests_v400/test_optimization.py | 67 +++++ tests_v400/test_typedParser.py | 53 ++++ 16 files changed, 1106 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/Test_v400.yml create mode 100644 .github/workflows/Test_v400_py310.yml create mode 100644 .github/workflows/Test_v4xx.yml create mode 100644 tests_v400/__init__.py create mode 100644 tests_v400/test_ArrayDimension.py create mode 100644 tests_v400/test_FMIExport.py create mode 100644 tests_v400/test_ModelicaSystem.py create mode 100644 tests_v400/test_ModelicaSystemCmd.py create mode 100644 tests_v400/test_OMParser.py create mode 100644 tests_v400/test_OMSessionCmd.py create mode 100644 tests_v400/test_ZMQ.py create mode 100644 tests_v400/test_docker.py create mode 100644 tests_v400/test_linearization.py create mode 100644 tests_v400/test_optimization.py create mode 100644 tests_v400/test_typedParser.py diff --git a/.github/workflows/Test_v400.yml b/.github/workflows/Test_v400.yml new file mode 100644 index 00000000..2407e060 --- /dev/null +++ b/.github/workflows/Test_v400.yml @@ -0,0 +1,73 @@ +name: Test-v4.0.0 + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + matrix: + # test for: + # * oldest supported version + # * latest available Python version + python-version: ['3.10', '3.14'] + # * Linux using ubuntu-latest + # * Windows using windows-latest + os: ['ubuntu-latest', 'windows-latest'] + # * OM stable - latest stable version + # * OM nightly - latest nightly build + omc-version: ['stable', 'nightly'] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: 'x64' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip build setuptools wheel twine + pip install . pytest pytest-md pytest-emoji pre-commit + + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: 'Europe/Berlin' + + - name: Run pre-commit linters + run: 'pre-commit run --all-files' + + - name: "Set up OpenModelica Compiler" + uses: OpenModelica/setup-openmodelica@v1.0.6 + with: + version: ${{ matrix.omc-version }} + packages: | + omc + libraries: | + 'Modelica 4.0.0' + - run: "omc --version" + + - name: Pull OpenModelica docker image + if: runner.os != 'Windows' + run: docker pull openmodelica/openmodelica:v1.25.0-minimal + + - name: Build wheel and sdist packages + run: python -m build --wheel --sdist --outdir dist + + - name: Check twine + run: python -m twine check dist/* + + - name: Run pytest + uses: pavelzw/pytest-action@v2 + with: + verbose: true + emoji: true + job-summary: true + custom-arguments: '-v ./tests_v400' + click-to-expand: true + report-title: 'Test Report' diff --git a/.github/workflows/Test_v400_py310.yml b/.github/workflows/Test_v400_py310.yml new file mode 100644 index 00000000..dbe635be --- /dev/null +++ b/.github/workflows/Test_v400_py310.yml @@ -0,0 +1,70 @@ +name: Test-v4.0.0-py310 + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + matrix: + # test for: + # * oldest supported version + python-version: ['3.10'] + # * Linux using ubuntu-latest + os: ['ubuntu-latest'] + # * OM stable - latest stable version + omc-version: ['stable'] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: 'x64' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip build setuptools wheel twine + pip install . pytest pytest-md pytest-emoji pre-commit + + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: 'Europe/Berlin' + + - name: Run pre-commit linters + run: 'pre-commit run --all-files' + + - name: "Set up OpenModelica Compiler" + uses: OpenModelica/setup-openmodelica@v1.0.6 + with: + version: ${{ matrix.omc-version }} + packages: | + omc + libraries: | + 'Modelica 4.0.0' + - run: "omc --version" + + - name: Pull OpenModelica docker image + if: runner.os != 'Windows' + run: docker pull openmodelica/openmodelica:v1.25.0-minimal + + - name: Build wheel and sdist packages + run: python -m build --wheel --sdist --outdir dist + + - name: Check twine + run: python -m twine check dist/* + + - name: Run pytest + uses: pavelzw/pytest-action@v2 + with: + verbose: true + emoji: true + job-summary: true + custom-arguments: '-v ./tests_v400' + click-to-expand: true + report-title: 'Test Report' diff --git a/.github/workflows/Test_v4xx.yml b/.github/workflows/Test_v4xx.yml new file mode 100644 index 00000000..cc662ff9 --- /dev/null +++ b/.github/workflows/Test_v4xx.yml @@ -0,0 +1,73 @@ +name: Test-v4.x.x + +on: + workflow_dispatch: + +jobs: + test: + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + matrix: + # test for: + # * oldest supported version + # * latest available Python version + python-version: ['3.10', '3.14'] + # * Linux using ubuntu-latest + # * Windows using windows-latest + os: ['ubuntu-latest', 'windows-latest'] + # * OM stable - latest stable version + # * OM nightly - latest nightly build + omc-version: ['stable', 'nightly'] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: 'x64' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip build setuptools wheel twine + pip install . pytest pytest-md pytest-emoji pre-commit + + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: 'Europe/Berlin' + + - name: Run pre-commit linters + run: 'pre-commit run --all-files' + + - name: "Set up OpenModelica Compiler" + uses: OpenModelica/setup-openmodelica@v1.0.6 + with: + version: ${{ matrix.omc-version }} + packages: | + omc + libraries: | + 'Modelica 4.0.0' + - run: "omc --version" + + - name: Pull OpenModelica docker image + if: runner.os != 'Windows' + run: docker pull openmodelica/openmodelica:v1.25.0-minimal + + - name: Build wheel and sdist packages + run: python -m build --wheel --sdist --outdir dist + + - name: Check twine + run: python -m twine check dist/* + + - name: Run pytest + uses: pavelzw/pytest-action@v2 + with: + verbose: true + emoji: true + job-summary: true + custom-arguments: '-v ./tests' + click-to-expand: true + report-title: 'Test Report' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 484570b6..dd477775 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: hooks: - id: mypy args: [] - exclude: tests/ + exclude: 'test|test_v400' additional_dependencies: - pyparsing - types-psutil diff --git a/tests_v400/__init__.py b/tests_v400/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests_v400/test_ArrayDimension.py b/tests_v400/test_ArrayDimension.py new file mode 100644 index 00000000..13b3c11b --- /dev/null +++ b/tests_v400/test_ArrayDimension.py @@ -0,0 +1,19 @@ +import OMPython + + +def test_ArrayDimension(tmp_path): + omc = OMPython.OMCSessionZMQ() + + omc.sendExpression(f'cd("{tmp_path.as_posix()}")') + + 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), "array dimension does not match" + + omc.sendExpression('loadString("model A Integer y = 5; Integer x[y+1,1+9]; end A;")') + omc.sendExpression("getErrorString()") + + result = omc.sendExpression("getComponents(A)") + assert result[-1][-1] == ('y+1', 10), "array dimension does not match" diff --git a/tests_v400/test_FMIExport.py b/tests_v400/test_FMIExport.py new file mode 100644 index 00000000..f47b87ae --- /dev/null +++ b/tests_v400/test_FMIExport.py @@ -0,0 +1,24 @@ +import OMPython +import shutil +import os + + +def test_CauerLowPassAnalog(): + mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + lmodel=["Modelica"]) + tmp = mod.getWorkDirectory() + try: + fmu = mod.convertMo2Fmu(fileNamePrefix="CauerLowPassAnalog") + assert os.path.exists(fmu) + finally: + shutil.rmtree(tmp, ignore_errors=True) + + +def test_DrumBoiler(): + mod = OMPython.ModelicaSystem(modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", lmodel=["Modelica"]) + tmp = mod.getWorkDirectory() + try: + fmu = mod.convertMo2Fmu(fileNamePrefix="DrumBoiler") + assert os.path.exists(fmu) + finally: + shutil.rmtree(tmp, ignore_errors=True) diff --git a/tests_v400/test_ModelicaSystem.py b/tests_v400/test_ModelicaSystem.py new file mode 100644 index 00000000..c55e95fc --- /dev/null +++ b/tests_v400/test_ModelicaSystem.py @@ -0,0 +1,411 @@ +import OMPython +import os +import pathlib +import pytest +import tempfile +import numpy as np + + +@pytest.fixture +def model_firstorder(tmp_path): + mod = tmp_path / "M.mo" + mod.write_text("""model M + Real x(start = 1, fixed = true); + parameter Real a = -1; +equation + der(x) = x*a; +end M; +""") + return mod + + +def test_ModelicaSystem_loop(model_firstorder): + def worker(): + filePath = model_firstorder.as_posix() + m = OMPython.ModelicaSystem(filePath, "M") + m.simulate() + m.convertMo2Fmu(fmuType="me") + for _ in range(10): + worker() + + +def test_setParameters(): + omc = OMPython.OMCSessionZMQ() + model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" + mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall") + + # method 1 + mod.setParameters(pvals={"e": 1.234}) + mod.setParameters(pvals={"g": 321.0}) + assert mod.getParameters("e") == ["1.234"] + assert mod.getParameters("g") == ["321.0"] + assert mod.getParameters() == { + "e": "1.234", + "g": "321.0", + } + with pytest.raises(KeyError): + mod.getParameters("thisParameterDoesNotExist") + + # method 2 + mod.setParameters(pvals={"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"] + with pytest.raises(KeyError): + mod.getParameters(["g", "thisParameterDoesNotExist"]) + + +def test_setSimulationOptions(): + omc = OMPython.OMCSessionZMQ() + model_path = omc.sendExpression("getInstallationDirectoryPath()") + "/share/doc/omc/testmodels/" + mod = OMPython.ModelicaSystem(fileName=model_path + "BouncingBall.mo", modelName="BouncingBall") + + # method 1 + mod.setSimulationOptions(simOptions={"stopTime": 1.234}) + mod.setSimulationOptions(simOptions={"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" + with pytest.raises(KeyError): + mod.getSimulationOptions("thisOptionDoesNotExist") + + # method 2 + mod.setSimulationOptions(simOptions={"stopTime": 2.1, "tolerance": "1.2e-08"}) + d = mod.getSimulationOptions() + assert d["stopTime"] == "2.1" + assert d["tolerance"] == "1.2e-08" + + +def test_relative_path(model_firstorder): + cwd = pathlib.Path.cwd() + (fd, name) = tempfile.mkstemp(prefix='tmpOMPython.tests', dir=cwd, text=True) + try: + with os.fdopen(fd, 'w') as f: + f.write(model_firstorder.read_text()) + + model_file = pathlib.Path(name).relative_to(cwd) + model_relative = str(model_file) + assert "/" not in model_relative + + mod = OMPython.ModelicaSystem(fileName=model_relative, modelName="M") + assert float(mod.getParameters("a")[0]) == -1 + finally: + model_file.unlink() # clean up the temporary file + + +def test_customBuildDirectory(tmp_path, model_firstorder): + filePath = model_firstorder.as_posix() + tmpdir = tmp_path / "tmpdir1" + tmpdir.mkdir() + m = OMPython.ModelicaSystem(filePath, "M", customBuildDirectory=tmpdir) + assert pathlib.Path(m.getWorkDirectory().resolve()) == tmpdir.resolve() + result_file = tmpdir / "a.mat" + assert not result_file.exists() + m.simulate(resultfile="a.mat") + assert result_file.is_file() + + +def test_getSolutions(model_firstorder): + filePath = model_firstorder.as_posix() + mod = OMPython.ModelicaSystem(filePath, "M") + x0 = 1 + a = -1 + tau = -1 / a + stopTime = 5*tau + mod.setSimulationOptions(simOptions={"stopTime": stopTime, "stepSize": 0.1, "tolerance": 1e-8}) + mod.simulate() + + x = mod.getSolutions("x") + t, x2 = mod.getSolutions(["time", "x"]) + assert (x2 == x).all() + sol_names = mod.getSolutions() + assert isinstance(sol_names, tuple) + assert "time" in sol_names + assert "x" in sol_names + assert "der(x)" in sol_names + with pytest.raises(OMPython.ModelicaSystemError): + mod.getSolutions("thisVariableDoesNotExist") + assert np.isclose(t[0], 0), "time does not start at 0" + assert np.isclose(t[-1], stopTime), "time does not end at stopTime" + x_analytical = x0 * np.exp(a*t) + assert np.isclose(x, x_analytical, rtol=1e-4).all() + + +def test_getters(tmp_path): + model_file = tmp_path / "M_getters.mo" + model_file.write_text(""" +model M_getters +Real x(start = 1, fixed = true); +output Real y "the derivative"; +parameter Real a = -0.5; +parameter Real b = 0.1; +equation +der(x) = x*a + b; +y = der(x); +end M_getters; +""") + mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="M_getters") + + q = mod.getQuantities() + assert isinstance(q, list) + assert sorted(q, key=lambda d: d["name"]) == sorted([ + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'local', + 'changeable': 'true', + 'description': None, + 'max': None, + 'min': None, + 'name': 'x', + 'start': '1.0', + 'unit': None, + 'variability': 'continuous', + }, + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'local', + 'changeable': 'false', + 'description': None, + 'max': None, + 'min': None, + 'name': 'der(x)', + 'start': None, + 'unit': None, + 'variability': 'continuous', + }, + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'output', + 'changeable': 'false', + 'description': 'the derivative', + 'max': None, + 'min': None, + 'name': 'y', + 'start': '-0.4', + 'unit': None, + 'variability': 'continuous', + }, + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'parameter', + 'changeable': 'true', + 'description': None, + 'max': None, + 'min': None, + 'name': 'a', + 'start': '-0.5', + 'unit': None, + 'variability': 'parameter', + }, + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'parameter', + 'changeable': 'true', + 'description': None, + 'max': None, + 'min': None, + 'name': 'b', + 'start': '0.1', + 'unit': None, + 'variability': 'parameter', + } + ], key=lambda d: d["name"]) + + assert mod.getQuantities("y") == [ + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'output', + 'changeable': 'false', + 'description': 'the derivative', + 'max': None, + 'min': None, + 'name': 'y', + 'start': '-0.4', + 'unit': None, + 'variability': 'continuous', + } + ] + + assert mod.getQuantities(["y", "x"]) == [ + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'output', + 'changeable': 'false', + 'description': 'the derivative', + 'max': None, + 'min': None, + 'name': 'y', + 'start': '-0.4', + 'unit': None, + 'variability': 'continuous', + }, + { + 'alias': 'noAlias', + 'aliasvariable': None, + 'causality': 'local', + 'changeable': 'true', + 'description': None, + 'max': None, + 'min': None, + 'name': 'x', + 'start': '1.0', + 'unit': None, + 'variability': 'continuous', + }, + ] + + with pytest.raises(KeyError): + mod.getQuantities("thisQuantityDoesNotExist") + + assert mod.getInputs() == {} + with pytest.raises(KeyError): + mod.getInputs("thisInputDoesNotExist") + # getOutputs before simulate() + assert mod.getOutputs() == {'y': '-0.4'} + assert mod.getOutputs("y") == ["-0.4"] + assert mod.getOutputs(["y", "y"]) == ["-0.4", "-0.4"] + with pytest.raises(KeyError): + mod.getOutputs("thisOutputDoesNotExist") + + # getContinuous before simulate(): + assert mod.getContinuous() == { + 'x': '1.0', + 'der(x)': None, + 'y': '-0.4' + } + assert mod.getContinuous("y") == ['-0.4'] + assert mod.getContinuous(["y", "x"]) == ['-0.4', '1.0'] + with pytest.raises(KeyError): + mod.getContinuous("a") # a is a parameter + + stopTime = 1.0 + a = -0.5 + b = 0.1 + x0 = 1.0 + x_analytical = -b/a + (x0 + b/a) * np.exp(a * stopTime) + dx_analytical = (x0 + b/a) * a * np.exp(a * stopTime) + mod.setSimulationOptions(simOptions={"stopTime": stopTime}) + mod.simulate() + + # getOutputs after simulate() + d = mod.getOutputs() + assert d.keys() == {"y"} + assert np.isclose(d["y"], dx_analytical, 1e-4) + assert mod.getOutputs("y") == [d["y"]] + assert mod.getOutputs(["y", "y"]) == [d["y"], d["y"]] + with pytest.raises(KeyError): + mod.getOutputs("thisOutputDoesNotExist") + + # getContinuous after simulate() should return values at end of simulation: + with pytest.raises(KeyError): + mod.getContinuous("a") # a is a parameter + with pytest.raises(KeyError): + mod.getContinuous(["x", "a", "y"]) # a is a parameter + d = mod.getContinuous() + assert d.keys() == {"x", "der(x)", "y"} + assert np.isclose(d["x"], x_analytical, 1e-4) + assert np.isclose(d["der(x)"], dx_analytical, 1e-4) + assert np.isclose(d["y"], dx_analytical, 1e-4) + assert mod.getContinuous("x") == [d["x"]] + assert mod.getContinuous(["y", "x"]) == [d["y"], d["x"]] + + with pytest.raises(KeyError): + mod.getContinuous("a") # a is a parameter + + with pytest.raises(OMPython.ModelicaSystemError): + mod.setSimulationOptions(simOptions={"thisOptionDoesNotExist": 3}) + + +def test_simulate_inputs(tmp_path): + model_file = tmp_path / "M_input.mo" + model_file.write_text(""" +model M_input +Real x(start=0, fixed=true); +input Real u1; +input Real u2; +output Real y; +equation +der(x) = u1 + u2; +y = x; +end M_input; +""") + mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="M_input") + + mod.setSimulationOptions(simOptions={"stopTime": 1.0}) + + # integrate zero (no setInputs call) - it should default to None -> 0 + assert mod.getInputs() == { + "u1": None, + "u2": None, + } + mod.simulate() + y = mod.getSolutions("y")[0] + assert np.isclose(y[-1], 0.0) + + # integrate a constant + mod.setInputs(name={"u1": 2.5}) + assert mod.getInputs() == { + "u1": [ + (0.0, 2.5), + (1.0, 2.5), + ], + # u2 is set due to the call to simulate() above + "u2": [ + (0.0, 0.0), + (1.0, 0.0), + ], + } + mod.simulate() + y = mod.getSolutions("y")[0] + assert np.isclose(y[-1], 2.5) + + # now let's integrate the sum of two ramps + mod.setInputs(name={"u1": [(0.0, 0.0), (0.5, 2), (1.0, 0)]}) + assert mod.getInputs("u1") == [[ + (0.0, 0.0), + (0.5, 2.0), + (1.0, 0.0), + ]] + mod.simulate() + y = mod.getSolutions("y")[0] + assert np.isclose(y[-1], 1.0) + + # let's try some edge cases + # unmatched startTime + with pytest.raises(OMPython.ModelicaSystemError): + mod.setInputs(name={"u1": [(-0.5, 0.0), (1.0, 1)]}) + mod.simulate() + # unmatched stopTime + with pytest.raises(OMPython.ModelicaSystemError): + mod.setInputs(name={"u1": [(0.0, 0.0), (0.5, 1)]}) + mod.simulate() + + # Let's use both inputs, but each one with different number of + # samples. This has an effect when generating the csv file. + mod.setInputs(name={"u1": [(0.0, 0), (1.0, 1)], + "u2": [(0.0, 0), (0.25, 0.5), (0.5, 1.0), (1.0, 0)]}) + csv_file = mod._createCSVData() + assert pathlib.Path(csv_file).read_text() == """time,u1,u2,end +0.0,0.0,0.0,0 +0.25,0.25,0.5,0 +0.5,0.5,1.0,0 +1.0,1.0,0.0,0 +""" + + mod.simulate() + y = mod.getSolutions("y")[0] + assert np.isclose(y[-1], 1.0) diff --git a/tests_v400/test_ModelicaSystemCmd.py b/tests_v400/test_ModelicaSystemCmd.py new file mode 100644 index 00000000..3544a1bd --- /dev/null +++ b/tests_v400/test_ModelicaSystemCmd.py @@ -0,0 +1,51 @@ +import OMPython +import pytest + + +@pytest.fixture +def model_firstorder(tmp_path): + mod = tmp_path / "M.mo" + mod.write_text("""model M + Real x(start = 1, fixed = true); + parameter Real a = -1; +equation + der(x) = x*a; +end M; +""") + return mod + + +@pytest.fixture +def mscmd_firstorder(model_firstorder): + mod = OMPython.ModelicaSystem(fileName=model_firstorder.as_posix(), modelName="M") + mscmd = OMPython.ModelicaSystemCmd(runpath=mod.getWorkDirectory(), modelname=mod._model_name) + return mscmd + + +def test_simflags(mscmd_firstorder): + mscmd = mscmd_firstorder + + mscmd.args_set({ + "noEventEmit": None, + "override": {'b': 2} + }) + with pytest.deprecated_call(): + mscmd.args_set(args=mscmd.parse_simflags(simflags="-noEventEmit -noRestart -override=a=1,x=3")) + + assert mscmd.get_cmd() == [ + mscmd.get_exe().as_posix(), + '-noEventEmit', + '-noRestart', + '-override=a=1,b=2,x=3', + ] + + mscmd.args_set({ + "override": {'b': None}, + }) + + assert mscmd.get_cmd() == [ + mscmd.get_exe().as_posix(), + '-noEventEmit', + '-noRestart', + '-override=a=1,x=3', + ] diff --git a/tests_v400/test_OMParser.py b/tests_v400/test_OMParser.py new file mode 100644 index 00000000..875604e5 --- /dev/null +++ b/tests_v400/test_OMParser.py @@ -0,0 +1,43 @@ +from OMPython import OMParser + +typeCheck = OMParser.typeCheck + + +def test_newline_behaviour(): + pass + + +def test_boolean(): + assert typeCheck('TRUE') is True + assert typeCheck('True') is True + assert typeCheck('true') is True + assert typeCheck('FALSE') is False + assert typeCheck('False') is False + assert typeCheck('false') is False + + +def test_int(): + assert typeCheck('2') == 2 + assert type(typeCheck('1')) == int + assert type(typeCheck('123123123123123123232323')) == int + assert type(typeCheck('9223372036854775808')) == int + + +def test_float(): + assert type(typeCheck('1.2e3')) == float + + +# def test_dict(): +# assert type(typeCheck('{"a": "b"}')) == dict + + +def test_ident(): + assert typeCheck('blabla2') == "blabla2" + + +def test_str(): + pass + + +def test_UnStringable(): + pass diff --git a/tests_v400/test_OMSessionCmd.py b/tests_v400/test_OMSessionCmd.py new file mode 100644 index 00000000..1588fac8 --- /dev/null +++ b/tests_v400/test_OMSessionCmd.py @@ -0,0 +1,17 @@ +import OMPython + + +def test_isPackage(): + omczmq = OMPython.OMCSessionZMQ() + omccmd = OMPython.OMCSessionCmd(session=omczmq) + assert not omccmd.isPackage('Modelica') + + +def test_isPackage2(): + mod = OMPython.ModelicaSystem(modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + lmodel=["Modelica"]) + omccmd = OMPython.OMCSessionCmd(session=mod._getconn) + assert omccmd.isPackage('Modelica') + + +# TODO: add more checks ... diff --git a/tests_v400/test_ZMQ.py b/tests_v400/test_ZMQ.py new file mode 100644 index 00000000..30bf78e7 --- /dev/null +++ b/tests_v400/test_ZMQ.py @@ -0,0 +1,70 @@ +import OMPython +import pathlib +import os +import pytest + + +@pytest.fixture +def model_time_str(): + return """model M + Real r = time; +end M; +""" + + +@pytest.fixture +def om(tmp_path): + origDir = pathlib.Path.cwd() + os.chdir(tmp_path) + om = OMPython.OMCSessionZMQ() + os.chdir(origDir) + return om + + +def testHelloWorld(om): + assert om.sendExpression('"HelloWorld!"') == "HelloWorld!" + + +def test_Translate(om, model_time_str): + assert om.sendExpression(model_time_str) == ("M",) + assert om.sendExpression('translateModel(M)') is True + + +def test_Simulate(om, model_time_str): + assert om.sendExpression(f'loadString("{model_time_str}")') is True + om.sendExpression('res:=simulate(M, stopTime=2.0)') + assert om.sendExpression('res.resultFile') + + +def test_execute(om): + with pytest.deprecated_call(): + assert om.execute('"HelloWorld!"') == '"HelloWorld!"\n' + assert om.sendExpression('"HelloWorld!"', parsed=False) == '"HelloWorld!"\n' + assert om.sendExpression('"HelloWorld!"', parsed=True) == 'HelloWorld!' + + +def test_omcprocessport_execute(om): + port = om.omc_process.get_port() + omcp = OMPython.OMCProcessPort(omc_port=port) + + # run 1 + om1 = OMPython.OMCSessionZMQ(omc_process=omcp) + assert om1.sendExpression('"HelloWorld!"', parsed=False) == '"HelloWorld!"\n' + + # run 2 + om2 = OMPython.OMCSessionZMQ(omc_process=omcp) + assert om2.sendExpression('"HelloWorld!"', parsed=False) == '"HelloWorld!"\n' + + del om1 + del om2 + + +def test_omcprocessport_simulate(om, model_time_str): + port = om.omc_process.get_port() + omcp = OMPython.OMCProcessPort(omc_port=port) + + om = OMPython.OMCSessionZMQ(omc_process=omcp) + assert om.sendExpression(f'loadString("{model_time_str}")') is True + om.sendExpression('res:=simulate(M, stopTime=2.0)') + assert om.sendExpression('res.resultFile') != "" + del om diff --git a/tests_v400/test_docker.py b/tests_v400/test_docker.py new file mode 100644 index 00000000..8d68f11f --- /dev/null +++ b/tests_v400/test_docker.py @@ -0,0 +1,32 @@ +import sys +import pytest +import OMPython + +skip_on_windows = pytest.mark.skipif( + sys.platform.startswith("win"), + reason="OpenModelica Docker image is Linux-only; skipping on Windows.", +) + + +@skip_on_windows +def test_docker(): + omcp = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal") + om = OMPython.OMCSessionZMQ(omc_process=omcp) + assert om.sendExpression("getVersion()") == "OpenModelica 1.25.0" + + omcpInner = OMPython.OMCProcessDockerContainer(dockerContainer=omcp.get_docker_container_id()) + omInner = OMPython.OMCSessionZMQ(omc_process=omcpInner) + assert omInner.sendExpression("getVersion()") == "OpenModelica 1.25.0" + + omcp2 = OMPython.OMCProcessDocker(docker="openmodelica/openmodelica:v1.25.0-minimal", port=11111) + om2 = OMPython.OMCSessionZMQ(omc_process=omcp2) + assert om2.sendExpression("getVersion()") == "OpenModelica 1.25.0" + + del omcp2 + del om2 + + del omcpInner + del omInner + + del omcp + del om diff --git a/tests_v400/test_linearization.py b/tests_v400/test_linearization.py new file mode 100644 index 00000000..bccbc40b --- /dev/null +++ b/tests_v400/test_linearization.py @@ -0,0 +1,102 @@ +import OMPython +import pytest +import numpy as np + + +@pytest.fixture +def model_linearTest(tmp_path): + mod = tmp_path / "M.mo" + mod.write_text(""" +model linearTest + Real x1(start=1); + Real x2(start=-2); + Real x3(start=3); + Real x4(start=-5); + parameter Real a=3,b=2,c=5,d=7,e=1,f=4; +equation + a*x1 = b*x2 -der(x1); + der(x2) + c*x3 + d*x1 = x4; + f*x4 - e*x3 - der(x3) = x1; + der(x4) = x1 + x2 + der(x3) + x4; +end linearTest; +""") + return mod + + +def test_example(model_linearTest): + mod = OMPython.ModelicaSystem(model_linearTest, "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: {[]}" + assert mod.getLinearInputs() == [] + assert mod.getLinearOutputs() == [] + assert mod.getLinearStates() == ["x1", "x2", "x3", "x4"] + + +def test_getters(tmp_path): + model_file = tmp_path / "pendulum.mo" + model_file.write_text(""" +model Pendulum +Real phi(start=Modelica.Constants.pi, fixed=true); +Real omega(start=0, fixed=true); +input Real u1; +input Real u2; +output Real y1; +output Real y2; +parameter Real l = 1.2; +parameter Real g = 9.81; +equation +der(phi) = omega + u2; +der(omega) = -g/l * sin(phi); +y1 = y2 + 0.5*omega; +y2 = phi + u1; +end Pendulum; +""") + mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="Pendulum", lmodel=["Modelica"]) + + d = mod.getLinearizationOptions() + assert isinstance(d, dict) + assert "startTime" in d + assert "stopTime" in d + assert mod.getLinearizationOptions(["stopTime", "startTime"]) == [d["stopTime"], d["startTime"]] + mod.setLinearizationOptions(linearizationOptions={"stopTime": 0.02}) + assert mod.getLinearizationOptions("stopTime") == ["0.02"] + + mod.setInputs(name={"u1": 10, "u2": 0}) + [A, B, C, D] = mod.linearize() + param_g = float(mod.getParameters("g")[0]) + param_l = float(mod.getParameters("l")[0]) + assert mod.getLinearInputs() == ["u1", "u2"] + assert mod.getLinearStates() == ["omega", "phi"] + assert mod.getLinearOutputs() == ["y1", "y2"] + assert np.isclose(A, [[0, param_g/param_l], [1, 0]]).all() + assert np.isclose(B, [[0, 0], [0, 1]]).all() + assert np.isclose(C, [[0.5, 1], [0, 1]]).all() + assert np.isclose(D, [[1, 0], [1, 0]]).all() + + # test LinearizationResult + result = mod.linearize() + assert result[0] == A + assert result[1] == B + assert result[2] == C + assert result[3] == D + with pytest.raises(KeyError): + result[4] + + A2, B2, C2, D2 = result + assert A2 == A + assert B2 == B + assert C2 == C + assert D2 == D + + assert result.n == 2 + assert result.m == 2 + assert result.p == 2 + assert np.isclose(result.x0, [0, np.pi]).all() + assert np.isclose(result.u0, [10, 0]).all() + assert result.stateVars == ["omega", "phi"] + assert result.inputVars == ["u1", "u2"] + assert result.outputVars == ["y1", "y2"] diff --git a/tests_v400/test_optimization.py b/tests_v400/test_optimization.py new file mode 100644 index 00000000..b4164397 --- /dev/null +++ b/tests_v400/test_optimization.py @@ -0,0 +1,67 @@ +import OMPython +import numpy as np + + +def test_optimization_example(tmp_path): + model_file = tmp_path / "BangBang2021.mo" + model_file.write_text(""" +model BangBang2021 "Model to verify that optimization gives bang-bang optimal control" +parameter Real m = 1; +parameter Real p = 1 "needed for final constraints"; + +Real a; +Real v(start = 0, fixed = true); +Real pos(start = 0, fixed = true); +Real pow(min = -30, max = 30) = f * v annotation(isConstraint = true); + +input Real f(min = -10, max = 10); + +Real costPos(nominal = 1) = -pos "minimize -pos(tf)" annotation(isMayer=true); + +Real conSpeed(min = 0, max = 0) = p * v " 0<= p*v(tf) <=0" annotation(isFinalConstraint = true); + +equation + +der(pos) = v; +der(v) = a; +f = m * a; + +annotation(experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-07, Interval = 0.01), +__OpenModelica_simulationFlags(s="optimization", optimizerNP="1"), +__OpenModelica_commandLineOptions="+g=Optimica"); + +end BangBang2021; +""") + + mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="BangBang2021") + + mod.setOptimizationOptions(optimizationOptions={"numberOfIntervals": 16, + "stopTime": 1, + "stepSize": 0.001, + "tolerance": 1e-8}) + + # test the getter + assert mod.getOptimizationOptions()["stopTime"] == "1" + assert mod.getOptimizationOptions("stopTime") == ["1"] + assert mod.getOptimizationOptions(["tolerance", "stopTime"]) == ["1e-08", "1"] + + r = mod.optimize() + # it is necessary to specify resultfile, otherwise it wouldn't find it. + time, f, v = mod.getSolutions(["time", "f", "v"], resultfile=r["resultFile"]) + assert np.isclose(f[0], 10) + assert np.isclose(f[-1], -10) + + def f_fcn(time, v): + if time < 0.3: + return 10 + if time <= 0.5: + return 30 / v + if time < 0.7: + return -30 / v + return -10 + f_expected = [f_fcn(t, v) for t, v in zip(time, v)] + + # The sharp edge at time=0.5 probably won't match, let's leave that out. + matches = np.isclose(f, f_expected, 1e-3) + assert matches[:498].all() + assert matches[502:].all() diff --git a/tests_v400/test_typedParser.py b/tests_v400/test_typedParser.py new file mode 100644 index 00000000..60daedec --- /dev/null +++ b/tests_v400/test_typedParser.py @@ -0,0 +1,53 @@ +from OMPython import OMTypedParser + +typeCheck = OMTypedParser.parseString + + +def test_newline_behaviour(): + pass + + +def test_boolean(): + assert typeCheck('true') is True + assert typeCheck('false') is False + + +def test_int(): + assert typeCheck('2') == 2 + assert type(typeCheck('1')) == int + assert type(typeCheck('123123123123123123232323')) == int + assert type(typeCheck('9223372036854775808')) == int + + +def test_float(): + assert type(typeCheck('1.2e3')) == float + + +def test_ident(): + assert typeCheck('blabla2') == "blabla2" + + +def test_empty(): + assert typeCheck('') is None + + +def test_str(): + pass + + +def test_UnStringable(): + pass + + +def test_everything(): + # this test used to be in OMTypedParser.py's main() + testdata = """ + (1.0,{{1,true,3},{"4\\" +",5.9,6,NONE ( )},record ABC + startTime = ErrorLevel.warning, + 'stop*Time' = SOME(1.0) +end ABC;}) + """ + expected = (1.0, ((1, True, 3), ('4"\n', 5.9, 6, None), {"'stop*Time'": 1.0, 'startTime': 'ErrorLevel.warning'})) + results = typeCheck(testdata) + assert results == expected From 44e071329102cbb2447d242af40e979119fc4531 Mon Sep 17 00:00:00 2001 From: syntron Date: Sun, 8 Feb 2026 20:52:18 +0100 Subject: [PATCH 4/4] (E001) update tests (v4.x.x) [test_*] reorder imports [tests_ModelicaDoE*] fix pylint hint * use .items() [tests_*] use OMSessionABC.get_version() [test_ModelicaSystemCmd] use get_model_name() instead of access to private variable _model_name [test_ModelicaSystemOMC] read file using utf-8 encoding / linter fix [test_ModelicaSystemRunner] update test case * ModelicaSystemRunner & OMCPath * ModelicaSystemRunner & OMPathRunnerLocal * ModelicaSystemRunner & OMPathRunnerBash * ModelicaSystemRunner & OMPathRunnerBash using docker * ModelicaSystemRunner & OMPathRunnerBash using WSL (not tested!) [test_OMCPath] update test case * OMCPath & OMCSessionZMQ * OMCPath & OMCSessionLocal * OMCPath & OMCSessionDocker * OMCPath & OMCSessionWSL (not tested!) * OMPathLocal & OMCSessionRunner * OMPathBash & OMCSessionRunner * OMPathBash & OMCSessionRunner in docker * OMPathBash & OMCSessionRunner in WSL (not tested!) add workflow to run unittests in ./tests [test_OMParser] use only the public interface => om_parser_basic() [test_OMTypedParser] rename file / use om_parser_typed() update tests - do NOT run test_FMIRegression.py reason: * it is only a test for OMC / not OMPython specific * furthermore, it is run automatically via cron job (= FMITest) [test_ModelExecutionCmd] rename from test_ModelicaSystemCmd --- OMPython/__init__.py | 2 + tests/test_FMIExport.py | 2 +- ...SystemCmd.py => test_ModelExecutionCmd.py} | 2 +- tests/test_ModelicaDoEOMC.py | 6 +- tests/test_ModelicaDoERunner.py | 6 +- tests/test_ModelicaSystemOMC.py | 2 +- tests/test_ModelicaSystemRunner.py | 176 +++++++++++++++++- tests/test_OMCPath.py | 96 +++++++--- tests/test_OMParser.py | 53 ++++-- tests/test_OMTypedParser.py | 65 +++++++ tests/test_ZMQ.py | 1 + tests/test_docker.py | 2 + tests/test_typedParser.py | 53 ------ 13 files changed, 365 insertions(+), 101 deletions(-) rename tests/{test_ModelicaSystemCmd.py => test_ModelExecutionCmd.py} (97%) create mode 100644 tests/test_OMTypedParser.py delete mode 100644 tests/test_typedParser.py diff --git a/OMPython/__init__.py b/OMPython/__init__.py index c12f8524..22c88137 100644 --- a/OMPython/__init__.py +++ b/OMPython/__init__.py @@ -30,6 +30,7 @@ OMPathABC, OMCPath, + OMSessionABC, OMSessionRunner, OMCSessionABC, @@ -77,6 +78,7 @@ 'OMPathABC', 'OMCPath', + 'OMSessionABC', 'OMSessionRunner', 'OMCSessionABC', diff --git a/tests/test_FMIExport.py b/tests/test_FMIExport.py index c7ab038a..65ac2766 100644 --- a/tests/test_FMIExport.py +++ b/tests/test_FMIExport.py @@ -1,6 +1,6 @@ -import shutil import os import pathlib +import shutil import OMPython diff --git a/tests/test_ModelicaSystemCmd.py b/tests/test_ModelExecutionCmd.py similarity index 97% rename from tests/test_ModelicaSystemCmd.py rename to tests/test_ModelExecutionCmd.py index 3d35376b..db5aadeb 100644 --- a/tests/test_ModelicaSystemCmd.py +++ b/tests/test_ModelExecutionCmd.py @@ -29,7 +29,7 @@ def mscmd_firstorder(model_firstorder): cmd_local=mod.get_session().model_execution_local, cmd_windows=mod.get_session().model_execution_windows, cmd_prefix=mod.get_session().model_execution_prefix(cwd=mod.getWorkDirectory()), - model_name=mod._model_name, + model_name=mod.get_model_name(), ) return mscmd diff --git a/tests/test_ModelicaDoEOMC.py b/tests/test_ModelicaDoEOMC.py index 143932fc..9d6afc63 100644 --- a/tests/test_ModelicaDoEOMC.py +++ b/tests/test_ModelicaDoEOMC.py @@ -159,6 +159,6 @@ def _run_ModelicaDoEOMC(doe_mod): f"y[{row['p']}]": float(row['b']), } - for var in var_dict: - assert var in sol['data'] - assert np.isclose(sol['data'][var][-1], var_dict[var]) + for key, val in var_dict.items(): + assert key in sol['data'] + assert np.isclose(sol['data'][key][-1], val) diff --git a/tests/test_ModelicaDoERunner.py b/tests/test_ModelicaDoERunner.py index 2d41315f..e29e7e05 100644 --- a/tests/test_ModelicaDoERunner.py +++ b/tests/test_ModelicaDoERunner.py @@ -153,6 +153,6 @@ def _check_runner_result(mod, doe_mod): 'b': float(row['b']), } - for var in var_dict: - assert var in sol['data'] - assert np.isclose(sol['data'][var][-1], var_dict[var]) + for key, val in var_dict.items(): + assert key in sol['data'] + assert np.isclose(sol['data'][key][-1], val) diff --git a/tests/test_ModelicaSystemOMC.py b/tests/test_ModelicaSystemOMC.py index 8dd17ef0..c63b92e1 100644 --- a/tests/test_ModelicaSystemOMC.py +++ b/tests/test_ModelicaSystemOMC.py @@ -495,7 +495,7 @@ def test_simulate_inputs(tmp_path): } mod.setInputs(**inputs) csv_file = mod._createCSVData() - assert pathlib.Path(csv_file).read_text() == """time,u1,u2,end + assert pathlib.Path(csv_file).read_text(encoding='utf-8') == """time,u1,u2,end 0.0,0.0,0.0,0 0.25,0.25,0.5,0 0.5,0.5,1.0,0 diff --git a/tests/test_ModelicaSystemRunner.py b/tests/test_ModelicaSystemRunner.py index ec9d734d..a207368c 100644 --- a/tests/test_ModelicaSystemRunner.py +++ b/tests/test_ModelicaSystemRunner.py @@ -1,9 +1,22 @@ +import sys + import numpy as np import pytest import OMPython +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_content(): return """ @@ -37,7 +50,7 @@ def param(): } -def test_runner(model_firstorder, param): +def test_ModelicaSystemRunner_OMC(model_firstorder, param): # create a model using ModelicaSystem mod = OMPython.ModelicaSystemOMC() mod.model( @@ -71,6 +84,167 @@ def test_runner(model_firstorder, param): _check_result(mod=mod, resultfile=resultfile_modr, param=param) +def test_ModelicaSystemRunner_local(model_firstorder, param): + # create a model using ModelicaSystem + mod = OMPython.ModelicaSystemOMC() + mod.model( + model_file=model_firstorder, + model_name="M", + ) + + resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat" + _run_simulation(mod=mod, resultfile=resultfile_mod, param=param) + + # run the model using only the runner class + omcs = OMPython.OMSessionRunner( + version=mod.get_session().get_version(), + ompath_runner=OMPython.OMPathRunnerLocal, + ) + modr = OMPython.ModelicaSystemRunner( + session=omcs, + work_directory=mod.getWorkDirectory(), + ) + modr.setup( + model_name="M", + ) + + resultfile_modr = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_modr.mat" + _run_simulation(mod=modr, resultfile=resultfile_modr, param=param) + + # cannot check the content as runner does not have the capability to open a result file + assert resultfile_mod.size() == resultfile_modr.size() + + # check results + _check_result(mod=mod, resultfile=resultfile_mod, param=param) + _check_result(mod=mod, resultfile=resultfile_modr, param=param) + + +@skip_on_windows +def test_ModelicaSystemRunner_bash(model_firstorder, param): + # create a model using ModelicaSystem + mod = OMPython.ModelicaSystemOMC() + mod.model( + model_file=model_firstorder, + model_name="M", + ) + + resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat" + _run_simulation(mod=mod, resultfile=resultfile_mod, param=param) + + # run the model using only the runner class + omcsr = OMPython.OMSessionRunner( + version=mod.get_session().get_version(), + ompath_runner=OMPython.OMPathRunnerBash, + ) + modr = OMPython.ModelicaSystemRunner( + session=omcsr, + work_directory=mod.getWorkDirectory(), + ) + modr.setup( + model_name="M", + ) + + resultfile_modr = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_modr.mat" + _run_simulation(mod=modr, resultfile=resultfile_modr, param=param) + + # cannot check the content as runner does not have the capability to open a result file + assert resultfile_mod.size() == resultfile_modr.size() + + # check results + _check_result(mod=mod, resultfile=resultfile_mod, param=param) + _check_result(mod=mod, resultfile=resultfile_modr, param=param) + + +@skip_on_windows +@skip_python_older_312 +def test_ModelicaSystemRunner_bash_docker(model_firstorder, param): + omcs = OMPython.OMCSessionDocker(docker="openmodelica/openmodelica:v1.25.0-minimal") + omversion = omcs.sendExpression("getVersion()") + assert isinstance(omversion, str) and omversion.startswith("OpenModelica") + + # create a model using ModelicaSystem + mod = OMPython.ModelicaSystemOMC( + session=omcs, + ) + mod.model( + model_file=model_firstorder, + model_name="M", + ) + + resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat" + _run_simulation(mod=mod, resultfile=resultfile_mod, param=param) + + # run the model using only the runner class + omcsr = OMPython.OMSessionRunner( + version=mod.get_session().get_version(), + cmd_prefix=omcs.model_execution_prefix(cwd=mod.getWorkDirectory()), + ompath_runner=OMPython.OMPathRunnerBash, + model_execution_local=False, + ) + modr = OMPython.ModelicaSystemRunner( + session=omcsr, + work_directory=mod.getWorkDirectory(), + ) + modr.setup( + model_name="M", + ) + + resultfile_modr = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_modr.mat" + _run_simulation(mod=modr, resultfile=resultfile_modr, param=param) + + # cannot check the content as runner does not have the capability to open a result file + assert resultfile_mod.size() == resultfile_modr.size() + + # check results + _check_result(mod=mod, resultfile=resultfile_mod, param=param) + _check_result(mod=mod, resultfile=resultfile_modr, param=param) + + +@pytest.mark.skip(reason="Not able to run WSL on github") +@skip_python_older_312 +def test_ModelicaSystemDoE_WSL(tmp_path, model_doe, param_doe): + omcs = OMPython.OMCSessionWSL() + omversion = omcs.sendExpression("getVersion()") + assert isinstance(omversion, str) and omversion.startswith("OpenModelica") + + # create a model using ModelicaSystem + mod = OMPython.ModelicaSystemOMC( + session=omcs, + ) + mod.model( + model_file=model_firstorder, + model_name="M", + ) + + resultfile_mod = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_mod.mat" + _run_simulation(mod=mod, resultfile=resultfile_mod, param=param) + + # run the model using only the runner class + omcsr = OMPython.OMSessionRunner( + version=mod.get_session().get_version(), + cmd_prefix=omcs.model_execution_prefix(cwd=mod.getWorkDirectory()), + ompath_runner=OMPython.OMPathRunnerBash, + model_execution_local=False, + ) + modr = OMPython.ModelicaSystemRunner( + session=omcsr, + work_directory=mod.getWorkDirectory(), + ) + modr.setup( + model_name="M", + ) + + resultfile_modr = mod.getWorkDirectory() / f"{mod.get_model_name()}_res_modr.mat" + _run_simulation(mod=modr, resultfile=resultfile_modr, param=param) + + # cannot check the content as runner does not have the capability to open a result file + assert resultfile_mod.size() == resultfile_modr.size() + + # check results + _check_result(mod=mod, resultfile=resultfile_mod, param=param) + _check_result(mod=mod, resultfile=resultfile_modr, param=param) + + def _run_simulation(mod, resultfile, param): simOptions = {"stopTime": param['stopTime'], "stepSize": 0.1, "tolerance": 1e-8} mod.setSimulationOptions(**simOptions) diff --git a/tests/test_OMCPath.py b/tests/test_OMCPath.py index df01b86a..e15c75ff 100644 --- a/tests/test_OMCPath.py +++ b/tests/test_OMCPath.py @@ -15,42 +15,98 @@ ) -def test_OMCPath_OMCProcessLocal(): - omcs = OMPython.OMCSessionLocal() +# TODO: based on compatibility layer +def test_OMCPath_OMCSessionZMQ(): + om = OMPython.OMCSessionZMQ() - _run_OMCPath_checks(omcs) + _run_OMPath_checks(om) + _run_OMPath_write_file(om) - del omcs + +def test_OMCPath_OMCSessionLocal(): + oms = OMPython.OMCSessionLocal() + + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) @skip_on_windows @skip_python_older_312 -def test_OMCPath_OMCProcessDocker(): +def test_OMCPath_OMCSessionDocker(): omcs = OMPython.OMCSessionDocker(docker="openmodelica/openmodelica:v1.25.0-minimal") omversion = omcs.sendExpression("getVersion()") assert isinstance(omversion, str) and omversion.startswith("OpenModelica") - _run_OMCPath_checks(omcs) - - del omcs + _run_OMPath_checks(omcs) + _run_OMPath_write_file(omcs) @pytest.mark.skip(reason="Not able to run WSL on github") @skip_python_older_312 -def test_OMCPath_OMCProcessWSL(): - omcs = OMPython.OMCSessionWSL( +def test_OMCPath_OMCSessionWSL(): + oms = OMPython.OMCSessionWSL( wsl_omc='omc', wsl_user='omc', timeout=30.0, ) - _run_OMCPath_checks(omcs) + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) + + +@skip_python_older_312 +def test_OMPathLocal_OMSessionRunner(): + oms = OMPython.OMSessionRunner() + + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) + + +@skip_on_windows +@skip_python_older_312 +def test_OMPathBash_OMSessionRunner(): + oms = OMPython.OMSessionRunner( + ompath_runner=OMPython.OMPathRunnerBash, + ) + + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) + + +@skip_on_windows +@skip_python_older_312 +def test_OMPathBash_OMSessionRunner_Docker(): + oms_docker = OMPython.OMCSessionDocker(docker="openmodelica/openmodelica:v1.25.0-minimal") + omversion = oms_docker.sendExpression("getVersion()") + assert isinstance(omversion, str) and omversion.startswith("OpenModelica") + + oms = OMPython.OMSessionRunner( + cmd_prefix=oms_docker.get_cmd_prefix(), + ompath_runner=OMPython.OMPathRunnerBash, + ) + + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) - del omcs +@pytest.mark.skip(reason="Not able to run WSL on github") +@skip_python_older_312 +def test_OMPathBash_OMSessionRunner_WSL(): + oms_docker = OMPython.OMCSessionWSL() + omversion = oms_docker.sendExpression("getVersion()") + assert isinstance(omversion, str) and omversion.startswith("OpenModelica") + + oms = OMPython.OMSessionRunner( + cmd_prefix=oms_docker.get_cmd_prefix(), + ompath_runner=OMPython.OMPathRunnerBash, + ) + + _run_OMPath_checks(oms) + _run_OMPath_write_file(oms) -def _run_OMCPath_checks(omcs: OMPython.OMCSessionABC): - p1 = omcs.omcpath_tempdir() + +def _run_OMPath_checks(om: OMPython.OMSessionABC): + p1 = om.omcpath_tempdir() p2 = p1 / 'test' p2.mkdir() assert p2.is_dir() @@ -59,8 +115,8 @@ def _run_OMCPath_checks(omcs: OMPython.OMCSessionABC): assert p3.write_text('test') assert p3.is_file() assert p3.size() > 0 - p3 = p3.resolve().absolute() - assert str(p3) == str((p2 / 'test.txt').resolve().absolute()) + p3 = p3.resolve() + assert str(p3) == str((p2 / 'test.txt').resolve()) assert p3.read_text() == "test" assert p3.is_file() assert p3.parent.is_dir() @@ -68,15 +124,11 @@ def _run_OMCPath_checks(omcs: OMPython.OMCSessionABC): assert p3.is_file() is False -def test_OMCPath_write_file(tmpdir): - omcs = OMPython.OMCSessionLocal() - +def _run_OMPath_write_file(om: OMPython.OMSessionABC): data = "abc # \\t # \" # \\n # xyz" - p1 = omcs.omcpath_tempdir() + p1 = om.omcpath_tempdir() p2 = p1 / 'test.txt' p2.write_text(data=data) assert data == p2.read_text() - - del omcs diff --git a/tests/test_OMParser.py b/tests/test_OMParser.py index 875604e5..9dca784d 100644 --- a/tests/test_OMParser.py +++ b/tests/test_OMParser.py @@ -1,6 +1,6 @@ -from OMPython import OMParser +import OMPython -typeCheck = OMParser.typeCheck +parser = OMPython.OMParser.om_parser_basic def test_newline_behaviour(): @@ -8,31 +8,38 @@ def test_newline_behaviour(): def test_boolean(): - assert typeCheck('TRUE') is True - assert typeCheck('True') is True - assert typeCheck('true') is True - assert typeCheck('FALSE') is False - assert typeCheck('False') is False - assert typeCheck('false') is False + assert parser('TRUE') is True + assert parser('True') is True + assert parser('true') is True + assert parser('FALSE') is False + assert parser('False') is False + assert parser('false') is False def test_int(): - assert typeCheck('2') == 2 - assert type(typeCheck('1')) == int - assert type(typeCheck('123123123123123123232323')) == int - assert type(typeCheck('9223372036854775808')) == int + assert parser('2') == 2 + assert type(parser('1')) == int + assert type(parser('123123123123123123232323')) == int + assert type(parser('9223372036854775808')) == int def test_float(): - assert type(typeCheck('1.2e3')) == float + assert type(parser('1.2e3')) == float -# def test_dict(): -# assert type(typeCheck('{"a": "b"}')) == dict +def test_dict(): + # TODO: why does it fail? + # assert type(parser('{"a": "b"}')) == dict + pass def test_ident(): - assert typeCheck('blabla2') == "blabla2" + assert parser('blabla2') == "blabla2" + + +def test_empty(): + # TODO: this differs from OMTypedParser + assert parser('') == {} def test_str(): @@ -41,3 +48,17 @@ def test_str(): def test_UnStringable(): pass + + +# def test_everything(): +# # this test used to be in OMTypedParser.py's main() +# testdata = """ +# (1.0,{{1,true,3},{"4\\" +# ",5.9,6,NONE ( )},record ABC +# startTime = ErrorLevel.warning, +# 'stop*Time' = SOME(1.0) +# end ABC;}) +# """ +# expected = (1.0, ((1, True, 3), ('4"\n', 5.9, 6, None), {"'stop*Time'": 1.0, 'startTime': 'ErrorLevel.warning'})) +# results = parser(testdata) +# assert results == expected diff --git a/tests/test_OMTypedParser.py b/tests/test_OMTypedParser.py new file mode 100644 index 00000000..94a14210 --- /dev/null +++ b/tests/test_OMTypedParser.py @@ -0,0 +1,65 @@ +import OMPython + +parser = OMPython.OMTypedParser.om_parser_typed + + +def test_newline_behaviour(): + pass + + +def test_boolean(): + # TODO: why does these fail? + # assert parser('TRUE') is True + # assert parser('True') is True + assert parser('true') is True + # TODO: why does these fail? + # assert parser('FALSE') is False + # assert parser('False') is False + assert parser('false') is False + + +def test_int(): + assert parser('2') == 2 + assert type(parser('1')) == int + assert type(parser('123123123123123123232323')) == int + assert type(parser('9223372036854775808')) == int + + +def test_float(): + assert type(parser('1.2e3')) == float + + +def test_dict(): + # TODO: why does it fail? + # assert type(parser('{"a": "b"}')) == dict + pass + + +def test_ident(): + assert parser('blabla2') == "blabla2" + + +def test_empty(): + assert parser('') is None + + +def test_str(): + pass + + +def test_UnStringable(): + pass + + +def test_everything(): + # this test used to be in OMTypedParser.py's main() + testdata = """ + (1.0,{{1,true,3},{"4\\" +",5.9,6,NONE ( )},record ABC + startTime = ErrorLevel.warning, + 'stop*Time' = SOME(1.0) +end ABC;}) + """ + expected = (1.0, ((1, True, 3), ('4"\n', 5.9, 6, None), {"'stop*Time'": 1.0, 'startTime': 'ErrorLevel.warning'})) + results = parser(testdata) + assert results == expected diff --git a/tests/test_ZMQ.py b/tests/test_ZMQ.py index 1302a79d..89a8387b 100644 --- a/tests/test_ZMQ.py +++ b/tests/test_ZMQ.py @@ -1,5 +1,6 @@ import pathlib import os + import pytest import OMPython diff --git a/tests/test_docker.py b/tests/test_docker.py index a1acfbe1..50d2763a 100644 --- a/tests/test_docker.py +++ b/tests/test_docker.py @@ -1,5 +1,7 @@ import sys + import pytest + import OMPython skip_on_windows = pytest.mark.skipif( diff --git a/tests/test_typedParser.py b/tests/test_typedParser.py deleted file mode 100644 index 8e74a556..00000000 --- a/tests/test_typedParser.py +++ /dev/null @@ -1,53 +0,0 @@ -from OMPython import OMTypedParser - -typeCheck = OMTypedParser.om_parser_typed - - -def test_newline_behaviour(): - pass - - -def test_boolean(): - assert typeCheck('true') is True - assert typeCheck('false') is False - - -def test_int(): - assert typeCheck('2') == 2 - assert type(typeCheck('1')) == int - assert type(typeCheck('123123123123123123232323')) == int - assert type(typeCheck('9223372036854775808')) == int - - -def test_float(): - assert type(typeCheck('1.2e3')) == float - - -def test_ident(): - assert typeCheck('blabla2') == "blabla2" - - -def test_empty(): - assert typeCheck('') is None - - -def test_str(): - pass - - -def test_UnStringable(): - pass - - -def test_everything(): - # this test used to be in OMTypedParser.py's main() - testdata = """ - (1.0,{{1,true,3},{"4\\" -",5.9,6,NONE ( )},record ABC - startTime = ErrorLevel.warning, - 'stop*Time' = SOME(1.0) -end ABC;}) - """ - expected = (1.0, ((1, True, 3), ('4"\n', 5.9, 6, None), {"'stop*Time'": 1.0, 'startTime': 'ErrorLevel.warning'})) - results = typeCheck(testdata) - assert results == expected