diff --git a/mcbackend/__init__.py b/mcbackend/__init__.py index 35ef7b9..c6a43eb 100644 --- a/mcbackend/__init__.py +++ b/mcbackend/__init__.py @@ -20,4 +20,4 @@ pass -__version__ = "0.2.3" +__version__ = "0.2.4" diff --git a/mcbackend/npproto/__init__.py b/mcbackend/npproto/__init__.py index 4554e02..e3d99a6 100644 --- a/mcbackend/npproto/__init__.py +++ b/mcbackend/npproto/__init__.py @@ -18,3 +18,4 @@ class Ndarray(betterproto.Message): dtype: str = betterproto.string_field(2) shape: List[int] = betterproto.int64_field(3) strides: List[int] = betterproto.int64_field(4) + order: str = betterproto.string_field(5) diff --git a/mcbackend/npproto/utils.py b/mcbackend/npproto/utils.py index 27bc98c..2dd0536 100644 --- a/mcbackend/npproto/utils.py +++ b/mcbackend/npproto/utils.py @@ -18,6 +18,7 @@ def ndarray_from_numpy(arr: numpy.ndarray) -> Ndarray: dtype=dt, data=bytes(arr.data), strides=list(arr.strides), + order="CF"[arr.flags.f_contiguous], ) @@ -38,4 +39,12 @@ def ndarray_to_numpy(nda: Ndarray) -> numpy.ndarray: dtype=numpy.dtype(nda.dtype), strides=nda.strides, ) + # The code that reads the bytes(arr.data) always results in C-ordered data. + # Passing `to the `np.ndarray(order=...)` call has no effect. + # This is where below workaround comes into play: + # It reshapes arrays that were originally in Fortran order. + # F-ordered arrays that were encoded with mcbackend < 0.2.4 default + # to `nda.order == ""` and there is nothing we can do for these. + if nda.order == "F": + arr = arr.T.reshape(arr.shape) return arr diff --git a/mcbackend/test_npproto.py b/mcbackend/test_npproto.py index 0ec5053..fc88d29 100644 --- a/mcbackend/test_npproto.py +++ b/mcbackend/test_npproto.py @@ -31,3 +31,15 @@ def test_conversion(self, arr: numpy.ndarray): result = utils.ndarray_to_numpy(dec) numpy.testing.assert_array_equal(result, arr) pass + + @pytest.mark.parametrize("shape", [(5,), (2, 3), (2, 3, 5), (5, 2, 1, 7)]) + @pytest.mark.parametrize("order", "CF") + def test_byteorders(self, shape, order): + arr = numpy.arange(numpy.prod(shape)).reshape(shape, order=order) + + nda = utils.ndarray_from_numpy(arr) + assert nda.order == "CF"[arr.flags.f_contiguous] + + dec = utils.ndarray_to_numpy(nda) + numpy.testing.assert_array_equal(arr, dec) + pass diff --git a/protobufs/npproto/ndarray.proto b/protobufs/npproto/ndarray.proto index fee734c..0a7d399 100644 --- a/protobufs/npproto/ndarray.proto +++ b/protobufs/npproto/ndarray.proto @@ -9,4 +9,5 @@ message ndarray { string dtype = 2; repeated int64 shape = 3; repeated int64 strides = 4; + string order = 5; }