Source code for pytablewriter.writer.text._markdown

import copy
from enum import Enum, unique
from typing import Any, List, Union

import dataproperty as dp
import typepy
from dataproperty import ColumnDataProperty, DataProperty
from mbstrdecoder import MultiByteStrDecoder
from pathvalidate import replace_symbol

from ..._function import normalize_enum
from ...error import EmptyTableDataError
from ...style import Align, GFMarkdownStyler, MarkdownStyler, StylerInterface
from .._table_writer import AbstractTableWriter
from ._text_writer import IndentationTextTableWriter


@unique
class MarkdownFlavor(Enum):
    COMMON_MARK = "common_mark"
    GITHUB = "github"
    GFM = "gfm"
    JEKYLL = "jekyll"
    KRAMDOWN = "kramdown"


def normalize_md_flavor(flavor: Union[str, MarkdownFlavor, None]) -> MarkdownFlavor:
    if isinstance(flavor, str):
        flavor_str = replace_symbol(flavor.strip(), "_").upper()
        flavor_str = flavor_str.replace("COMMONMARK", "COMMON_MARK")
        flavor = flavor_str

    norm_flavor = normalize_enum(flavor, MarkdownFlavor, default=MarkdownFlavor.COMMON_MARK)

    if norm_flavor == MarkdownFlavor.GITHUB:
        return MarkdownFlavor.GFM

    if norm_flavor == MarkdownFlavor.JEKYLL:
        return MarkdownFlavor.KRAMDOWN

    return norm_flavor


[docs] class MarkdownTableWriter(IndentationTextTableWriter): """ A table writer class for Markdown format. Example: :ref:`example-markdown-table-writer` """ FORMAT_NAME = "markdown" DEFAULT_FLAVOR = MarkdownFlavor.COMMON_MARK @property def format_name(self) -> str: return self.FORMAT_NAME @property def support_split_write(self) -> bool: return True def __init__(self, **kwargs: Any) -> None: self.__flavor = normalize_md_flavor(kwargs.pop("flavor", self.DEFAULT_FLAVOR)) super().__init__(**kwargs) self.indent_string = "" self.column_delimiter = "|" self.char_left_side_row = "|" self.char_right_side_row = "|" self.char_cross_point = "|" self.char_header_row_cross_point = "|" self.char_header_row_left_cross_point = "|" self.char_header_row_right_cross_point = "|" self.is_write_opening_row = True self._use_default_header = True self._is_require_header = True self._quoting_flags = copy.deepcopy(dp.NOT_QUOTING_FLAGS) self._dp_extractor.min_column_width = 3 self._init_cross_point_maps() def _to_header_item(self, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str: return self.__escape_vertical_bar_char(super()._to_header_item(col_dp, value_dp)) def _to_row_item(self, row_idx: int, col_dp: ColumnDataProperty, value_dp: DataProperty) -> str: return self.__escape_vertical_bar_char(super()._to_row_item(row_idx, col_dp, value_dp)) def _get_opening_row_items(self) -> List[str]: return [] def _get_header_row_separator_items(self) -> List[str]: header_separator_list = [] margin = " " * self.margin for col_dp in self._column_dp_list: padding_len = self._get_padding_len(col_dp) align = self._get_align(col_dp.column_index, col_dp.align) if align == Align.RIGHT: separator_item = "-" * (padding_len - 1) + ":" elif align == Align.CENTER: separator_item = ":" + "-" * (padding_len - 2) + ":" else: separator_item = "-" * padding_len header_separator_list.append( "{margin}{item}{margin}".format(margin=margin, item=separator_item) ) return header_separator_list def _get_value_row_separator_items(self) -> List[str]: return [] def _get_closing_row_items(self) -> List[str]: return [] def _write_header(self) -> None: super()._write_header() if self.__flavor == MarkdownFlavor.KRAMDOWN: self._write_line()
[docs] def write_table(self, **kwargs: Any) -> None: """ |write_table| with Markdown table format. Args: flavor (Optional[str]): possible flavors are as follows (case insensitive): - ``"CommonMark"`` - ``"gfm"`` - ``"github"`` (alias of ``"gfm"``) - ``kramdown`` - ``Jekyll`` (alias of ``"kramdown"``) Defaults to ``"CommonMark"``. Example: :ref:`example-markdown-table-writer` .. note:: - |None| values are written as an empty string - Vertical bar characters (``'|'``) in table items are escaped """ if "flavor" in kwargs: new_flavor = normalize_md_flavor(kwargs["flavor"]) if new_flavor != self.__flavor: self._clear_preprocess() self.__flavor = new_flavor if self.__flavor: self._styler = self._create_styler(self) with self._logger: try: self._verify_property() except EmptyTableDataError: self._logger.logger.debug("no tabular data found") return self.__write_chapter() self._write_table(**kwargs) if self.is_write_null_line_after_table: self.write_null_line()
def _write_table_iter(self, **kwargs: Any) -> None: self.__write_chapter() super()._write_table_iter() def __write_chapter(self) -> None: if typepy.is_null_string(self.table_name): return self._write_line( "{:s} {:s}".format( "#" * (self._indent_level + 1), MultiByteStrDecoder(self.table_name).unicode_str ) ) if self.__flavor == MarkdownFlavor.KRAMDOWN: self._write_line() def _create_styler(self, writer: AbstractTableWriter) -> StylerInterface: if self.__flavor == MarkdownFlavor.GFM: return GFMarkdownStyler(writer) return MarkdownStyler(writer) @staticmethod def __escape_vertical_bar_char(value: str) -> str: return value.replace("|", r"\|")