# Buggy code
def copy(self, column_names=None, virtual=True):
    df = DataFrameArrays()
    df._length_unfiltered = self._length_unfiltered
    df._length_original = self._length_original
    df._cached_filtered_length = self._cached_filtered_length
    df._index_end = self._index_end
    df._index_start = self._index_start
    df._active_fraction = self._active_fraction
    df._renamed_columns = list(self._renamed_columns)
    df._column_aliases = dict(self._column_aliases)
    df.units.update(self.units)
    df.variables.update(self.variables)  # we add all, could maybe only copy used
    df._categories.update(self._categories)
    if column_names is None:
        column_names = self.get_column_names(hidden=True)
    all_column_names = self.get_column_names(hidden=True)

    # put in the selections (thus filters) in place
    # so drop moves instead of really dropping it
    df.functions.update(self.functions)
    for key, value in self.selection_histories.items():
        # TODO: selection_histories begin a defaultdict always gives
        # us the filtered selection, so check if we really have a
        # selection
        if self.get_selection(key):
            df.selection_histories[key] = list(value)
            # the filter should never be modified, so we can share a reference
            # except when we add filter on filter using
            # df = df[df.x>0]
            # df = df[df.x < 10]
            # in that case we make a copy in __getitem__
            if key == FILTER_SELECTION_NAME:
                df._selection_masks[key] = self._selection_masks[key]
            else:
                df._selection_masks[key] = vaex.superutils.Mask(df._length_original)
            # and make sure the mask is consistent with the cache chunks
            np.asarray(df._selection_masks[key])[:] = np.asarray(
                self._selection_masks[key]
            )
    for key, value in self.selection_history_indices.items():
        if self.get_selection(key):
            df.selection_history_indices[key] = value
            # we can also copy the caches, which prevents recomputations of selections
            df._selection_mask_caches[key] = collections.defaultdict(dict)
            df._selection_mask_caches[key].update(self._selection_mask_caches[key])

    if 1:
        # print("-----", column_names)
        depending = set()
        added = set()
        for name in column_names:
            # print("add", name)
            added.add(name)
            if name in self.columns:
                column = self.columns[name]
                df.add_column(name, column, dtype=self._dtypes_override.get(name))
                if isinstance(column, ColumnSparse):
                    df._sparse_matrices[name] = self._sparse_matrices[name]
            elif name in self.virtual_columns:
                if virtual:  # TODO: check if the ast is cached
                    df.add_virtual_column(name, self.virtual_columns[name])
                    deps = [
                        key
                        for key, value in df._virtual_expressions[
                            name
                        ].ast_names.items()
                    ]
                    # print("add virtual", name, df._virtual_expressions[name].expression, deps)
                    depending.update(deps)
            else:
                # this might be an expression, create a valid name
                self.validate_expression(name)
                expression = name
                name = vaex.utils.find_valid_name(name)
                # add the expression
                df[name] = df._expr(expression)
                # then get the dependencies
                deps = [
                    key
                    for key, value in df._virtual_expressions[name].ast_names.items()
                ]
                depending.update(deps)
            # print(depending, "after add")
        # depending |= column_names
        # print(depending)
        # print(depending, "before filter")
        if self.filtered:
            selection = self.get_selection(FILTER_SELECTION_NAME)
            depending |= selection._depending_columns(self)
        depending.difference_update(added)  # remove already added
        # print(depending, "after filter")
        # return depending_columns

        hide = []

        while depending:
            new_depending = set()
            for name in depending:
                added.add(name)
                if name in self.columns:
                    # print("add column", name)
                    df.add_column(
                        name, self.columns[name], dtype=self._dtypes_override.get(name)
                    )
                    # print("and hide it")
                    # df._hide_column(name)
                    hide.append(name)
                elif name in self.virtual_columns:
                    if virtual:  # TODO: check if the ast is cached
                        df.add_virtual_column(name, self.virtual_columns[name])
                        deps = [
                            key
                            for key, value in self._virtual_expressions[
                                name
                            ].ast_names.items()
                        ]
                        new_depending.update(deps)
                    # df._hide_column(name)
                    hide.append(name)
                elif name in self.variables:
                    # if must be a variables?
                    # TODO: what if the variable depends on other variables
                    # we already add all variables
                    # df.add_variable(name, self.variables[name])
                    pass

            # print("new_depending", new_depending)
            new_depending.difference_update(added)
            depending = new_depending
        for name in hide:
            df._hide_column(name)

    else:
        # we copy all columns, but drop the ones that are not wanted
        # this makes sure that needed columns are hidden instead
        def add_columns(columns):
            for name in columns:
                if name in self.columns:
                    df.add_column(
                        name, self.columns[name], dtype=self._dtypes_override.get(name)
                    )
                elif name in self.virtual_columns:
                    if virtual:
                        df.add_virtual_column(name, self.virtual_columns[name])
                else:
                    # this might be an expression, create a valid name
                    expression = name
                    name = vaex.utils.find_valid_name(name)
                    df[name] = df._expr(expression)

        # to preserve the order, we first add the ones we want, then the rest
        add_columns(column_names)
        # then the rest
        rest = set(all_column_names) - set(column_names)
        add_columns(rest)
        # and remove them
        for name in rest:
            # if the column should not have been added, drop it. This checks if columns need
            # to be hidden instead, and expressions be rewritten.
            if name not in column_names:
                df.drop(name, inplace=True)
                assert name not in df.get_column_names(hidden=True)

    df.copy_metadata(self)
    return df


