# Buggy code
def _copartition(self, axis, other, how, sort, force_repartition=False):
    """Copartition two dataframes.

    Args:
        axis: The axis to copartition along.
        other: The other dataframes(s) to copartition against.
        how: How to manage joining the index object ("left", "right", etc.)
        sort: Whether or not to sort the joined index.
        force_repartition: Whether or not to force the repartitioning. By default,
            this method will skip repartitioning if it is possible. This is because
            reindexing is extremely inefficient. Because this method is used to
            `join` or `append`, it is vital that the internal indices match.

    Returns:
        A tuple (left data, right data list, joined index).
    """
    if isinstance(other, type(self)):
        other = [other]

    index_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis ^ 1, index_obj, how, sort)
    # We have to set these because otherwise when we perform the functions it may
    # end up serializing this entire object.
    left_old_idx = self.axes[axis]
    right_old_idxes = index_obj

    # Start with this and we'll repartition the first time, and then not again.
    if not left_old_idx.equals(joined_index) or force_repartition:
        reindexed_self = self._frame_mgr_cls.map_axis_partitions(
            axis, self._partitions, lambda df: df.reindex(joined_index, axis=axis)
        )
    else:
        reindexed_self = self._partitions
    reindexed_other_list = []

    for i in range(len(other)):
        if right_old_idxes[i].equals(joined_index) and not force_repartition:
            reindexed_other = other[i]._partitions
        else:
            reindexed_other = other[i]._frame_mgr_cls.map_axis_partitions(
                axis,
                other[i]._partitions,
                lambda df: df.reindex(joined_index, axis=axis),
            )
        reindexed_other_list.append(reindexed_other)
    return reindexed_self, reindexed_other_list, joined_index


# Traceback (IndexError)
import modin.pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [400, 500, 600]})
new_df = pd.DataFrame({'B': [4, 5, 6], 'C': [7, 8, 9]})
df.update(new_df)
df
IndexError                                Traceback (most recent call last)
python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
700                 type_pprinters=self.type_printers,
701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
703             printer.flush()
704             return stream.getvalue()

python3.7/site-packages/IPython/lib/pretty.py in pretty(self, obj)
392                         if cls is not object \
393                                 and callable(cls.__dict__.get('__repr__')):
--> 394                             return _repr_pprint(obj, self, cycle)
395
396             return _default_pprint(obj, self, cycle)

python3.7/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
682     """A pprint that just redirects to the normal repr function."""
683     # Find newlines and replace them with p.break_()
--> 684     output = repr(obj)
685     lines = output.splitlines()
686     with p.group():

modin/modin/pandas/dataframe.py in __repr__(self)
151
152             num_cols += len(self.columns) - i
--> 153         result = repr(self._build_repr_df(num_rows, num_cols))
154         if len(self.index) > num_rows or len(self.columns) > num_cols:
155             # The split here is so that we don't repr pandas row lengths.

modin/modin/pandas/base.py in _build_repr_df(self, num_rows, num_cols)
98         else:
99             indexer = row_indexer
--> 100         return self.iloc[indexer]._query_compiler.to_pandas()
101
102     def _update_inplace(self, new_query_compiler):

modin/modin/backends/pandas/query_compiler.py in to_pandas(self)
173
174     def to_pandas(self):
--> 175         return self._modin_frame.to_pandas()
176
177     @classmethod

