# Buggy code
def _write_col_header(self, indent):
    truncate_h = self.fmt.truncate_h
    if isinstance(self.columns, ABCMultiIndex):
        template = 'colspan="{span:d}" halign="left"'

        if self.fmt.sparsify:
            # GH3547
            sentinel = com.sentinel_factory()
        else:
            sentinel = None
        levels = self.columns.format(sparsify=sentinel, adjoin=False, names=False)
        level_lengths = get_level_lengths(levels, sentinel)
        inner_lvl = len(level_lengths) - 1
        for lnum, (records, values) in enumerate(zip(level_lengths, levels)):
            if truncate_h:
                # modify the header lines
                ins_col = self.fmt.tr_col_num
                if self.fmt.sparsify:
                    recs_new = {}
                    # Increment tags after ... col.
                    for tag, span in list(records.items()):
                        if tag >= ins_col:
                            recs_new[tag + 1] = span
                        elif tag + span > ins_col:
                            recs_new[tag] = span + 1
                            if lnum == inner_lvl:
                                values = (
                                    values[:ins_col] + (u("..."),) + values[ins_col:]
                                )
                            else:
                                # sparse col headers do not receive a ...
                                values = (
                                    values[:ins_col]
                                    + (values[ins_col - 1],)
                                    + values[ins_col:]
                                )
                        else:
                            recs_new[tag] = span
                        # if ins_col lies between tags, all col headers
                        # get ...
                        if tag + span == ins_col:
                            recs_new[ins_col] = 1
                            values = values[:ins_col] + (u("..."),) + values[ins_col:]
                    records = recs_new
                    inner_lvl = len(level_lengths) - 1
                    if lnum == inner_lvl:
                        records[ins_col] = 1
                else:
                    recs_new = {}
                    for tag, span in list(records.items()):
                        if tag >= ins_col:
                            recs_new[tag + 1] = span
                        else:
                            recs_new[tag] = span
                    recs_new[ins_col] = 1
                    records = recs_new
                    values = values[:ins_col] + [u("...")] + values[ins_col:]

            # see gh-22579
            # Column Offset Bug with to_html(index=False) with
            # MultiIndex Columns and Index.
            # Initially fill row with blank cells before column names.
            # TODO: Refactor to remove code duplication with code
            # block below for standard columns index.
            row = [""] * (self.row_levels - 1)
            if self.fmt.index or self.show_col_idx_names:
                # see gh-22747
                # If to_html(index_names=False) do not show columns
                # index names.
                # TODO: Refactor to use _get_column_name_list from
                # DataFrameFormatter class and create a
                # _get_formatted_column_labels function for code
                # parity with DataFrameFormatter class.
                if self.fmt.show_index_names:
                    name = self.columns.names[lnum]
                    row.append(pprint_thing(name or ""))
                else:
                    row.append("")

            tags = {}
            j = len(row)
            for i, v in enumerate(values):
                if i in records:
                    if records[i] > 1:
                        tags[j] = template.format(span=records[i])
                else:
                    continue
                j += 1
                row.append(v)
            self.write_tr(row, indent, self.indent_delta, tags=tags, header=True)
    else:
        # see gh-22579
        # Column misalignment also occurs for
        # a standard index when the columns index is named.
        # Initially fill row with blank cells before column names.
        # TODO: Refactor to remove code duplication with code block
        # above for columns MultiIndex.
        row = [""] * (self.row_levels - 1)
        if self.fmt.index or self.show_col_idx_names:
            # see gh-22747
            # If to_html(index_names=False) do not show columns
            # index names.
            # TODO: Refactor to use _get_column_name_list from
            # DataFrameFormatter class.
            if self.fmt.show_index_names:
                row.append(self.columns.name or "")
            else:
                row.append("")
        row.extend(self.columns)
        align = self.fmt.justify

        if truncate_h:
            ins_col = self.row_levels + self.fmt.tr_col_num
            row.insert(ins_col, "...")

        self.write_tr(row, indent, self.indent_delta, header=True, align=align)


# Traceback (TypeError)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-59e289592884> in <module>()
3           ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
4 df = pd.DataFrame(index=arrays, columns=arrays)
----> 5 df.to_html(max_cols=7, sparsify=False)

~\Anaconda3\lib\site-packages\pandas\core\frame.py in to_html(self, buf, columns, col_space, header, index, na_rep, formatters, float_format, sparsify, index_names, justify, bold_rows, classes, escape, max_rows, max_cols, show_dimensions, notebook, decimal, border, table_id)
2032                                            decimal=decimal, table_id=table_id)
2033         # TODO: a generic formatter wld b in DataFrameFormatter
-> 2034         formatter.to_html(classes=classes, notebook=notebook, border=border)
2035
2036         if buf is None:

