class EmptyTableDataError(Exception):
    """
    Exception raised when a table writer class of the |headers| and
    |value_matrix| attributes are null.
    """ class Cell:
    """
    .. py:attribute:: row
        :type: int

        row index.

    .. py:attribute:: col
        :type: int

        column index.

    .. py:attribute:: value
        :type: Any

        data for the cell.

    .. py:attribute:: default_style
        :type: pytablewriter.style.Style

        default |Style| for the cell.
    """

    def __init__(self, row: int, col: int, value: Any, default_style: Style):
        self.row = row
        self.col = col
        self.value = value
        self.default_style = default_style

    def is_header_row(self) -> bool:
        """
        Return |True| if the cell is a header.
        """

        return self.row < 0 class Style:
    """Style specifier class for table elements.

    Args:
        color (Union[|str|, tcolorpy.Color, |None|]):
            Text color for cells.
            When using str, specify a color code (``"#XXXXXX"``) or a color name.

            .. note::
                In the current version, only applicable for part of text format writer classes.

        fg_color (Union[|str|, tcolorpy.Color, |None|]):
            Alias to :py:attr:`~.color`.

        bg_color (Union[|str|, tcolorpy.Color, |None|]):
            Background color for cells.
            When using str, specify a color code (``"#XXXXXX"``) or a color name.

            .. note::
                In the current version, only applicable for part of text format writer classes.

        align (|str| / :py:class:`~.style.Align`):
            Horizontal text alignment for cells.
            This can be only applied for text format writer classes.
            Possible string values are:

            - ``"auto"`` (default)
                - Detect data type for each column and set alignment that appropriate
                  for the type automatically
            - ``"left"``
            - ``"right"``
            - ``"center"``

        vertical_align (|str| / :py:class:`~.style.VerticalAlign`):
            Vertical text alignment for cells.
            This can be only applied for HtmlTableWriter class.
            Possible string values are:

            - ``"baseline"`` (default)
            - ``"top"``
            - ``"middle"``
            - ``"bottom"``

        font_size (|str| / :py:class:`~.style.FontSize`):
            Font size specification for cells in a column.
            This can be only applied for HTML/Latex writer classes.
            Possible string values are:

            - ``"tiny"``
            - ``"small"``
            - ``"medium"``
            - ``"large"``
            - ``"none"`` (default: no font size specification)

        font_weight (|str| / :py:class:`~.style.FontWeight`):
            Font weight specification for cells in a column.
            This can be only applied for HTML/Latex/Markdown writer classes.
            Possible string values are:

            - ``"normal"`` (default)
            - ``"bold"``

        font_style (|str| / :py:class:`~.style.FontStyle`):
            Font style specification for cells in a column.
            This can be applied only for HTML/Latex/Markdown writer classes.
            Possible string values are:

            - ``"normal"`` (default)
            - ``"italic"``

        decoration_line (|str| / :py:class:`~.style.DecorationLine`)

            Experiental.
            Possible string values are:

            - ``"line-through"``
            - ``"strike"`` (alias for ``"line-through"``)
            - ``"underline"``
            - ``"none"`` (default)

        thousand_separator (|str| / :py:class:`~.style.ThousandSeparator`):
            Thousand separator specification for numbers in a column.
            This can be only applied for text format writer classes.
            Possible string values are:

            - ``","``/``"comma"``
            - ``" "``/``"space"``
            - ``"_"``/``"underscore"``
            - ``""``/``"none"`` (default)

    Example:
        :ref:`example-style`
    """

    @property
    def align(self) -> Align:
        return self.__align

    @align.setter
    def align(self, value: Align) -> None:
        self.__align = value

    @property
    def vertical_align(self) -> VerticalAlign:
        return self.__valign

    @property
    def decoration_line(self) -> DecorationLine:
        return self.__decoration_line

    @property
    def font_size(self) -> FontSize:
        return self.__font_size

    @property
    def font_style(self) -> FontStyle:
        return self.__font_style

    @property
    def font_weight(self) -> FontWeight:
        return self.__font_weight

    @property
    def color(self) -> Optional[Color]:
        return self.__fg_color

    @property
    def fg_color(self) -> Optional[Color]:
        return self.__fg_color

    @property
    def bg_color(self) -> Optional[Color]:
        return self.__bg_color

    @property
    def thousand_separator(self) -> ThousandSeparator:
        return self.__thousand_separator

    @property
    def padding(self):
        return self.__padding

    @padding.setter
    def padding(self, value: Optional[int]):
        self.__padding = value

    def __init__(self, **kwargs) -> None:
        self.__update_color(initialize=True, **kwargs)
        self.__update_align(initialize=True, **kwargs)
        self.__update_font(initialize=True, **kwargs)
        self.__update_misc(initialize=True, **kwargs)

    def __repr__(self) -> str:
        items = []

        if self.align:
            items.append(f"align={self.align.align_string}")
        if self.padding is not None:
            items.append(f"padding={self.padding}")
        if self.vertical_align:
            items.append(f"valign={self.vertical_align.align_str}")
        if self.color:
            items.append(f"color={self.color}")
        if self.bg_color:
            items.append(f"bg_color={self.bg_color}")
        if self.decoration_line is not DecorationLine.NONE:
            items.append(f"decoration_line={self.decoration_line.value}")
        if self.font_size is not FontSize.NONE:
            items.append(f"font_size={self.font_size.value}")
        if self.font_style:
            items.append(f"font_style={self.font_style.value}")
        if self.font_weight:
            items.append(f"font_weight={self.font_weight.value}")
        if self.thousand_separator is not ThousandSeparator.NONE:
            items.append(f"thousand_separator={self.thousand_separator.value}")

        return "({})".format(", ".join(items))

    def __eq__(self, other):
        if self.__class__ is not other.__class__:
            return NotImplemented

        return all(
            [
                self.align == other.align,
                self.font_size == other.font_size,
                self.font_style == other.font_style,
                self.font_weight == other.font_weight,
                self.thousand_separator == other.thousand_separator,
            ]
        )

    def __ne__(self, other):
        equal = self.__eq__(other)
        return NotImplemented if equal is NotImplemented else not equal

    def update(self, **kwargs) -> None:
        """Update specified style attributes."""
        self.__update_color(initialize=False, **kwargs)
        self.__update_align(initialize=False, **kwargs)
        self.__update_font(initialize=False, **kwargs)
        self.__update_misc(initialize=False, **kwargs)

    def __update_color(self, initialize: bool, **kwargs) -> None:
        fg_color = kwargs.get("color") or kwargs.get("fg_color")
        if fg_color:
            self.__fg_color: Optional[Color] = Color(fg_color)
        elif initialize:
            self.__fg_color = None

        bg_color = kwargs.get("bg_color")
        if bg_color:
            self.__bg_color: Optional[Color] = Color(bg_color)
        elif initialize:
            self.__bg_color = None

    def __update_font(self, initialize: bool, **kwargs) -> None:
        font_size = kwargs.get("font_size")
        if font_size:
            self.__font_size = normalize_enum(
                kwargs.get("font_size"), FontSize, validate=False, default=FontSize.NONE
            )
        elif initialize:
            self.__font_size = FontSize.NONE
        self.__validate_attr("font_size", (FontSize, str))

        font_style = kwargs.get("font_style")
        if font_style:
            self.__font_style = normalize_enum(font_style, FontStyle, default=FontStyle.NORMAL)
        elif initialize:
            self.__font_style = FontStyle.NORMAL

        font_weight = kwargs.get("font_weight")
        if font_weight:
            self.__font_weight = normalize_enum(font_weight, FontWeight, default=FontWeight.NORMAL)
        elif initialize:
            self.__font_weight = FontWeight.NORMAL

    def __update_align(self, initialize: bool, **kwargs) -> None:
        align = kwargs.get("align")
        if align:
            self.__align = normalize_enum(align, Align, default=Align.AUTO)
        elif initialize:
            self.__align = Align.AUTO

        valign = kwargs.get("vertical_align")
        if valign:
            self.__valign = normalize_enum(valign, VerticalAlign, default=VerticalAlign.BASELINE)
        elif initialize:
            self.__valign = VerticalAlign.BASELINE

    def __update_misc(self, initialize: bool, **kwargs) -> None:
        padding = kwargs.get("padding")
        if padding is not None:
            self.__padding = padding
        elif initialize:
            self.__padding = None

        decoration_line = kwargs.get("decoration_line")
        if decoration_line:
            self.__decoration_line = normalize_enum(
                decoration_line, DecorationLine, default=DecorationLine.NONE
            )
        elif initialize:
            self.__decoration_line = DecorationLine.NONE

        thousand_separator = kwargs.get("thousand_separator")
        if thousand_separator:
            self.__thousand_separator = _normalize_thousand_separator(
                normalize_enum(
                    thousand_separator,
                    ThousandSeparator,
                    default=ThousandSeparator.NONE,
                    validate=False,
                )
            )
        elif initialize:
            self.__thousand_separator = ThousandSeparator.NONE
        self.__validate_attr("thousand_separator", ThousandSeparator)

    def __validate_attr(self, attr_name: str, expected_type) -> None:
        value = getattr(self, attr_name)
        if isinstance(expected_type, (list, tuple)):
            expected = " or ".join(c.__name__ for c in expected_type)
        else:
            expected = expected_type.__name__

        if not isinstance(value, expected_type):
            raise TypeError(f"{attr_name} must be instance of {expected}: actual={type(value)}") class StylerInterface(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def apply(self, value: Any, style: Style) -> str:  # pragma: no cover
        raise NotImplementedError()

    @abc.abstractmethod
    def apply_align(self, value: str, style: Style) -> str:  # pragma: no cover
        raise NotImplementedError()

    @abc.abstractmethod
    def apply_terminal_style(self, value: str, style: Style) -> str:  # pragma: no cover
        raise NotImplementedError()

    @abc.abstractmethod
    def get_font_size(self, style: Style) -> Optional[str]:  # pragma: no cover
        raise NotImplementedError()

    @abc.abstractmethod
    def get_additional_char_width(self, style: Style) -> int:  # pragma: no cover
        raise NotImplementedError() class TextStyler(AbstractStyler):
    def apply_terminal_style(self, value: str, style: Style) -> str:
        if not self._writer.enable_ansi_escape:
            return value

        ansi_styles = []

        if style.decoration_line in (DecorationLine.STRIKE, DecorationLine.LINE_THROUGH):
            ansi_styles.append("strike")
        if style.decoration_line == DecorationLine.UNDERLINE:
            ansi_styles.append("underline")

        if style.font_weight == FontWeight.BOLD:
            ansi_styles.append("bold")

        if self._writer.colorize_terminal:
            return tcolor(value, color=style.color, bg_color=style.bg_color, styles=ansi_styles)

        return tcolor(value, styles=ansi_styles)

    def __get_align_format(self, style: Style) -> str:
        align_char = get_align_char(style.align)
        format_items = ["{:" + align_char]
        if style.padding is not None and style.padding > 0:
            format_items.append(str(style.padding))
        format_items.append("s}")

        return "".join(format_items)

    def apply_align(self, value: str, style: Style) -> str:
        return self.__get_align_format(style).format(value)

    def apply(self, value: Any, style: Style) -> str:
        if value:
            if style.thousand_separator == ThousandSeparator.SPACE:
                value = value.replace(",", " ")
            elif style.thousand_separator == ThousandSeparator.UNDERSCORE:
                value = value.replace(",", "_")

        return value def get_align_char(align: Align) -> str:
    return _align_char_mapping[align] HEADER_ROW = -1 class AbstractTableWriter(TableWriterInterface, metaclass=abc.ABCMeta):
    def margin(self) -> int:
    def margin(self, value: int) -> None:
    def header_list(self):
    def header_list(self, value):
    def value_matrix(self) -> Sequence:
    def value_matrix(self, value_matrix: Sequence) -> None:
    def table_format(self):
    def type_hint_list(self):
    def type_hint_list(self, value):
    def styles(self):
    def styles(self, value):
    def style_list(self):
    def style_list(self, value):
    def value_preprocessor(self):
    def value_preprocessor(self, value):
    def stream(self):
    def stream(self, value) -> None:
    def _write_table(self, **kwargs) -> None:
    def __init__(self, **kwargs) -> None:
    def _repr_html_(self) -> str:
    def __clear_preprocess_status(self) -> None:
    def __clear_preprocess_data(self) -> None:
    def headers(self) -> Sequence[str]:
    def headers(self, value: Sequence[str]) -> None:
    def is_formatting_float(self) -> bool:
    def is_formatting_float(self, value: bool) -> None:
    def max_workers(self) -> int:
    def max_workers(self, value: Optional[int]) -> None:
    def tabledata(self) -> TableData:
    def table_name(self) -> str:
    def table_name(self, value: str) -> None:
    def type_hints(self) -> List[TypeHint]:
    def type_hints(self, value: Sequence[Union[str, TypeHint]]) -> None:
    def default_style(self) -> Style:
    def default_style(self, style) -> None:
    def column_styles(self) -> List[Optional[Style]]:
    def column_styles(self, value: Sequence[Optional[Style]]) -> None:
    def colorize_terminal(self) -> bool:
    def colorize_terminal(self, value: bool) -> None:
    def enable_ansi_escape(self) -> bool:
    def enable_ansi_escape(self, value: bool) -> None:
    def _quoting_flags(self) -> Dict[Typecode, bool]:
    def _quoting_flags(self, value: Mapping[Typecode, bool]) -> None:
    def add_style_filter(self, style_filter: StyleFilterFunc) -> None:
    def add_col_separator_style_filter(self, style_filter: ColSeparatorStyleFilterFunc) -> None:
    def clear_theme(self) -> None:
    def set_style(self, column: Union[str, int], style: Style) -> None:
    def set_theme(self, theme: str, **kwargs) -> None:
    def __is_skip_close(self) -> bool:
    def close(self) -> None:
    def from_tabledata(self, value: TableData, is_overwrite_table_name: bool = True) -> None:
    def from_csv(self, csv_source: str, delimiter: str = ",") -> None:
    def from_dataframe(
        self, dataframe, add_index_column: bool = False, overwrite_type_hints: bool = True
    ) -> None:
    def from_series(self, series, add_index_column: bool = True) -> None:
    def from_tablib(self, tablib_dataset) -> None:
    def from_writer(
        self, writer: "AbstractTableWriter", is_overwrite_table_name: bool = True
    ) -> None:
    def register_trans_func(self, trans_func: TransFunc) -> None:
    def update_preprocessor(self, **kwargs) -> None:
    def write_table(self, **kwargs) -> None:
    def _write_table_iter(self, **kwargs) -> None:
    def _get_padding_len(
        self, column_dp: ColumnDataProperty, value_dp: Optional[DataProperty] = None
    ) -> int:
    def _to_header_item(self, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str:
    def _get_header_format_string(
        self, _col_dp: ColumnDataProperty, _value_dp: DataProperty
    ) -> str:
    def _to_row_item(self, row_idx: int, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str:
    def _apply_style_to_row_item(
        self, row_idx: int, col_dp: ColumnDataProperty, value_dp: DataProperty, style: Style
    ) -> str:
    def _fetch_style_from_filter(
        self, row_idx: int, col_dp: ColumnDataProperty, value_dp: DataProperty, default_style: Style
    ) -> Style:
    def _get_col_style(self, col_idx: int) -> Style:
    def _get_align(self, col_idx: int, default_align: Align) -> Align:
    def __retrieve_align_from_data(
        self, col_dp: ColumnDataProperty, value_dp: DataProperty
    ) -> Align:
    def _verify_property(self) -> None:
    def __set_value_matrix(self, value_matrix: Sequence) -> None:
    def __set_type_hints(self, type_hints: Sequence[Union[str, TypeHint]]) -> None:
    def _verify_table_name(self) -> None:
    def _verify_stream(self) -> None:
    def _verify_header(self) -> None:
    def _validate_empty_header(self) -> None:
    def _verify_value_matrix(self) -> None:
    def _create_styler(self, writer) -> StylerInterface:
    def _preprocess_table_dp(self) -> None:
    def _preprocess_table_property(self) -> None:
    def _preprocess_header(self) -> None:
    def _preprocess_value_matrix(self) -> None:
    def _preprocess(self) -> None:
    def _clear_preprocess(self) -> None:
    def __clear_preprocess(self) -> None: class IndentationInterface(metaclass=abc.ABCMeta):
    """
    Interface class for indentation methods.
    """

    @abc.abstractmethod
    def set_indent_level(self, indent_level):  # pragma: no cover
        pass

    @abc.abstractmethod
    def inc_indent_level(self):  # pragma: no cover
        pass

    @abc.abstractmethod
    def dec_indent_level(self):  # pragma: no cover
        pass class TextWriterInterface(metaclass=abc.ABCMeta):
    """
    Interface class for writing texts.
    """

    @abc.abstractmethod
    def write_null_line(self):  # pragma: no cover
        pass
import enum
import io
import sys
import typepy
from itertools import chain
from typing import IO, List, Optional, Sequence, Union, cast
from dataproperty import Align, ColumnDataProperty, DataProperty, LineBreakHandling
from ...error import EmptyTableDataError
from ...style import Cell, Style, StylerInterface, TextStyler
from ...style._styler import get_align_char
from .._common import HEADER_ROW
from .._table_writer import AbstractTableWriter, ColSeparatorStyleFilterFunc
from ._interface import IndentationInterface, TextWriterInterface
            tabular_text = self.stream.getvalue()
        finally:
            self.stream = old_stream

        return tabular_text

    def _set_chars(self, c: str) -> None:
        self.char_left_side_row = c
        self.char_right_side_row = c

        self.char_cross_point = c
        self.char_left_cross_point = c
        self.char_right_cross_point = c
        self.char_top_left_cross_point = c
        self.char_top_right_cross_point = c
        self.char_bottom_left_cross_point = c
        self.char_bottom_right_cross_point = c

        self.char_opening_row = c
        self.char_opening_row_cross_point = c

        self.char_header_row_separator = c
        self.char_header_row_cross_point = c
        self.char_header_row_left_cross_point = c
        self.char_header_row_right_cross_point = c

        self.char_value_row_separator = c

        self.char_closing_row = c
        self.char_closing_row_cross_point = c

        self._init_cross_point_maps()

    def _create_styler(self, writer: AbstractTableWriter) -> StylerInterface:
        return TextStyler(writer)

    def _write_table_iter(self, **kwargs) -> None:
        super()._write_table_iter()
        if self.is_write_null_line_after_table:
            self.write_null_line()

    def _write_table(self, **kwargs) -> None:
        self._preprocess()
        self._write_opening_row()

        try:
            self._write_header()
            self.__write_header_row_separator()
        except ValueError:
            pass

        is_first_value_row = True
        for row, (values, value_dp_list) in enumerate(
            zip(self._table_value_matrix, self._table_value_dp_matrix)
        ):
            try:
                if is_first_value_row:
                    is_first_value_row = False
                else:
                    if self.is_write_value_separator_row:
                        self._write_value_row_separator()

                self._write_value_row(row, cast(List[str], values), value_dp_list)
            except TypeError:
                continue

        self._write_closing_row()

    def _get_opening_row_items(self) -> List[str]:
        return self.__get_row_separator_items(self.__opening_row_cell_format, self.char_opening_row)

    def _get_header_row_separator_items(self) -> List[str]:
        return self.__get_row_separator_items(
            self._header_row_separator_cell_format, self.char_header_row_separator
        )

    def _get_value_row_separator_items(self) -> List[str]:
        return self.__get_row_separator_items(
            self.__value_row_separator_cell_format, self.char_value_row_separator
        )

    def _get_closing_row_items(self) -> List[str]:
        return self.__get_row_separator_items(self.__closing_row_cell_format, self.char_closing_row)

    def __get_row_separator_items(self, margin_format: str, separator_char: str) -> List[str]:
        return [
            margin_format.format(separator_char * self._get_padding_len(col_dp))
            for col_dp in self._column_dp_list
        ]

    def _get_header_format_string(self, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str:
        return "{{:{:s}{:s}}}".format(
            get_align_char(Align.CENTER),
            str(self._get_padding_len(col_dp, value_dp)),
        )

    def _to_header_item(self, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str:
        return self.__value_cell_margin_format.format(super()._to_header_item(col_dp, value_dp))

    def _apply_style_to_row_item(
        self, row_idx: int, col_dp: ColumnDataProperty, value_dp: DataProperty, style: Style
    ) -> str:
        return self.__value_cell_margin_format.format(
            super()._apply_style_to_row_item(row_idx, col_dp, value_dp, style)
        )

    def _write_raw_string(self, unicode_text: str) -> None:
        self.stream.write(unicode_text)

    def _write_raw_line(self, unicode_text: str = "") -> None:
        self._write_raw_string(unicode_text + "\n")

    def _write(self, text):
        self._write_raw_string(text)

    def _write_line(self, text: str = "") -> None:
        self._write_raw_line(text)

    def _fetch_col_separator_style(
        self, left_cell: Optional[Cell], right_cell: Optional[Cell], default_style: Style

    ) -> Style: