Skip to content

Commit d4df231

Browse files
authored
Merge pull request #9 from MPython-Package-Factory/no-spm-dep
ENH: do not explicitly import spm._spm
2 parents 7a91ff8 + 8673465 commit d4df231

File tree

12 files changed

+309
-162
lines changed

12 files changed

+309
-162
lines changed

mpython/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "25.04alpha3"
1+
__version__ = "25.04rc1"

mpython/array.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import numpy as np
22

33
from .core import WrappedArray, _ListishMixin
4-
from .utils import _copy_if_needed
4+
from .utils import _copy_if_needed, DelayedImport
5+
6+
7+
class _imports(DelayedImport):
8+
Cell = 'mpython.cell.Cell'
59

610

711
class Array(_ListishMixin, WrappedArray):
@@ -48,7 +52,7 @@ def _as_runtime(self) -> np.ndarray:
4852
return np.ndarray.view(self, np.ndarray)
4953

5054
@classmethod
51-
def _from_runtime(cls, other) -> "Array":
55+
def _from_runtime(cls, other, runtime=None) -> "Array":
5256
other = np.asarray(other)
5357
if len(other.shape) == 2 and other.shape[0] == 1:
5458
other = other.squeeze(0)
@@ -176,7 +180,7 @@ def from_cell(cls, other, **kwargs) -> "Array":
176180
array : Array
177181
Converted array.
178182
"""
179-
from .cell import Cell # FIXME: avoid circular import
183+
Cell = _imports.Cell
180184

181185
if not isinstance(other, Cell):
182186
raise TypeError(f"Expected a {Cell} but got a {type(other)}")

mpython/cell.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import numpy as np
22

3-
from .core import AnyDelayedArray, DelayedCell, MatlabType, WrappedArray, _ListMixin
4-
from .utils import _copy_if_needed, _empty_array, _import_matlab, _matlab_array_types
5-
6-
global matlab
3+
from .core import (
4+
AnyDelayedArray, DelayedCell, MatlabType, WrappedArray, _ListMixin
5+
)
6+
from .utils import _copy_if_needed, _empty_array, _matlab_array_types
77

88

99
class Cell(_ListMixin, WrappedArray):
@@ -67,7 +67,8 @@ class Cell(_ListMixin, WrappedArray):
6767
def _DEFAULT(cls, shape: list = ()) -> np.ndarray:
6868
data = np.empty(shape, dtype=object)
6969
opt = dict(
70-
flags=["refs_ok", "zerosize_ok"], op_flags=["writeonly", "no_broadcast"]
70+
flags=["refs_ok", "zerosize_ok"],
71+
op_flags=["writeonly", "no_broadcast"]
7172
)
7273
with np.nditer(data, **opt) as iter:
7374
for elem in iter:
@@ -77,7 +78,8 @@ def _DEFAULT(cls, shape: list = ()) -> np.ndarray:
7778
def _fill_default(self):
7879
arr = np.ndarray.view(self, np.ndarray)
7980
opt = dict(
80-
flags=["refs_ok", "zerosize_ok"], op_flags=["writeonly", "no_broadcast"]
81+
flags=["refs_ok", "zerosize_ok"],
82+
op_flags=["writeonly", "no_broadcast"]
8183
)
8284
with np.nditer(arr, **opt) as iter:
8385
for elem in iter:
@@ -106,7 +108,7 @@ def _as_runtime(self) -> dict:
106108
return dict(type__="cell", size__=size, data__=data)
107109

108110
@classmethod
109-
def _from_runtime(cls, objdict: dict) -> "Cell":
111+
def _from_runtime(cls, objdict: dict, runtime=None) -> "Cell":
110112
if isinstance(objdict, (list, tuple, set)):
111113
shape = [len(objdict)]
112114
objdict = dict(type__="cell", size__=shape, data__=objdict)
@@ -126,16 +128,18 @@ def _from_runtime(cls, objdict: dict) -> "Cell":
126128
obj = data.view(cls)
127129
except Exception:
128130
raise RuntimeError(
129-
f"Failed to construct Cell data:\n data={data}\n objdict={objdict}"
131+
f"Failed to construct Cell data:\n"
132+
f" data={data}\n objdict={objdict}"
130133
)
131134

132135
# recurse
133136
opt = dict(
134-
flags=["refs_ok", "zerosize_ok"], op_flags=["readwrite", "no_broadcast"]
137+
flags=["refs_ok", "zerosize_ok"],
138+
op_flags=["readwrite", "no_broadcast"]
135139
)
136140
with np.nditer(data, **opt) as iter:
137141
for elem in iter:
138-
elem[()] = MatlabType._from_runtime(elem.item())
142+
elem[()] = MatlabType._from_runtime(elem.item(), runtime)
139143

140144
return obj
141145

@@ -217,10 +221,6 @@ def from_any(cls, other, **kwargs) -> "Cell":
217221

218222
# recursive shallow conversion
219223
if not deepcat:
220-
# make sure matlab is imported so that we can detect
221-
# matlab arrays.
222-
_import_matlab()
223-
224224
# This is so list[list] are converted to Cell[Cell] and
225225
# not to a 2D Cell array.
226226
def asrecursive(other):
@@ -266,7 +266,8 @@ def asrecursive(other):
266266

267267
# recurse
268268
opt = dict(
269-
flags=["refs_ok", "zerosize_ok"], op_flags=["readwrite", "no_broadcast"]
269+
flags=["refs_ok", "zerosize_ok"],
270+
op_flags=["readwrite", "no_broadcast"]
270271
)
271272
with np.nditer(other, **opt) as iter:
272273
for elem in iter:
@@ -286,7 +287,8 @@ def _unroll_build(cls, arr):
286287
rebuild = False
287288
arr = np.asarray(arr)
288289
opt = dict(
289-
flags=["refs_ok", "zerosize_ok"], op_flags=["readwrite", "no_broadcast"]
290+
flags=["refs_ok", "zerosize_ok"],
291+
op_flags=["readwrite", "no_broadcast"]
290292
)
291293
with np.nditer(arr, **opt) as iter:
292294
for elem in iter:

mpython/core/base_types.py

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22

33
import numpy as np
44

5-
from ..utils import _import_matlab, _matlab_array_types
5+
from ..utils import _import_matlab, _matlab_array_types, DelayedImport
6+
7+
8+
class _imports(DelayedImport):
9+
Array = 'mpython.array.Array'
10+
Cell = 'mpython.cell.Cell'
11+
Struct = 'mpython.struct.Struct'
12+
SparseArray = 'mpython.sparse_array.SparseArray'
13+
MatlabClass = 'mpython.matlab_class.MatlabClass'
14+
MatlabFunction = 'mpython.matlab_function.MatlabFunction'
15+
AnyDelayedArray = 'mpython.core.delayed_types.AnyDelayedArray'
616

717

818
class MatlabType:
@@ -16,16 +26,14 @@ def from_any(cls, other, **kwargs):
1626
1727
!!! warning "Conversion is performed in-place when possible."
1828
"""
19-
# FIXME: Circular import
20-
from ..array import Array
21-
22-
# FIXME: Circular import
23-
from ..cell import Cell
24-
from ..matlab_class import MatlabClass
25-
from ..matlab_function import MatlabFunction
26-
from ..sparse_array import SparseArray
27-
from ..struct import Struct
28-
from .delayed_types import AnyDelayedArray
29+
# Circular import
30+
Array = _imports.Array
31+
Cell = _imports.Cell
32+
MatlabClass = _imports.MatlabClass
33+
MatlabFunction = _imports.MatlabFunction
34+
SparseArray = _imports.SparseArray
35+
Struct = _imports.Struct
36+
AnyDelayedArray = _imports.AnyDelayedArray
2937

