diff --git a/spm/__wrapper__/array.py b/spm/__wrapper__/array.py index 08b795319..d87c946de 100644 --- a/spm/__wrapper__/array.py +++ b/spm/__wrapper__/array.py @@ -1,11 +1,11 @@ +import numpy as np + from .core import ( - WrappedArray, + WrappedArray, _ListishMixin ) from .utils import _copy_if_needed -import numpy as np - class Array(_ListishMixin, WrappedArray): """ @@ -178,7 +178,7 @@ def from_cell(cls, other, **kwargs) -> "Array": array : Array Converted array. """ - from .cell import Cell # FIXME: avoid circular import + from .cell import Cell # FIXME: avoid circular import if not isinstance(other, Cell): raise TypeError(f"Expected a {Cell} but got a {type(other)}") @@ -200,4 +200,4 @@ def __repr__(self): # Scalar -> display as python scalar return np.array2string(self, separator=", ") else: - return super().__repr__() \ No newline at end of file + return super().__repr__() diff --git a/spm/__wrapper__/cell.py b/spm/__wrapper__/cell.py index ddd0c4e14..1a3bee3b0 100644 --- a/spm/__wrapper__/cell.py +++ b/spm/__wrapper__/cell.py @@ -1,3 +1,4 @@ +import numpy as np from .core import ( MatlabType, WrappedArray, @@ -6,15 +7,13 @@ _ListMixin, ) from .utils import ( - _empty_array, - _copy_if_needed, - _import_matlab, + _empty_array, + _copy_if_needed, + _import_matlab, _matlab_array_types ) global matlab -import numpy as np - class Cell(_ListMixin, WrappedArray): """ diff --git a/spm/__wrapper__/core/base_types.py b/spm/__wrapper__/core/base_types.py index e82c235ee..ad4c4258e 100644 --- a/spm/__wrapper__/core/base_types.py +++ b/spm/__wrapper__/core/base_types.py @@ -1,9 +1,10 @@ +from functools import partial +import numpy as np from ..utils import ( _matlab_array_types, _import_matlab, -) -from functools import partial -import numpy as np +) + class MatlabType(object): """Generic type for objects that have an exact matlab equivalent.""" @@ -16,10 +17,10 @@ def from_any(cls, other, **kwargs): !!! warning "Conversion is performed in-place when possible." """ - # FIXME: Circular import + # FIXME: Circular import from .delayed_types import AnyDelayedArray - # FIXME: Circular import + # FIXME: Circular import from ..cell import Cell from ..array import Array from ..matlab_function import MatlabFunction @@ -45,11 +46,20 @@ def from_any(cls, other, **kwargs): if "type__" in other: type__ = other["type__"] - if type__ == "structarray": + if type__ == "none": + # MPython returns this when run with nargout=1 but + # should have been nargout=0 + return None + + elif type__ == "structarray": # MPython returns a list of dictionaries in data__ # and the array shape in size__. return Struct._from_runtime(other) + elif type__ == "emptystruct": + # 0x0 struct + return Struct.from_shape([0]) + elif type__ == "cell": # MPython returns a list of dictionaries in data__ # and the array shape in size__. @@ -81,8 +91,7 @@ def from_any(cls, other, **kwargs): else: other = type(other)( - zip(other.keys(), - map(_from_any, other.values())) + zip(other.keys(), map(_from_any, other.values())) ) return Struct.from_any(other) @@ -135,7 +144,7 @@ def _to_runtime(cls, obj): Convert object to representation that the matlab runtime understands. """ to_runtime = cls._to_runtime - from ..utils import sparse # FIXME: Circular import + from ..utils import sparse # FIXME: Circular import if isinstance(obj, MatlabType): # class / structarray / cell @@ -159,7 +168,7 @@ def _to_runtime(cls, obj): return obj elif sparse and isinstance(obj, sparse.sparray): - from .SparseArray import SparseArray + from ..sparse_array import SparseArray return SparseArray.from_any(obj)._as_runtime() else: @@ -182,6 +191,7 @@ def _as_matlab_object(self): # FIXME: Or just keep `_as_matlab_object` and remove `_as_runtime`? return self._as_runtime() + class AnyMatlabArray(MatlabType): """Base class for all matlab-like arrays (numeric, cell, struct).""" @@ -203,4 +213,4 @@ def as_struct(self): f"Cannot interpret a {type(self).__name__} as a struct" ) - # TODO: `as_obj` for object arrays? \ No newline at end of file + # TODO: `as_obj` for object arrays? diff --git a/spm/__wrapper__/core/delayed_types.py b/spm/__wrapper__/core/delayed_types.py index 7e5303d71..9f93368fc 100644 --- a/spm/__wrapper__/core/delayed_types.py +++ b/spm/__wrapper__/core/delayed_types.py @@ -256,6 +256,7 @@ def __setattr__(self, key, value): self.as_struct[key] = value return self._finalize() # Setter -> we can trigger finalize + class WrappedDelayedArray(AnyDelayedArray): """ Base class for future objects with known type. diff --git a/spm/__wrapper__/core/mixin_types.py b/spm/__wrapper__/core/mixin_types.py index 9c10c75d9..feb7d1715 100644 --- a/spm/__wrapper__/core/mixin_types.py +++ b/spm/__wrapper__/core/mixin_types.py @@ -1,16 +1,17 @@ +from collections.abc import ( + MutableSequence, + MutableMapping, + KeysView, + ValuesView, + ItemsView +) +import numpy as np + from .base_types import MatlabType from .wrapped_types import WrappedArray from .delayed_types import AnyDelayedArray from ..utils import _matlab_array_types, _empty_array -import numpy as np -from collections.abc import ( - MutableSequence, - MutableMapping, - KeysView, - ValuesView, - ItemsView -) class _ListishMixin: """These methods are implemented in Cell and Array, but not Struct.""" @@ -81,7 +82,7 @@ def _from_runtime(cls, dictobj: dict): indices = np.asarray(dictobj['indices__'], dtype=np.long) - 1 values = np.asarray(dictobj['values__'], dtype=dtype).ravel() return cls.from_coo(values, indices.T, size) - + class _ListMixin(_ListishMixin, MutableSequence): """These methods are implemented in Cell, but not in Array or Struct.""" @@ -303,7 +304,6 @@ def sort(self, *, key=None, reverse=False, kind="stable", axis=0): self.reverse() - class _DictMixin(MutableMapping): # NOTE: @@ -446,7 +446,7 @@ def __getitem__(self, key): parent = getattr(self, "_delayed_wrapper", self) - from ..struct import Struct # FIXME: circular imports + from ..struct import Struct # FIXME: circular imports delayed = Struct(self.shape) opt = dict( flags=['refs_ok', 'zerosize_ok', 'multi_index'], @@ -527,7 +527,7 @@ def setdefault(self, key, value=None): item.setdefault(key, value) def update(self, other): - from ..struct import Struct # FIXME: circular imports + from ..struct import Struct # FIXME: circular imports other = Struct.from_any(other) other = np.ndarray.view(other, np.ndarray) other = np.broadcast_to(other, self.shape) @@ -542,7 +542,7 @@ def update(self, other): item.update(other_elem) # --- helper ------------------------------------------------------ - class deal: # FIXME: Removed dependency to Cell + class deal: # FIXME: Removed dependency to Cell """ Helper class to assign values into a specific field of a Struct array. @@ -573,6 +573,5 @@ def broadcast_to_struct(self, struct): return np.broadcast_to(self, shape) def to_cell(self): - from ..cell import Cell # FIXME: circular imports + from ..cell import Cell # FIXME: circular imports return np.ndarray.view(self, Cell) - diff --git a/spm/__wrapper__/core/wrapped_types.py b/spm/__wrapper__/core/wrapped_types.py index 3a84ea009..76eb1c567 100644 --- a/spm/__wrapper__/core/wrapped_types.py +++ b/spm/__wrapper__/core/wrapped_types.py @@ -1,6 +1,6 @@ from .base_types import ( - MatlabType, - AnyMatlabArray, + MatlabType, + AnyMatlabArray, ) from .delayed_types import ( AnyDelayedArray, @@ -9,6 +9,7 @@ ) import numpy as np + # ---------------------------------------------------------------------- # WrappedArray # ----------------------------------------------------------------------x @@ -294,7 +295,7 @@ def _resize_for_index(self, index, set_default=True): def _return_delayed(self, index): from ..cell import Cell - from ..struct import Struct # FIXME: avoid circular import + from ..struct import Struct # FIXME: avoid circular import if not isinstance(index, tuple): index = (index,) @@ -336,4 +337,4 @@ def _return_delayed(self, index): # In numeric arrays, only seeting OOB items is allowed. # Getting OOB items should raise an error, which this # call to the ndarray accessor will do. - return super().__getitem__(index) \ No newline at end of file + return super().__getitem__(index) diff --git a/spm/__wrapper__/matlab_class.py b/spm/__wrapper__/matlab_class.py index 3e1aa8041..2fa8d5012 100644 --- a/spm/__wrapper__/matlab_class.py +++ b/spm/__wrapper__/matlab_class.py @@ -1,7 +1,8 @@ +import warnings +import numpy as np + from .core import MatlabType -import numpy as np -import warnings class MatlabClass(MatlabType): _subclasses = dict() @@ -96,7 +97,7 @@ def _process_index(self, ind, k=1, n=1): ) except TypeError: pass - + from .runtime import Runtime if not hasattr(self, '__endfn'): diff --git a/spm/__wrapper__/matlab_function.py b/spm/__wrapper__/matlab_function.py index fdd78bd5a..c077c5858 100644 --- a/spm/__wrapper__/matlab_function.py +++ b/spm/__wrapper__/matlab_function.py @@ -1,6 +1,7 @@ from .core import MatlabType from .utils import _import_matlab + class MatlabFunction(MatlabType): """ Wrapper for matlab function handles. @@ -19,7 +20,7 @@ def __init__(self, matlab_object): matlab = _import_matlab() if not isinstance(matlab_object, matlab.object): raise TypeError("Expected a matlab.object") - + self._matlab_object = matlab_object def _as_runtime(self): @@ -37,4 +38,4 @@ def from_any(cls, other): def __call__(self, *args, **kwargs): from .runtime import Runtime - return Runtime.call(self._matlab_object, *args, **kwargs) \ No newline at end of file + return Runtime.call(self._matlab_object, *args, **kwargs) diff --git a/spm/__wrapper__/runtime.py b/spm/__wrapper__/runtime.py index 5fd1982aa..ee9c960f2 100644 --- a/spm/__wrapper__/runtime.py +++ b/spm/__wrapper__/runtime.py @@ -33,7 +33,7 @@ def _process_argin(*args, **kwargs): @staticmethod def _process_argout(res): - return MatlabType.from_any(res) + return MatlabType._from_runtime(res) @staticmethod def _import_initialize(): @@ -57,7 +57,7 @@ def _import_initialize(): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ print(Runtime._help) raise e - + # Make sure matlab is imported _import_matlab() @@ -69,4 +69,3 @@ def _import_initialize(): If the issue persists, please open an issue with the entire error message at https://github.com/spm/spm-python/issues. """ - diff --git a/spm/__wrapper__/sparse_array.py b/spm/__wrapper__/sparse_array.py index 66b141f13..12742ce8d 100644 --- a/spm/__wrapper__/sparse_array.py +++ b/spm/__wrapper__/sparse_array.py @@ -1,5 +1,8 @@ +import warnings +import numpy as np + from .core import ( - AnyWrappedArray, + AnyWrappedArray, _SparseMixin ) from .utils import ( @@ -8,8 +11,6 @@ ) from .array import Array -import numpy as np -import warnings if sparse: class WrappedSparseArray(sparse.sparray, AnyWrappedArray): @@ -205,4 +206,3 @@ def from_coo(cls, values, indices, shape=None, **kw) -> "SparseArray": obj = cls.from_shape(shape, dtype=dtype) obj[tuple(indices)] = values return obj - diff --git a/spm/__wrapper__/struct.py b/spm/__wrapper__/struct.py index 8c262b1e1..f04793175 100644 --- a/spm/__wrapper__/struct.py +++ b/spm/__wrapper__/struct.py @@ -1,3 +1,5 @@ +import numpy as np + from .core import ( WrappedArray, _DictMixin, @@ -5,12 +7,10 @@ DelayedStruct ) from .utils import ( - _copy_if_needed, + _copy_if_needed, _empty_array ) -import numpy as np - class Struct(_DictMixin, WrappedArray): """ @@ -358,7 +358,7 @@ def as_dict(self, keys=None) -> dict: raise ValueError(keys) return asdict - + def _allkeys(self): # Return all keys present across all elements. # Keys are ordered by (1) element (2) within-element order @@ -478,4 +478,3 @@ def __delattr__(self, key): return _DictMixin.__delitem__(self, key) except KeyError as e: raise AttributeError(str(e)) - diff --git a/spm/__wrapper__/utils.py b/spm/__wrapper__/utils.py index 048f24e19..47a546913 100644 --- a/spm/__wrapper__/utils.py +++ b/spm/__wrapper__/utils.py @@ -7,17 +7,19 @@ except (ImportError, ModuleNotFoundError): sparse = None + # ---------------------------------------------------------------------- # Helpers # ---------------------------------------------------------------------- + # We'll complain later if the runtime is not instantiated def _import_matlab(): try: import matlab except (ImportError, ModuleNotFoundError): matlab = None - return matlab + return matlab def _copy_if_needed(out, inp, copy=None) -> np.ndarray: