# Buggy code
def shuffle(*arrays, **options):
    arrays = [convert_to_tensor_or_dataframe(ar) for ar in arrays]
    axes = options.pop("axes", (0,))
    if not isinstance(axes, Iterable):
        axes = (axes,)
    elif not isinstance(axes, tuple):
        axes = tuple(axes)
    random_state = check_random_state(options.pop("random_state", None)).to_numpy()
    if options:
        raise TypeError(
            "shuffle() got an unexpected keyword argument {0}".format(
                next(iter(options))
            )
        )

    max_ndim = max(ar.ndim for ar in arrays)
    axes = tuple(np.unique([validate_axis(max_ndim, ax) for ax in axes]))
    seeds = gen_random_seeds(len(axes), random_state)

    # verify shape
    for ax in axes:
        shapes = {ar.shape[ax] for ar in arrays if ax < ar.ndim}
        if len(shapes) > 1:
            raise ValueError("arrays do not have same shape on axis {0}".format(ax))

    op = LearnShuffle(axes=axes, seeds=seeds, output_types=get_output_types(*arrays))
    shuffled_arrays = op(arrays)
    if len(arrays) == 1:
        return shuffled_arrays[0]
    else:
        return ExecutableTuple(shuffled_arrays)


# Traceback (TypeError)
In [14]: from mars.learn.utils import shuffle

In [15]: X, y = shuffle(X, y)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider.serialize_field()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider._serialize_value()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider._serialize_typed_value()

TypeError: Expected tuple, got numpy.ndarray

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
<ipython-input-15-0c15ee335b21> in <module>
----> 1 X, y = shuffle(X, y)

~/Workspace/mars/mars/learn/utils/shuffle.py in shuffle(*arrays, **options)
413     op = LearnShuffle(axes=axes, seeds=seeds,
414                       output_types=get_output_types(*arrays))
--> 415     shuffled_arrays = op(arrays)
416     if len(arrays) == 1:
417         return shuffled_arrays[0]

~/Workspace/mars/mars/learn/utils/shuffle.py in __call__(self, arrays)
92     def __call__(self, arrays):
93         params = self._calc_params([ar.params for ar in arrays])
---> 94         return self.new_tileables(arrays, kws=params)
95
96     def _shuffle_index_value(self, index_value):

~/Workspace/mars/mars/operands.py in new_tileables(self, inputs, kws, **kw)
351         tileables = self._new_tileables(inputs, kws=kws, **kw)
352         if is_eager_mode():
--> 353             ExecutableTuple(tileables).execute(fetch=False)
354         return tileables
355

~/Workspace/mars/mars/core.py in execute(self, session, **kw)
626         if session is None:
627             session = Session.default_or_local()
--> 628         return session.run(self, **kw)
629
630     def fetch(self, session=None, **kw):

~/Workspace/mars/mars/session.py in run(self, *tileables, **kw)
184         tileables = tuple(mt.tensor(t) if not isinstance(t, (Entity, Base)) else t
185                           for t in tileables)
--> 186         result = self._sess.run(*tileables, **kw)
187
188         for t in tileables:

~/Workspace/mars/mars/deploy/local/session.py in run(self, *tileables, **kw)
124
125         # submit graph to local cluster
--> 126         self._api.submit_graph(self._session_id, json.dumps(graph.to_json(), separators=(',', ':')),
127                                graph_key, targets, compose=compose)
128

~/Workspace/mars/mars/graph.pyx in mars.graph.DirectedGraph.to_json()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Serializable.to_json()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Serializable.serialize()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Provider.serialize_model()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Field.serialize()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Field.serialize()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider.serialize_field()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider._serialize_reference()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.AttributeAsDict.serialize()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Provider.serialize_attribute_as_dict()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Provider.serialize_model()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Field.serialize()

~/Workspace/mars/mars/serialize/core.pyx in mars.serialize.core.Field.serialize()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider.serialize_field()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider.serialize_field()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider._serialize_value()

~/Workspace/mars/mars/serialize/jsonserializer.pyx in mars.serialize.jsonserializer.JsonSerializeProvider._serialize_typed_value()

TypeError: Fail to serialize field `seeds` for LearnShuffle <key=4901c18065398f9e19eec455538bc65a>, reason: Expected tuple, got numpy.ndarray

# Fixed code
def shuffle(*arrays, **options):
    arrays = [convert_to_tensor_or_dataframe(ar) for ar in arrays]
    axes = options.pop("axes", (0,))
    if not isinstance(axes, Iterable):
        axes = (axes,)
    elif not isinstance(axes, tuple):
        axes = tuple(axes)
    random_state = check_random_state(options.pop("random_state", None)).to_numpy()
    if options:
        raise TypeError(
            "shuffle() got an unexpected keyword argument {0}".format(
                next(iter(options))
            )
        )

    max_ndim = max(ar.ndim for ar in arrays)
    axes = tuple(np.unique([validate_axis(max_ndim, ax) for ax in axes]))
    seeds = gen_random_seeds(len(axes), random_state)

    # verify shape
    for ax in axes:
        shapes = {ar.shape[ax] for ar in arrays if ax < ar.ndim}
        if len(shapes) > 1:
            raise ValueError("arrays do not have same shape on axis {0}".format(ax))

    op = LearnShuffle(
        axes=axes, seeds=tuple(seeds), output_types=get_output_types(*arrays)
    )
    shuffled_arrays = op(arrays)
    if len(arrays) == 1:
        return shuffled_arrays[0]
    else:
        return ExecutableTuple(shuffled_arrays)