Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ jobs:
- name: Install and Test with pytest
run: |
python -m pip install -e .[Dev]
pytest tests/ --cov=${{ github.event.repository.name }} --cov-report=html:htmlcov --cov-report=term
pytest tests/ --cov=RATpy --cov-report=term
34 changes: 25 additions & 9 deletions RATpy/wrappers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pathlib
from contextlib import suppress
from typing import Callable, Tuple

import numpy as np
Expand All @@ -7,6 +8,25 @@
import RATpy.rat_core


def start_matlab():
"""Starts MATLAB asynchronously and returns a future to retrieve the engine later

Returns
-------
future : matlab.engine.futureresult.FutureResult
A future used to get the actual matlab engine

"""
future = None
with suppress(ImportError):
import matlab.engine

future = matlab.engine.start_matlab(background=True)
print(future)
Comment thread
StephenNneji marked this conversation as resolved.
Outdated

return future


class MatlabWrapper:
"""Creates a python callback for a MATLAB function.

Expand All @@ -17,21 +37,17 @@ class MatlabWrapper:

"""

loader = start_matlab()

def __init__(self, filename: str) -> None:
self.engine = None
try:
import matlab.engine
except ImportError:
if self.loader is None:
raise ImportError("matlabengine is required to use MatlabWrapper") from None
self.engine = matlab.engine.start_matlab()

self.engine = self.loader.result()
path = pathlib.Path(filename)
self.engine.cd(str(path.parent), nargout=0)
self.function_name = path.stem

def __del__(self):
if self.engine is not None:
self.engine.quit()

def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]:
"""Returns a wrapper for the custom MATLAB function

Expand Down
1 change: 0 additions & 1 deletion requirements-dev.txt

This file was deleted.

1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pytest >= 7.4.0
pytest-cov >= 4.1.0
matplotlib >= 3.8.3
StrEnum >= 0.4.15; python_version < '3.11'
ruff >= 0.4.10
25 changes: 13 additions & 12 deletions tests/test_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,13 +618,14 @@ def test_make_input(test_project, test_problem, test_cells, test_limits, test_pr
"domainRatio",
]

mocked_matlab_module = mock.MagicMock()
mocked_matlab_future = mock.MagicMock()
mocked_engine = mock.MagicMock()
mocked_matlab_module.engine.start_matlab.return_value = mocked_engine
mocked_matlab_future.result.return_value = mocked_engine

with mock.patch.dict(
"sys.modules",
{"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine},
with mock.patch.object(
RATpy.wrappers.MatlabWrapper,
"loader",
mocked_matlab_future,
), mock.patch.object(RATpy.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object(
RATpy.inputs,
"get_python_handle",
Expand Down Expand Up @@ -757,13 +758,13 @@ def test_make_cells(test_project, test_cells, request) -> None:
test_project = request.getfixturevalue(test_project)
test_cells = request.getfixturevalue(test_cells)

mocked_matlab_module = mock.MagicMock()
mocked_matlab_engine = mock.MagicMock()
mocked_matlab_module.engine.start_matlab.return_value = mocked_matlab_engine

with mock.patch.dict(
"sys.modules",
{"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine},
mocked_matlab_future = mock.MagicMock()
mocked_engine = mock.MagicMock()
mocked_matlab_future.result.return_value = mocked_engine
with mock.patch.object(
RATpy.wrappers.MatlabWrapper,
"loader",
mocked_matlab_future,
), mock.patch.object(RATpy.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object(
RATpy.inputs,
"get_python_handle",
Expand Down
13 changes: 7 additions & 6 deletions tests/test_wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@


def test_matlab_wrapper() -> None:
with mock.patch.dict("sys.modules", {"matlab": mock.MagicMock(side_effect=ImportError)}), pytest.raises(
ImportError,
with (
mock.patch.object(RATpy.wrappers.MatlabWrapper, "loader", None),
pytest.raises(ImportError),
):
RATpy.wrappers.MatlabWrapper("demo.m")
mocked_matlab_module = mock.MagicMock()
mocked_engine = mock.MagicMock()
mocked_matlab_module.engine.start_matlab.return_value = mocked_engine

with mock.patch.dict("sys.modules", {"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine}):
mocked_matlab_future = mock.MagicMock()
mocked_engine = mock.MagicMock()
mocked_matlab_future.result.return_value = mocked_engine
with mock.patch.object(RATpy.wrappers.MatlabWrapper, "loader", mocked_matlab_future):
wrapper = RATpy.wrappers.MatlabWrapper("demo.m")
assert wrapper.function_name == "demo"
mocked_engine.cd.assert_called_once()
Expand Down