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

    Parameters
    ----------
        axis : 0 or 1
            The axis to copartition along (0 - rows, 1 - columns).
        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]
    if all(o.axes[axis].equals(self.axes[axis]) for o in other):
        return (
            self._partitions,
            [self._simple_shuffle(axis, o) for o in other],
            self.axes[axis].copy(),
        )
    index_other_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis, 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


# Traceback (IndexError)
df = pd.DataFrame({"a":[1, 2 ,3]})
df.shift(-1).a / df.a
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-8-7cc3bcb4fa16> in <module>
1 df = pd.DataFrame({"a":[1, 2 ,3]})
----> 2 df.shift(-1).a / df.a

~/Envs/strategy/lib/python3.7/site-packages/modin/pandas/series.py in __truediv__(self, right)
348
349     def __truediv__(self, right):
--> 350         return self.truediv(right)
351
352     def __rtruediv__(self, left):

~/Envs/strategy/lib/python3.7/site-packages/modin/pandas/series.py in truediv(self, other, level, fill_value, axis)
1478         new_self, new_other = self._prepare_inter_op(other)
1479         return super(Series, new_self).truediv(
-> 1480             new_other, level=level, fill_value=None, axis=axis
1481         )
1482

~/Envs/strategy/lib/python3.7/site-packages/modin/pandas/base.py in truediv(self, other, axis, level, fill_value)
3299         """
3300         return self._binary_op(
-> 3301             "truediv", other, axis=axis, level=level, fill_value=fill_value
3302         )
3303

~/Envs/strategy/lib/python3.7/site-packages/modin/pandas/base.py in _binary_op(self, op, other, **kwargs)
231             )
232         other = self._validate_other(other, axis, numeric_or_object_only=True)
--> 233         new_query_compiler = getattr(self._query_compiler, op)(other, **kwargs)
234         return self._create_or_update_from_compiler(new_query_compiler)
235

~/Envs/strategy/lib/python3.7/site-packages/modin/data_management/functions/binary_function.py in caller(query_compiler, other, *args, **kwargs)
49                             lambda x, y: func(x, y, *args, **kwargs),
50                             other._modin_frame,
---> 51                             join_type=join_type,
52                         )
53                     )

~/Envs/strategy/lib/python3.7/site-packages/modin/engines/base/frame/data.py in _binary_op(self, op, right_frame, join_type)
1604         right_parts = right_parts[0]
1605         new_frame = self._frame_mgr_cls.binary_operation(
-> 1606             1, left_parts, lambda l, r: op(l, r), right_parts
1607         )
1608         new_columns = self.columns.join(right_frame.columns, how=join_type)

~/Envs/strategy/lib/python3.7/site-packages/modin/engines/base/frame/partition_manager.py in binary_operation(cls, axis, left, func, right)
753                     other_axis_partition=right_partitions[i],
754                 )
--> 755                 for i in range(len(left_partitions))
756             ]
757         )

~/Envs/strategy/lib/python3.7/site-packages/modin/engines/base/frame/partition_manager.py in <listcomp>(.0)
753                     other_axis_partition=right_partitions[i],
754                 )
--> 755                 for i in range(len(left_partitions))
756             ]
757         )

IndexError: list index out of range

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

    Parameters
    ----------
        axis : 0 or 1
            The axis to copartition along (0 - rows, 1 - columns).
        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]

    is_aligning_applied = False
    for i in range(len(other)):
        if (
            len(self._partitions) != len(other[i]._partitions)
            and len(self.axes[0]) == len(other[i].axes[0])
            and axis == 0
        ):
            is_aligning_applied = True
            self._partitions = self._frame_mgr_cls.map_axis_partitions(
                axis, self._partitions, lambda df: df
            )
            other[i]._partitions = other[i]._frame_mgr_cls.map_axis_partitions(
                axis, other[i]._partitions, lambda df: df
            )

    if (
        all(o.axes[axis].equals(self.axes[axis]) for o in other)
        and not is_aligning_applied
    ):
        return (
            self._partitions,
            [self._simple_shuffle(axis, o) for o in other],
            self.axes[axis].copy(),
        )
    index_other_obj = [o.axes[axis] for o in other]
    joined_index = self._join_index_objects(axis, 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

    is_avoid_reindex = len(joined_index) != len(joined_index.unique()) and axis == 0
    # Start with this and we'll repartition the first time, and then not again.
    if (
        not is_aligning_applied
        and not is_avoid_reindex
        and (force_repartition or not left_old_idx.equals(joined_index))
    ):
        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 (
            is_aligning_applied
            or is_avoid_reindex
            or (not force_repartition and right_old_idxes[i].equals(joined_index))
        ):
            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