Skip to content

Commit 9367c44

Browse files
committed
Fix conversion of cells (or cells of cells) from matlab
1 parent dcb77fb commit 9367c44

2 files changed

Lines changed: 35 additions & 13 deletions

File tree

spm/__wrapper__.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ def from_any(cls, other):
294294
if isinstance(other, str):
295295
return other
296296

297+
if isinstance(other, bytes):
298+
return other.decode()
299+
297300
if other is None:
298301
# This can happen when matlab code is called without `nargout`
299302
return other
@@ -308,6 +311,10 @@ def from_any(cls, other):
308311
dtype = _matlab_array_types()[type(other)]
309312
return Array.from_any(other, dtype=dtype)
310313

314+
if hasattr(other, "__iter__"):
315+
# Iterable -> let's try to make it a cell
316+
return cls.from_any(list(other))
317+
311318
raise TypeError(
312319
f"Cannot convert {type(other)} into a matlab object."
313320
)
@@ -1736,27 +1743,24 @@ def _as_runtime(self) -> dict:
17361743
def _from_runtime(cls, objdict: dict) -> "Cell":
17371744
if objdict['type__'] != 'cell':
17381745
raise TypeError('objdict is not a cell')
1739-
size = np.array(objdict['size__'], dtype=np.uint32).ravel()
1740-
data = np.array(objdict['data__'], dtype=object)
1741-
data = data.reshape(size[::-1]).transpose()
17421746
try:
1743-
obj = data.view(cls)
1747+
size = np.array(objdict['size__'], dtype=np.uint32).ravel()
1748+
data = objdict['data__']
1749+
obj = Cell.from_shape([len(data)])
1750+
opt = dict(flags=['refs_ok', 'zerosize_ok', 'multi_index'],
1751+
op_flags=['writeonly', 'no_broadcast'])
1752+
with np.nditer(obj, **opt) as iter:
1753+
for elem in iter:
1754+
elem[()] = MatlabType.from_any(data[iter.multi_index[0]])
1755+
obj = obj.reshape(size[::-1]).transpose()
1756+
return obj
17441757
except Exception:
17451758
raise RuntimeError(
17461759
f'Failed to construct Cell data:\n'
17471760
f' data={data}\n'
17481761
f' objdict={objdict}'
17491762
)
17501763

1751-
# recurse
1752-
opt = dict(flags=['refs_ok', 'zerosize_ok'],
1753-
op_flags=['readwrite', 'no_broadcast'])
1754-
with np.nditer(data, **opt) as iter:
1755-
for elem in iter:
1756-
elem[()] = MatlabType.from_any(elem.item())
1757-
1758-
return obj
1759-
17601764
@classmethod
17611765
def from_shape(cls, shape=tuple(), **kwargs) -> "Cell":
17621766
"""
@@ -1833,6 +1837,8 @@ def from_any(cls, other, **kwargs) -> "Cell":
18331837
# recursive shallow conversion
18341838
if not deepcat:
18351839

1840+
# This is so list[list] are converted to Cell[Cell] and
1841+
# not to a 2D Cell array.
18361842
def asrecursive(other):
18371843
if isinstance(other, np.ndarray):
18381844
return other
@@ -1850,6 +1856,7 @@ def asrecursive(other):
18501856
return other
18511857

18521858
other = asrecursive(other)
1859+
18531860
if not isinstance(other, np.ndarray):
18541861
other = np.asanyarray(other, **kwargs)
18551862

tests/test_cell.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ def test_as_cell(self):
6363
c = Cell()
6464
self.assertTrue(c.as_cell is c)
6565

66+
def test_empty1d_row_from_matlab(self):
67+
c_matlab = Runtime.call("cell", 1, 3)
68+
c_python = Cell.from_shape([3])
69+
self.assertListEqual(c_matlab.tolist(), c_python.tolist())
70+
71+
def test_empty1d_col_from_matlab(self):
72+
c_matlab = Runtime.call("cell", 3, 1)
73+
c_python = Cell.from_shape([3, 1])
74+
self.assertListEqual(c_matlab.tolist(), c_python.tolist())
75+
76+
def test_empty2d_from_matlab(self):
77+
c_matlab = Runtime.call("cell", 3, 2)
78+
c_python = Cell.from_shape([3, 2])
79+
self.assertListEqual(c_matlab.tolist(), c_python.tolist())
80+
6681
def test_cell1d_from_matlab(self):
6782
c_matlab = Runtime.call("eval", "{1, 2, 3}")
6883
c_python = Cell.from_any([1, 2, 3])

0 commit comments

Comments
 (0)