~\Anaconda3\lib\site-packages\pandas\io\formats\format.py in to_html(self, classes, notebook, border)
749                                       table_id=self.table_id)
750         if hasattr(self.buf, 'write'):
--> 751             html_renderer.write_result(self.buf)
752         elif isinstance(self.buf, compat.string_types):
753             with open(self.buf, 'w') as f:

~\Anaconda3\lib\site-packages\pandas\io\formats\html.py in write_result(self, buf)
177
178         indent += self.indent_delta
--> 179         indent = self._write_header(indent)
180         indent = self._write_body(indent)
181

~\Anaconda3\lib\site-packages\pandas\io\formats\html.py in _write_header(self, indent)
279                         recs_new[ins_col] = 1
280                         records = recs_new
--> 281                         values = (values[:ins_col] + [u('...')] +
282                                   values[ins_col:])
283

TypeError: can only concatenate tuple (not "list") to tuple

# Fixed code
def _write_col_header(self, indent):
    truncate_h = self.fmt.truncate_h
    if isinstance(self.columns, ABCMultiIndex):
        template = 'colspan="{span:d}" halign="left"'

        if self.fmt.sparsify:
            # GH3547
            sentinel = com.sentinel_factory()
        else:
            sentinel = False
        levels = self.columns.format(sparsify=sentinel, adjoin=False, names=False)
        level_lengths = get_level_lengths(levels, sentinel)
        inner_lvl = len(level_lengths) - 1
        for lnum, (records, values) in enumerate(zip(level_lengths, levels)):
            if truncate_h:
                # modify the header lines
                ins_col = self.fmt.tr_col_num
                if self.fmt.sparsify:
                    recs_new = {}
                    # Increment tags after ... col.
                    for tag, span in list(records.items()):
                        if tag >= ins_col:
                            recs_new[tag + 1] = span
                        elif tag + span > ins_col:
                            recs_new[tag] = span + 1
                            if lnum == inner_lvl:
                                values = (
                                    values[:ins_col] + (u("..."),) + values[ins_col:]
                                )
                            else:
                                # sparse col headers do not receive a ...
                                values = (
                                    values[:ins_col]
                                    + (values[ins_col - 1],)
                                    + values[ins_col:]
                                )
                        else:
                            recs_new[tag] = span
                        # if ins_col lies between tags, all col headers
                        # get ...
                        if tag + span == ins_col:
                            recs_new[ins_col] = 1
                            values = values[:ins_col] + (u("..."),) + values[ins_col:]
                    records = recs_new
                    inner_lvl = len(level_lengths) - 1
                    if lnum == inner_lvl:
                        records[ins_col] = 1
                else:
                    recs_new = {}
                    for tag, span in list(records.items()):
                        if tag >= ins_col:
                            recs_new[tag + 1] = span
                        else:
                            recs_new[tag] = span
                    recs_new[ins_col] = 1
                    records = recs_new
                    values = values[:ins_col] + [u("...")] + values[ins_col:]

            # see gh-22579
            # Column Offset Bug with to_html(index=False) with
            # MultiIndex Columns and Index.
            # Initially fill row with blank cells before column names.
            # TODO: Refactor to remove code duplication with code
            # block below for standard columns index.
            row = [""] * (self.row_levels - 1)
            if self.fmt.index or self.show_col_idx_names:
                # see gh-22747
                # If to_html(index_names=False) do not show columns
                # index names.
                # TODO: Refactor to use _get_column_name_list from
                # DataFrameFormatter class and create a
                # _get_formatted_column_labels function for code
                # parity with DataFrameFormatter class.
                if self.fmt.show_index_names:
                    name = self.columns.names[lnum]
                    row.append(pprint_thing(name or ""))
                else:
                    row.append("")

            tags = {}
            j = len(row)
            for i, v in enumerate(values):
                if i in records:
                    if records[i] > 1:
                        tags[j] = template.format(span=records[i])
                else:
                    continue
                j += 1
                row.append(v)
            self.write_tr(row, indent, self.indent_delta, tags=tags, header=True)
    else:
        # see gh-22579
        # Column misalignment also occurs for
        # a standard index when the columns index is named.
        # Initially fill row with blank cells before column names.
        # TODO: Refactor to remove code duplication with code block
        # above for columns MultiIndex.
        row = [""] * (self.row_levels - 1)
        if self.fmt.index or self.show_col_idx_names:
            # see gh-22747
            # If to_html(index_names=False) do not show columns
            # index names.
            # TODO: Refactor to use _get_column_name_list from
            # DataFrameFormatter class.
            if self.fmt.show_index_names:
                row.append(self.columns.name or "")
            else:
                row.append("")
        row.extend(self.columns)
        align = self.fmt.justify

        if truncate_h:
            ins_col = self.row_levels + self.fmt.tr_col_num
            row.insert(ins_col, "...")

        self.write_tr(row, indent, self.indent_delta, header=True, align=align)