# Traceback (AttributeError)
could not convert column 0, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 0, error: TypeError('getattr(): attribute name must be string',)
could not convert column 1, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 1, error: TypeError('getattr(): attribute name must be string',)
could not convert column 2, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 2, error: TypeError('getattr(): attribute name must be string',)
could not convert column 3, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 3, error: TypeError('getattr(): attribute name must be string',)
could not convert column 4, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 4, error: TypeError('getattr(): attribute name must be string',)
could not convert column 5, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 5, error: TypeError('getattr(): attribute name must be string',)
could not convert column 6, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 6, error: TypeError('getattr(): attribute name must be string',)
could not convert column 7, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 7, error: TypeError('getattr(): attribute name must be string',)
could not convert column 8, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 8, error: TypeError('getattr(): attribute name must be string',)
could not convert column 9, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 9, error: TypeError('getattr(): attribute name must be string',)
could not convert column 10, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 10, error: TypeError('getattr(): attribute name must be string',)
could not convert column 11, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 11, error: TypeError('getattr(): attribute name must be string',)
could not convert column 12, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 12, error: TypeError('getattr(): attribute name must be string',)
could not convert column 13, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 13, error: TypeError('getattr(): attribute name must be string',)
could not convert column 14, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 14, error: TypeError('getattr(): attribute name must be string',)
could not convert column 15, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 15, error: TypeError('getattr(): attribute name must be string',)
could not convert column 16, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 16, error: TypeError('getattr(): attribute name must be string',)
could not convert column 17, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 17, error: TypeError('getattr(): attribute name must be string',)
could not convert column 18, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 18, error: TypeError('getattr(): attribute name must be string',)
could not convert column 19, error: TypeError('getattr(): attribute name must be string',), will try to convert it to string
Giving up column 19, error: TypeError('getattr(): attribute name must be string',)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/IPython/core/formatters.py in __call__(self, obj, include, exclude)
968                 d['include'] = include
969                 d['exclude'] = exclude
--> 970                 return method(**d)
971             return None
972         else:

5 frames
/usr/local/lib/python3.6/dist-packages/vaex/dataframe.py in column_filter(name)
3486             if not strings and (self.dtype(name) == str_type or self.dtype(name).type == np.string_):
3487                 return False
-> 3488             if not hidden and name.startswith('__'):
3489                 return False
3490             return True

AttributeError: 'int' object has no attribute 'startswith'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-a7b44e392414> in <module>()
3 df = pd.DataFrame(X)
4 df['target'] = y
----> 5 vaex.from_pandas(df)

2 frames
/usr/local/lib/python3.6/dist-packages/IPython/core/formatters.py in format(self, obj, include, exclude)
150             return {}, {}
151
--> 152         format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
153
154         if format_dict or md_dict:

TypeError: 'NoneType' object is not iterable