3038
# Conversion rules:
3139
# - we do not convert to matlab's own array types
@@ -34,7 +42,7 @@ def from_any(cls, other, **kwargs):
3442
# the matlab runtime;
3543
# - instead, we convert to python types that mimic matlab types.
3644
_from_any = partial(cls.from_any, **kwargs)
37-
_from_runtime = kwargs.pop("_from_runtime", False)
45+
_runtime = kwargs.pop("_runtime", None)
3846

3947
if isinstance(other, MatlabType):
4048
if isinstance(other, AnyDelayedArray):
@@ -56,21 +64,21 @@ def from_any(cls, other, **kwargs):
5664
elif type__ == "structarray":
5765
# MPython returns a list of dictionaries in data__
5866
# and the array shape in size__.
59-
return Struct._from_runtime(other)
67+
return Struct._from_runtime(other, _runtime)
6068

6169
elif type__ == "cell":
6270
# MPython returns a list of dictionaries in data__
6371
# and the array shape in size__.
64-
return Cell._from_runtime(other)
72+
return Cell._from_runtime(other, _runtime)
6573

6674
elif type__ == "object":
6775
# MPython returns the object's fields serialized
6876
# in a dictionary.
69-
return MatlabClass._from_runtime(other)
77+
return MatlabClass._from_runtime(other, _runtime)
7078

