# Buggy code
def apply_func_to_select_indices_along_full_axis(
    self, axis, func, indices, keep_remaining=False
):
    """Applies a function to a select subset of full columns/rows.

    Note: This should be used when you need to apply a function that relies
        on some global information for the entire column/row, but only need
        to apply a function to a subset.

    Important: For your func to operate directly on the indices provided,
        it must use `internal_indices` as a keyword argument.

    Args:
        axis: The axis to apply the function over (0 - rows, 1 - columns)
        func: The function to apply.
        indices: The global indices to apply the func to.
        keep_remaining: Whether or not to keep the other partitions.
            Some operations may want to drop the remaining partitions and
            keep only the results.

    Returns:
        A new BaseBlockPartitions object, the type of object that called this.
    """
    if self.partitions.size == 0:
        return np.array([[]])
    if isinstance(indices, dict):
        dict_indices = indices
        indices = list(indices.keys())
    else:
        dict_indices = None
    if not isinstance(indices, list):
        indices = [indices]
    partitions_dict = self._get_dict_of_block_index(axis, indices)
    preprocessed_func = self.preprocess_func(func)
    # Since we might be keeping the remaining blocks that are not modified,
    # we have to also keep the block_partitions object in the correct
    # direction (transpose for columns).
    if not axis:
        partitions_for_apply = self.column_partitions
        partitions_for_remaining = self.partitions.T
    else:
        partitions_for_apply = self.row_partitions
        partitions_for_remaining = self.partitions
    # We may have a command to perform different functions on different
    # columns at the same time. We attempt to handle this as efficiently as
    # possible here. Functions that use this in the dictionary format must
    # accept a keyword argument `func_dict`.
    if dict_indices is not None:
        if not keep_remaining:
            result = np.array(
                [
                    partitions_for_apply[i].apply(
                        preprocessed_func,
                        func_dict={
                            idx: dict_indices[idx] for idx in partitions_dict[i]
                        },
                    )
                    for i in partitions_dict
                ]
            )
        else:
            result = np.array(
                [
                    partitions_for_remaining[i]
                    if i not in partitions_dict
                    else self._apply_func_to_list_of_partitions(
                        preprocessed_func,
                        partitions_for_apply[i],
                        func_dict={
                            idx: dict_indices[idx] for idx in partitions_dict[i]
                        },
                    )
                    for i in range(len(partitions_for_apply))
                ]
            )
    else:
        if not keep_remaining:
            # See notes in `apply_func_to_select_indices`
            result = np.array(
                [
                    partitions_for_apply[i].apply(
                        preprocessed_func, internal_indices=partitions_dict[i]
                    )
                    for i in partitions_dict
                ]
            )
        else:
            # See notes in `apply_func_to_select_indices`
            result = np.array(
                [
                    partitions_for_remaining[i]
                    if i not in partitions_dict
                    else partitions_for_apply[i].apply(
                        preprocessed_func, internal_indices=partitions_dict[i]
                    )
                    for i in range(len(partitions_for_remaining))
                ]
            )
    return self.__constructor__(result.T) if not axis else self.__constructor__(result)


# Traceback (AssertionError)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-5-7f2184cfd6d7> in <module>
2 df = pd.DataFrame(columns=cols)
3 for col in cols:
----> 4     df[col] = np.arange(10)

~/Documents/modin/modin/pandas/dataframe.py in __setitem__(self, key, value)
4605         else:
4606             loc = self.columns.get_loc(key)
-> 4607             self.__delitem__(key)
4608             self.insert(loc=loc, column=key, value=value)
4609

~/Documents/modin/modin/pandas/dataframe.py in __delitem__(self, key)
4690         if key not in self:
4691             raise KeyError(key)
-> 4692         self._update_inplace(new_query_compiler=self._query_compiler.delitem(key))
4693
4694     def __finalize__(self, other, method=None, **kwargs):

~/Documents/modin/modin/data_management/query_compiler/pandas_query_compiler.py in delitem(self, key)
2294     # These will change the shape of the resulting data.
2295     def delitem(self, key):
-> 2296         return self.drop(columns=[key])
2297
2298     def drop(self, index=None, columns=None):