# Fixed code
def copy(self, column_names=None, virtual=True):
    df = DataFrameArrays()
    df._length_unfiltered = self._length_unfiltered
    df._length_original = self._length_original
    df._cached_filtered_length = self._cached_filtered_length
    df._index_end = self._index_end
    df._index_start = self._index_start
    df._active_fraction = self._active_fraction
    df._renamed_columns = list(self._renamed_columns)
    df._column_aliases = dict(self._column_aliases)
    df.units.update(self.units)
    df.variables.update(self.variables)  # we add all, could maybe only copy used
    df._categories.update(self._categories)
    if column_names is None:
        column_names = self.get_column_names(hidden=True, alias=False)
    all_column_names = self.get_column_names(hidden=True, alias=False)

    # put in the selections (thus filters) in place
    # so drop moves instead of really dropping it
    df.functions.update(self.functions)
    for key, value in self.selection_histories.items():
        # TODO: selection_histories begin a defaultdict always gives
        # us the filtered selection, so check if we really have a
        # selection
        if self.get_selection(key):
            df.selection_histories[key] = list(value)
            # the filter should never be modified, so we can share a reference
            # except when we add filter on filter using
            # df = df[df.x>0]
            # df = df[df.x < 10]
            # in that case we make a copy in __getitem__
            if key == FILTER_SELECTION_NAME:
                df._selection_masks[key] = self._selection_masks[key]
            else:
                df._selection_masks[key] = vaex.superutils.Mask(df._length_original)
            # and make sure the mask is consistent with the cache chunks
            np.asarray(df._selection_masks[key])[:] = np.asarray(
                self._selection_masks[key]
            )
    for key, value in self.selection_history_indices.items():
        if self.get_selection(key):
            df.selection_history_indices[key] = value
            # we can also copy the caches, which prevents recomputations of selections
            df._selection_mask_caches[key] = collections.defaultdict(dict)
            df._selection_mask_caches[key].update(self._selection_mask_caches[key])

    if 1:
        # print("-----", column_names)
        depending = set()
        added = set()
        for name in column_names:
            # print("add", name)
            added.add(name)
            if name in self.columns:
                column = self.columns[name]
                df.add_column(name, column, dtype=self._dtypes_override.get(name))
                if isinstance(column, ColumnSparse):
                    df._sparse_matrices[name] = self._sparse_matrices[name]
            elif name in self.virtual_columns:
                if virtual:  # TODO: check if the ast is cached
                    df.add_virtual_column(name, self.virtual_columns[name])
                    deps = [
                        key
                        for key, value in df._virtual_expressions[
                            name
                        ].ast_names.items()
                    ]
                    # print("add virtual", name, df._virtual_expressions[name].expression, deps)
                    depending.update(deps)
            else:
                # this might be an expression, create a valid name
                self.validate_expression(name)
                expression = name
                name = vaex.utils.find_valid_name(name)
                # add the expression
                df[name] = df._expr(expression)
                # then get the dependencies
                deps = [
                    key
                    for key, value in df._virtual_expressions[name].ast_names.items()
                ]
                depending.update(deps)
            # print(depending, "after add")
        # depending |= column_names
        # print(depending)
        # print(depending, "before filter")
        if self.filtered:
            selection = self.get_selection(FILTER_SELECTION_NAME)
            depending |= selection._depending_columns(self)
        depending.difference_update(added)  # remove already added
        # print(depending, "after filter")
        # return depending_columns

        hide = []

        while depending:
            new_depending = set()
            for name in depending:
                added.add(name)
                if name in self.columns:
                    # print("add column", name)
                    df.add_column(
                        name, self.columns[name], dtype=self._dtypes_override.get(name)
                    )
                    # print("and hide it")
                    # df._hide_column(name)
                    hide.append(name)
                elif name in self.virtual_columns:
                    if virtual:  # TODO: check if the ast is cached
                        df.add_virtual_column(name, self.virtual_columns[name])
                        deps = [
                            key
                            for key, value in self._virtual_expressions[
                                name
                            ].ast_names.items()
                        ]
                        new_depending.update(deps)
                    # df._hide_column(name)
                    hide.append(name)
                elif name in self.variables:
                    # if must be a variables?
                    # TODO: what if the variable depends on other variables
                    # we already add all variables
                    # df.add_variable(name, self.variables[name])
                    pass

            # print("new_depending", new_depending)
            new_depending.difference_update(added)
            depending = new_depending
        for name in hide:
            df._hide_column(name)

    else:
        # we copy all columns, but drop the ones that are not wanted
        # this makes sure that needed columns are hidden instead
        def add_columns(columns):
            for name in columns:
                if name in self.columns:
                    df.add_column(
                        name, self.columns[name], dtype=self._dtypes_override.get(name)
                    )
                elif name in self.virtual_columns:
                    if virtual:
                        df.add_virtual_column(name, self.virtual_columns[name])
                else:
                    # this might be an expression, create a valid name
                    expression = name
                    name = vaex.utils.find_valid_name(name)
                    df[name] = df._expr(expression)

        # to preserve the order, we first add the ones we want, then the rest
        add_columns(column_names)
        # then the rest
        rest = set(all_column_names) - set(column_names)
        add_columns(rest)
        # and remove them
        for name in rest:
            # if the column should not have been added, drop it. This checks if columns need
            # to be hidden instead, and expressions be rewritten.
            if name not in column_names:
                df.drop(name, inplace=True)
                assert name not in df.get_column_names(hidden=True)

    df.copy_metadata(self)
    return df