modin/modin/engines/base/frame/data.py in to_pandas(self)
1291             Pandas DataFrame.
1292         """
-> 1293         df = self._frame_mgr_cls.to_pandas(self._partitions)
1294         if df.empty:
1295             if len(self.columns) != 0:

modin/modin/engines/base/frame/partition_manager.py in to_pandas(cls, partitions)
256             A Pandas DataFrame
257         """
--> 258         retrieved_objects = [[obj.to_pandas() for obj in part] for part in partitions]
259         if all(
260             isinstance(part, pandas.Series) for row in retrieved_objects for part in row

modin/modin/engines/base/frame/partition_manager.py in <listcomp>(.0)
256             A Pandas DataFrame
257         """
--> 258         retrieved_objects = [[obj.to_pandas() for obj in part] for part in partitions]
259         if all(
260             isinstance(part, pandas.Series) for row in retrieved_objects for part in row

modin/modin/engines/base/frame/partition_manager.py in <listcomp>(.0)
256             A Pandas DataFrame
257         """
--> 258         retrieved_objects = [[obj.to_pandas() for obj in part] for part in partitions]
259         if all(
260             isinstance(part, pandas.Series) for row in retrieved_objects for part in row

modin/modin/engines/python/pandas_on_python/frame/partition.py in to_pandas(self)
113             A Pandas DataFrame.
114         """
--> 115         dataframe = self.get()
116         assert type(dataframe) is pandas.DataFrame or type(dataframe) is pandas.Series
117

modin/modin/engines/python/pandas_on_python/frame/partition.py in get(self)
46             The object that was `put`.
47         """
---> 48         self.drain_call_queue()
49         return self.data.copy()
50

modin/modin/engines/python/pandas_on_python/frame/partition.py in drain_call_queue(self)
86         if len(self.call_queue) == 0:
87             return
---> 88         self.apply(lambda x: x)
89
90     def mask(self, row_indices=None, col_indices=None):

modin/modin/engines/python/pandas_on_python/frame/partition.py in apply(self, func, **kwargs)
74             return result
75
---> 76         self.data = call_queue_closure(self.data, self.call_queue)
77         self.call_queue = []
78         return PandasOnPythonFramePartition(func(self.data.copy(), **kwargs))

modin/modin/engines/python/pandas_on_python/frame/partition.py in call_queue_closure(data, call_queues)
71                 except Exception as e:
72                     self.call_queue = []
---> 73                     raise e
74             return result
75

modin/modin/engines/python/pandas_on_python/frame/partition.py in call_queue_closure(data, call_queues)
68             for func, kwargs in call_queues:
69                 try:
---> 70                     result = func(result, **kwargs)
71                 except Exception as e:
72                     self.call_queue = []

modin/modin/engines/python/pandas_on_python/frame/partition.py in <lambda>(df)
90     def mask(self, row_indices=None, col_indices=None):
91         new_obj = self.add_to_apply_calls(
---> 92             lambda df: pandas.DataFrame(df.iloc[row_indices, col_indices])
93         )
94         new_obj._length_cache = (

python3.7/site-packages/pandas/core/indexing.py in __getitem__(self, key)
1760                 except (KeyError, IndexError, AttributeError):
1761                     pass
-> 1762             return self._getitem_tuple(key)
1763         else:
1764             # we by definition only have the 0th axis

python3.7/site-packages/pandas/core/indexing.py in _getitem_tuple(self, tup)
2065     def _getitem_tuple(self, tup: Tuple):
2066
-> 2067         self._has_valid_tuple(tup)
2068         try:
2069             return self._getitem_lowerdim(tup)

python3.7/site-packages/pandas/core/indexing.py in _has_valid_tuple(self, key)
701                 raise IndexingError("Too many indexers")
702             try:
--> 703                 self._validate_key(k, i)
704             except ValueError:
705                 raise ValueError(

python3.7/site-packages/pandas/core/indexing.py in _validate_key(self, key, axis)
2007             # check that the key does not exceed the maximum size of the index
2008             if len(arr) and (arr.max() >= len_axis or arr.min() < -len_axis):
-> 2009                 raise IndexError("positional indexers are out-of-bounds")
2010         else:
2011             raise ValueError(f"Can only index by location with a [{self._valid_types}]")

IndexError: positional indexers are out-of-bounds

# Fixed code
def _copartition(self, axis, other, how, sort, force_repartition=False):
    """
    Copartition two dataframes.

    Parameters
    ----------
        axis : int
            The axis to copartition along.
        other : BasePandasFrame
            The other dataframes(s) to copartition against.
        how : str
            How to manage joining the index object ("left", "right", etc.)
        sort : boolean
            Whether or not to sort the joined index.
        force_repartition : boolean
            Whether or not to force the repartitioning. By default,
            this method will skip repartitioning if it is possible. This is because
            reindexing is extremely inefficient. Because this method is used to
            `join` or `append`, it is vital that the internal indices match.

    Returns
    -------
    Tuple
        A tuple (left data, right data list, joined index).
    """
    if isinstance(other, type(self)):
        other = [other]

    index_other_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis ^ 1, index_other_obj, how, sort)
    # We have to set these because otherwise when we perform the functions it may
    # end up serializing this entire object.
    left_old_idx = self.axes[axis]
    right_old_idxes = index_other_obj

    # Start with this and we'll repartition the first time, and then not again.
    if not left_old_idx.equals(joined_index) or force_repartition:
        reindexed_self = self._frame_mgr_cls.map_axis_partitions(
            axis, self._partitions, lambda df: df.reindex(joined_index, axis=axis)
        )
    else:
        reindexed_self = self._partitions
    reindexed_other_list = []

    for i in range(len(other)):
        if right_old_idxes[i].equals(joined_index) and not force_repartition:
            reindexed_other = other[i]._partitions
        else:
            reindexed_other = other[i]._frame_mgr_cls.map_axis_partitions(
                axis,
                other[i]._partitions,
                lambda df: df.reindex(joined_index, axis=axis),
            )
        reindexed_other_list.append(reindexed_other)
    return reindexed_self, reindexed_other_list, joined_index