# Buggy code
def __call__(self, left, right):
    empty_left, empty_right = build_empty_df(left.dtypes), build_empty_df(right.dtypes)
    # left should have values to keep columns order.
    gen_left_data = [np.random.rand(1).astype(dt)[0] for dt in left.dtypes]
    empty_left = empty_left.append(
        pd.DataFrame([gen_left_data], columns=list(empty_left.columns)).astype(
            left.dtypes
        )
    )
    gen_right_data = [np.random.rand(1).astype(dt)[0] for dt in right.dtypes]
    empty_right = empty_right.append(
        pd.DataFrame([gen_right_data], columns=list(empty_right.columns)).astype(
            right.dtypes
        )
    )
    # this `merge` will check whether the combination of those arguments is valid
    merged = empty_left.merge(
        empty_right,
        how=self.how,
        on=self.on,
        left_on=self.left_on,
        right_on=self.right_on,
        left_index=self.left_index,
        right_index=self.right_index,
        sort=self.sort,
        suffixes=self.suffixes,
        copy=self.copy_,
        indicator=self.indicator,
        validate=self.validate,
    )

    # the `index_value` doesn't matter.
    index_tokenize_objects = [
        left,
        right,
        self.how,
        self.left_on,
        self.right_on,
        self.left_index,
        self.right_index,
    ]
    return self.new_dataframe(
        [left, right],
        shape=(np.nan, merged.shape[1]),
        dtypes=merged.dtypes,
        index_value=parse_index(merged.index, *index_tokenize_objects),
        columns_value=parse_index(merged.columns, store_data=True),
    )


# Traceback (KeyError)
In [4]: df = pd.DataFrame({'a': np.arange(10), 'b': np.random.rand(10)})

In [5]: df2 = df.copy()

In [6]: df2.set_index('a', inplace=True)

In [7]: df2
Out[7]:
b
a
0  0.984265
1  0.544014
2  0.592392
3  0.269762
4  0.236130
5  0.846061
6  0.308780
7  0.604834
8  0.973824
9  0.867099

In [8]: df.merge(df2, on='a')  # can work for pandas
Out[8]:
a       b_x       b_y
0  0  0.984265  0.984265
1  1  0.544014  0.544014
2  2  0.592392  0.592392
3  3  0.269762  0.269762
4  4  0.236130  0.236130
5  5  0.846061  0.846061
6  6  0.308780  0.308780
7  7  0.604834  0.604834
8  8  0.973824  0.973824
9  9  0.867099  0.867099

In [9]: import mars.dataframe as md

In [10]: mdf = md.DataFrame(df)

In [11]: mdf2 = md.DataFrame(df2)

In [12]: mdf.merge(mdf2, on='a')  # cannot work for mars dataframe
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-12-bd6a81883d3a> in <module>
----> 1 mdf.merge(mdf2, on='a')

~/Workspace/mars/mars/dataframe/merge/merge.py in merge(df, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, strategy, validate)
350         left_index=left_index, right_index=right_index, sort=sort, suffixes=suffixes,
351         copy=copy, indicator=indicator, validate=validate, object_type=ObjectType.dataframe)
--> 352     return op(df, right)
353
354

~/Workspace/mars/mars/dataframe/merge/merge.py in __call__(self, left, right)
174                                   left_index=self.left_index, right_index=self.right_index,
175                                   sort=self.sort, suffixes=self.suffixes,
--> 176                                   copy=self.copy_, indicator=self.indicator, validate=self.validate)
177
178         # the `index_value` doesn't matter.

~/miniconda3/lib/python3.7/site-packages/pandas/core/frame.py in merge(self, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
7292             copy=copy,
7293             indicator=indicator,
-> 7294             validate=validate,
7295         )
7296

~/miniconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
84         copy=copy,
85         indicator=indicator,
---> 86         validate=validate,
87     )
88     return op.get_result()

~/miniconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in __init__(self, left, right, how, on, left_on, right_on, axis, left_index, right_index, sort, suffixes, copy, indicator, validate)
625             self.right_join_keys,
626             self.join_names,
--> 627         ) = self._get_merge_keys()
628
629         # validate the merge keys dtypes. We may need to coerce

~/miniconda3/lib/python3.7/site-packages/pandas/core/reshape/merge.py in _get_merge_keys(self)
981                     if not is_rkey(rk):
982                         if rk is not None:
--> 983                             right_keys.append(right._get_label_or_level_values(rk))
984                         else:
985                             # work-around for merge_asof(right_index=True)

~/miniconda3/lib/python3.7/site-packages/pandas/core/generic.py in _get_label_or_level_values(self, key, axis)
1689             values = self.axes[axis].get_level_values(key)._values
1690         else:
-> 1691             raise KeyError(key)
1692
1693         # Check for duplicates

KeyError: 'a'

# Fixed code
def __call__(self, left, right):
    empty_left, empty_right = self._make_data(left), self._make_data(right)
    # this `merge` will check whether the combination of those arguments is valid
    merged = empty_left.merge(
        empty_right,
        how=self.how,
        on=self.on,
        left_on=self.left_on,
        right_on=self.right_on,
        left_index=self.left_index,
        right_index=self.right_index,
        sort=self.sort,
        suffixes=self.suffixes,
        copy=self.copy_,
        indicator=self.indicator,
        validate=self.validate,
    )

    # the `index_value` doesn't matter.
    index_tokenize_objects = [
        left,
        right,
        self.how,
        self.left_on,
        self.right_on,
        self.left_index,
        self.right_index,
    ]
    return self.new_dataframe(
        [left, right],
        shape=(np.nan, merged.shape[1]),
        dtypes=merged.dtypes,
        index_value=parse_index(merged.index, *index_tokenize_objects),
        columns_value=parse_index(merged.columns, store_data=True),
    )