~/Documents/modin/modin/data_management/query_compiler/pandas_query_compiler.py in drop(self, index, columns)
2336             new_columns = self.columns[~self.columns.isin(columns)]
2337             new_dtypes = self.dtypes.drop(columns)
-> 2338         return self.__constructor__(new_data, new_index, new_columns, new_dtypes)
2339
2340     # END __delitem__ and drop

~/Documents/modin/modin/data_management/query_compiler/pandas_query_compiler.py in __constructor__(self, block_paritions_object, index, columns, dtypes)
41     def __constructor__(self, block_paritions_object, index, columns, dtypes=None):
42         """By default, constructor method will invoke an init"""
---> 43         return type(self)(block_paritions_object, index, columns, dtypes)
44
45     # Index, columns and dtypes objects

~/Documents/modin/modin/data_management/query_compiler/pandas_query_compiler.py in __init__(self, block_partitions_object, index, columns, dtypes)
32         dtypes=None,
33     ):
---> 34         assert isinstance(block_partitions_object, BaseBlockPartitions)
35         self.data = block_partitions_object
36         self.index = index

AssertionError:

# Fixed code
def apply_func_to_select_indices_along_full_axis(
    self, axis, func, indices, keep_remaining=False
):
    """Applies a function to a select subset of full columns/rows.

    Note: This should be used when you need to apply a function that relies
        on some global information for the entire column/row, but only need
        to apply a function to a subset.

    Important: For your func to operate directly on the indices provided,
        it must use `internal_indices` as a keyword argument.

    Args:
        axis: The axis to apply the function over (0 - rows, 1 - columns)
        func: The function to apply.
        indices: The global indices to apply the func to.
        keep_remaining: Whether or not to keep the other partitions.
            Some operations may want to drop the remaining partitions and
            keep only the results.

    Returns:
        A new BaseBlockPartitions object, the type of object that called this.
    """
    if self.partitions.size == 0:
        return self.__constructor__(np.array([[]]))
    if isinstance(indices, dict):
        dict_indices = indices
        indices = list(indices.keys())
    else:
        dict_indices = None
    if not isinstance(indices, list):
        indices = [indices]
    partitions_dict = self._get_dict_of_block_index(axis, indices)
    preprocessed_func = self.preprocess_func(func)
    # Since we might be keeping the remaining blocks that are not modified,
    # we have to also keep the block_partitions object in the correct
    # direction (transpose for columns).
    if not axis:
        partitions_for_apply = self.column_partitions
        partitions_for_remaining = self.partitions.T
    else:
        partitions_for_apply = self.row_partitions
        partitions_for_remaining = self.partitions
    # We may have a command to perform different functions on different
    # columns at the same time. We attempt to handle this as efficiently as
    # possible here. Functions that use this in the dictionary format must
    # accept a keyword argument `func_dict`.
    if dict_indices is not None:
        if not keep_remaining:
            result = np.array(
                [
                    partitions_for_apply[i].apply(
                        preprocessed_func,
                        func_dict={
                            idx: dict_indices[idx] for idx in partitions_dict[i]
                        },
                    )
                    for i in partitions_dict
                ]
            )
        else:
            result = np.array(
                [
                    partitions_for_remaining[i]
                    if i not in partitions_dict
                    else self._apply_func_to_list_of_partitions(
                        preprocessed_func,
                        partitions_for_apply[i],
                        func_dict={
                            idx: dict_indices[idx] for idx in partitions_dict[i]
                        },
                    )
                    for i in range(len(partitions_for_apply))
                ]
            )
    else:
        if not keep_remaining:
            # See notes in `apply_func_to_select_indices`
            result = np.array(
                [
                    partitions_for_apply[i].apply(
                        preprocessed_func, internal_indices=partitions_dict[i]
                    )
                    for i in partitions_dict
                ]
            )
        else:
            # See notes in `apply_func_to_select_indices`
            result = np.array(
                [
                    partitions_for_remaining[i]
                    if i not in partitions_dict
                    else partitions_for_apply[i].apply(
                        preprocessed_func, internal_indices=partitions_dict[i]
                    )
                    for i in range(len(partitions_for_remaining))
                ]
            )
    return self.__constructor__(result.T) if not axis else self.__constructor__(result)