Skip to content

Commit eee9c83

Browse files
committed
Adds docstring, type hints, and unit tests
1 parent db451b5 commit eee9c83

12 files changed

Lines changed: 232 additions & 48 deletions

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ __pycache__/
2020
build/*
2121
dist/*
2222
*.whl
23+
24+
# test
25+
.coverage

‎MANIFEST.in‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ To install in local directory:
1616
To build wheel:
1717
pip install build
1818
python -m build --wheel
19+
20+
matlabengine is an optional dependency only required for Matlab custom functions. The version of matlabengine should match the version of Matlab installed on the machine. This can be installed as shown below:
21+
pip install -e .[Matlab-2023a]

‎cpp/rat.cpp‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,14 +1236,14 @@ PYBIND11_MODULE(rat_core, m) {
12361236

12371237
py::class_<PlotEventData>(m, "PlotEventData")
12381238
.def(py::init<>())
1239-
.def_readonly("reflectivity", &PlotEventData::reflectivity)
1240-
.def_readonly("shiftedData", &PlotEventData::shiftedData)
1241-
.def_readonly("sldProfiles", &PlotEventData::sldProfiles)
1242-
.def_readonly("allLayers", &PlotEventData::allLayers)
1243-
.def_readonly("ssubs", &PlotEventData::ssubs)
1244-
.def_readonly("resample", &PlotEventData::resample)
1245-
.def_readonly("dataPresent", &PlotEventData::dataPresent)
1246-
.def_readonly("modelType", &PlotEventData::modelType);
1239+
.def_readwrite("reflectivity", &PlotEventData::reflectivity)
1240+
.def_readwrite("shiftedData", &PlotEventData::shiftedData)
1241+
.def_readwrite("sldProfiles", &PlotEventData::sldProfiles)
1242+
.def_readwrite("allLayers", &PlotEventData::allLayers)
1243+
.def_readwrite("ssubs", &PlotEventData::ssubs)
1244+
.def_readwrite("resample", &PlotEventData::resample)
1245+
.def_readwrite("dataPresent", &PlotEventData::dataPresent)
1246+
.def_readwrite("modelType", &PlotEventData::modelType);
12471247

12481248
py::class_<BestFitsMean>(m, "BestFitsMean")
12491249
.def(py::init<>())

‎examples/DSPC_custom_layers_example.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import numpy as np
33
from customBilayer import customBilayer
44
from rat import events, rat_core
5-
from rat.misc import DylibWrapper # MatlabWrapper
5+
from rat.misc import DylibWrapper, MatlabWrapper
66

77
faulthandler.enable()
88

@@ -171,7 +171,7 @@
171171

172172

173173
def fakePlot(event):
174-
print("Hello plotting")
174+
print('Hello plotting')
175175

176176
import time
177177
start = time.perf_counter()

‎examples/domains_custom_layers_example.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import numpy as np
33
from alloyDomains import alloyDomains
44
from rat import events, rat_core
5-
from rat.misc import DylibWrapper # MatlabWrapper
5+
from rat.misc import DylibWrapper, MatlabWrapper
66

77
faulthandler.enable()
88

‎rat/events.py‎

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,49 @@
1+
from typing import Callable, Union, List
12
from rat import rat_core
2-
from rat.rat_core import EventTypes
3+
from rat.rat_core import EventTypes, PlotEventData
34

45

5-
def nofiy(event_type, data):
6+
def notify(event_type: EventTypes, data: Union[str, PlotEventData]) -> None:
7+
"""Calls registered callbacks with the data when event type has
8+
been triggered.
9+
10+
Parameters
11+
----------
12+
event_type : EventTypes
13+
The event type that was triggered.
14+
data : str or PlotEventData
15+
The data sent by th event. The message event data is a string.
16+
"""
617
callbacks = __event_callbacks[event_type]
718
for callback in callbacks:
819
callback(data)
920

21+
def get_event_callback(event_type: EventTypes) -> List[Callable[[Union[str, PlotEventData]], None]]:
22+
"""Returns all callbacks registered for the given event type.
23+
24+
Parameters
25+
----------
26+
event_type : EventTypes
27+
The event type.
28+
29+
Retuns
30+
------
31+
callback : Callable[[Union[str, PlotEventData]], None]
32+
The callback for the event type.
33+
"""
34+
return list(__event_callbacks[event_type])
35+
36+
37+
def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData]], None]) -> None:
38+
"""Registers a new callback for the event type.
1039
11-
def register(event_type, callback):
40+
Parameters
41+
----------
42+
event_type : EventTypes
43+
The event type to register.
44+
callback : Callable[[Union[str, PlotEventData]], None]
45+
The callback for when the event is triggered.
46+
"""
1247
if not isinstance(event_type, EventTypes):
1348
raise ValueError("event_type must be a events.EventTypes enum")
1449

@@ -17,10 +52,12 @@ def register(event_type, callback):
1752
__event_callbacks[event_type].add(callback)
1853

1954

20-
def clear():
55+
def clear() -> None:
56+
"""Clears all event callbacks."""
2157
__event_impl.clear()
22-
__event_callbacks.clear()
58+
for key in __event_callbacks.keys():
59+
__event_callbacks[key] = set()
2360

2461

25-
__event_impl = rat_core.EventBridge(nofiy)
62+
__event_impl = rat_core.EventBridge(notify)
2663
__event_callbacks = {EventTypes.Message: set(), EventTypes.Plot: set()}

‎rat/misc.py‎

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,80 @@
11
import pathlib
2+
from typing import Callable, Tuple
23
import numpy as np
4+
from numpy.typing import ArrayLike
35
from rat import rat_core
46

5-
try:
6-
import matlab.engine
7-
class MatlabWrapper:
8-
def __init__(self, filename):
9-
self.engine = matlab.engine.start_matlab()
10-
path = pathlib.Path(filename)
11-
self.engine.cd(str(path.parent), nargout=0)
12-
self.function_name = path.stem
137

14-
def __del__(self):
8+
class MatlabWrapper:
9+
"""Creates a python callback for a MATLAB function.
10+
11+
Parameters
12+
----------
13+
filename : string
14+
The path of the file containing MATLAB function
15+
"""
16+
def __init__(self, filename: str) -> None :
17+
self.engine = None
18+
try:
19+
import matlab.engine
20+
except ImportError:
21+
raise ImportError('matlabengine is required to use MatlabWrapper')
22+
self.engine = matlab.engine.start_matlab()
23+
path = pathlib.Path(filename)
24+
self.engine.cd(str(path.parent), nargout=0)
25+
self.function_name = path.stem
26+
27+
def __del__(self):
28+
if self.engine is not None:
1529
self.engine.quit()
1630

17-
def getHandle(self):
18-
def handle(params, bulk_in, bulk_out, contrast, domain=-1):
19-
if domain == -1:
20-
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
21-
np.array(bulk_in, 'float'),
22-
np.array(bulk_out, 'float'),
23-
float(contrast + 1), nargout=2)
24-
else:
25-
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
26-
np.array(bulk_in, 'float'),
27-
np.array(bulk_out, 'float'),
28-
float(contrast + 1), float(domain + 1), nargout=2)
29-
return output, sub_rough
30-
return handle
31-
except ImportError:
32-
pass # maybe should log matlab engine is not installed
31+
def getHandle(self)\
32+
-> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]:
33+
"""Returns a wrapper for the custom MATLAB function
34+
35+
Returns
36+
-------
37+
wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]
38+
The wrapper function for the MATLAB callback
39+
"""
40+
def handle(params, bulk_in, bulk_out, contrast, domain=-1):
41+
if domain == -1:
42+
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
43+
np.array(bulk_in, 'float'),
44+
np.array(bulk_out, 'float'),
45+
float(contrast + 1), nargout=2)
46+
else:
47+
output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'),
48+
np.array(bulk_in, 'float'),
49+
np.array(bulk_out, 'float'),
50+
float(contrast + 1), float(domain + 1), nargout=2)
51+
return output, sub_rough
52+
return handle
3353

3454

3555
class DylibWrapper:
36-
def __init__(self, filename, function_name):
56+
"""Creates a python callback for a function in dynamic library.
57+
58+
Parameters
59+
----------
60+
filename : str
61+
The path of the dyanamic library
62+
function_name : str
63+
The name of the function to call
64+
"""
65+
def __init__(self, filename, function_name) -> None:
3766
self.engine = rat_core.DylibEngine(filename, function_name)
3867

39-
def getHandle(self):
68+
def getHandle(self)\
69+
-> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]:
70+
71+
"""Returns a wrapper for the custom dynamic library function
72+
73+
Returns
74+
-------
75+
wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]
76+
The wrapper function for the dynamic library callback
77+
"""
4078
def handle(params, bulk_in, bulk_out, contrast, domain=-1):
4179
if domain == -1:
4280
output, sub_rough = self.engine.invoke(params, bulk_in, bulk_out, contrast)

‎setup.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def build_libraries(self, libraries):
143143
)
144144

145145
super().build_libraries(libraries)
146-
146+
147147

148148
setup(
149149
name='rat',
@@ -160,9 +160,9 @@ def build_libraries(self, libraries):
160160
ext_modules=ext_modules,
161161
install_requires=['numpy'],
162162
python_requires='>=3.9',
163-
# setup_requires=['pybind11>=2.4'],
164163
cmdclass={'build_clib': BuildClib, 'build_ext': BuildExt},
165-
extras_require={"Matlab_2023b": ["matlabengine==23.2.1"],
164+
extras_require={"Matlab_latest": ["matlabengine"],
165+
"Matlab_2023b": ["matlabengine==23.2.1"],
166166
"Matlab_2023a": ["matlabengine==9.14.3"],
167167
"Matlab-2022b": ["matlabengine==9.13.9"],
168168
"Matlab_2022a": ["matlabengine==9.12.19"],

‎tests/__init__.py‎

Whitespace-only changes.

0 commit comments

Comments
 (0)