7179
elif type__ == "sparse":
7280
# MPython returns the coordinates and values in a dict.
73-
return SparseArray._from_runtime(other)
81+
return SparseArray._from_runtime(other, _runtime)
7482

7583
elif type__ == "char":
7684
# Character array that is not a row vector
@@ -82,26 +90,28 @@ def from_any(cls, other, **kwargs):
8290
size = size[:-1] + [1]
8391
other["type__"] = "cell"
8492
other["size__"] = np.asarray([size])
85-
return Cell._from_runtime(other)
93+
return Cell._from_runtime(other, _runtime)
8694

8795
else:
8896
raise ValueError("Don't know what to do with type", type__)
8997

9098
else:
91-
other = type(other)(zip(other.keys(), map(_from_any, other.values())))
99+
other = type(other)(
100+
zip(other.keys(), map(_from_any, other.values()))
101+
)
92102
return Struct.from_any(other)
93103

94104
if isinstance(other, (list, tuple, set)):
95105
# nested tuples are cells of cells, not cell arrays
96-
if _from_runtime:
97-
return Cell._from_runtime(other)
106+
if _runtime:
107+
return Cell._from_runtime(other, _runtime)
98108
else:
99109
return Cell.from_any(other)
100110

101111
if isinstance(other, (np.ndarray, int, float, complex, bool)):
102112
# [array of] numbers -> Array
103-
if _from_runtime:
104-
return Array._from_runtime(other)
113+
if _runtime:
114+
return Array._from_runtime(other, _runtime)
105115
else:
106116
return Array.from_any(other)
107117

@@ -117,20 +127,20 @@ def from_any(cls, other, **kwargs):
117127

118128
matlab = _import_matlab()
119129
if matlab and isinstance(other, matlab.object):
120-
return MatlabFunction.from_any(other)
130+
return MatlabFunction._from_runtime(other, _runtime)
121131

122132
if type(other) in _matlab_array_types():
123-
return Array._from_runtime(other)
133+
return Array._from_runtime(other, _runtime)
124134

125135
if hasattr(other, "__iter__"):
126136
# Iterable -> let's try to make it a cell
127-
return cls.from_any(list(other), _from_runtime=_from_runtime)
137+
return cls.from_any(list(other), _runtime=_runtime)
128138

129139
raise TypeError(f"Cannot convert {type(other)} into a matlab object.")
130140

131141
@classmethod
132-
def _from_runtime(cls, obj):
133-
return cls.from_any(obj, _from_runtime=True)
142+
def _from_runtime(cls, obj, _runtime):
143+
return cls.from_any(obj, _runtime=_runtime)
134144

135145
@classmethod
136146
def _to_runtime(cls, obj):
@@ -162,8 +172,7 @@ def _to_runtime(cls, obj):
162172
return obj
163173

164174
elif sparse and isinstance(obj, sparse.sparray):
165-
from .SparseArray import SparseArray
166-
175+
SparseArray = _imports.SparseArray
167176
return SparseArray.from_any(obj)._as_runtime()
168177

169178
else:
@@ -192,14 +201,20 @@ class AnyMatlabArray(MatlabType):
192201

193202
@property
194203
def as_num(self):
195-
raise TypeError(f"Cannot interpret a {type(self).__name__} as a numeric array")
204+
raise TypeError(
205+
f"Cannot interpret a {type(self).__name__} as a numeric array"
206+
)
196207

197208
@property
198209
def as_cell(self):
199-
raise TypeError(f"Cannot interpret a {type(self).__name__} as a cell")
210+
raise TypeError(
211+
f"Cannot interpret a {type(self).__name__} as a cell"
212+
)
200213

201214
@property
202215
def as_struct(self):
203-
raise TypeError(f"Cannot interpret a {type(self).__name__} as a struct")
216+
raise TypeError(
217+
f"Cannot interpret a {type(self).__name__} as a struct"
218+
)
204219

205220
# TODO: `as_obj` for object arrays?

0 commit comments

Comments
 (0)