integrations.standard_io.api
integrations/standard_io/api.py
1""" 2integrations/standard_io/api.py 3""" 4 5import textwrap 6from pathlib import Path 7from typing import TYPE_CHECKING 8 9import pandas as pd 10 11from integrations.base.interface import APIInterface 12from libs.types import StyleOptions 13from libs.utils import formatter 14 15if TYPE_CHECKING: 16 from integrations.protocols import MessageParserProtocol 17 18 19class AdapterAPI(APIInterface): 20 """インターフェースAPI操作クラス""" 21 22 def _text_formatter(self, text: str, style: StyleOptions) -> str: 23 """ 24 テキスト整形 25 26 Args: 27 text (str): 対象テキスト 28 style (StyleOptions): 修飾オプション 29 30 Returns: 31 str: 整形済みテキスト 32 33 """ 34 ret: str = "" 35 for line in text.splitlines(): 36 line = line.replace("<@>", "") 37 if not style.keep_indent: 38 line = textwrap.dedent(line) 39 if line or style.keep_blank: 40 ret += textwrap.indent(f"{line}\n", "\t" * style.indent) 41 return ret.rstrip() 42 43 def post(self, m: "MessageParserProtocol") -> None: 44 """ 45 メッセージ出力 46 47 Args: 48 m (MessageParserProtocol): メッセージデータ 49 50 """ 51 # 見出し 52 if m.post.headline: 53 header_data, header_option = m.post.headline 54 if isinstance(header_data, str): 55 print("=" * 80) 56 if header_option.title: 57 print(f"【{header_option.title}】") 58 if isinstance(header_data, str): 59 print(textwrap.dedent(header_data).rstrip()) 60 print("=" * 80) 61 62 # 本文 63 for data, options in m.post.message: 64 if options.key_title and options.title: 65 print(options.print_title) 66 67 match data: 68 case x if isinstance(x, str): 69 print(self._text_formatter(x, options)) 70 case x if isinstance(x, pd.DataFrame): 71 options.rename_type = StyleOptions.RenameType.NORMAL 72 match options.data_kind: # 単位付与/文字列変換 73 case StyleOptions.DataKind.POINTS_TOTAL: 74 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 75 x["avg_point"] = x["avg_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 76 case StyleOptions.DataKind.POINTS_DIFF: 77 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 78 x["diff_from_above"] = x["diff_from_above"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 79 x["diff_from_top"] = x["diff_from_top"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 80 case StyleOptions.DataKind.RECORD_DATA: 81 x["rank"] = x["rank"].map(lambda v: f"{v:.0f}位") 82 x["rpoint"] = x["rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 83 x["point"] = x["point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 84 case StyleOptions.DataKind.RECORD_DATA_ALL: 85 for prefix in ("p1", "p2", "p3", "p4"): 86 x[f"{prefix}_rank"] = x[f"{prefix}_rank"].map(lambda v: f"{v:.0f}位") 87 x[f"{prefix}_rpoint"] = x[f"{prefix}_rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 88 x[f"{prefix}_point"] = x[f"{prefix}_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 89 case _: 90 pass 91 disp = formatter.df_rename(x, options).to_markdown( 92 index=options.show_index, 93 tablefmt="simple_outline", 94 floatfmt=formatter.floatfmt_adjust(x, index=options.show_index), 95 colalign=formatter.column_alignment(x, index=options.show_index), 96 ) 97 print(disp) 98 case x if isinstance(x, Path): 99 print(f"{options.title}: {x.absolute()}") 100 case _: 101 pass 102 103 print("")
20class AdapterAPI(APIInterface): 21 """インターフェースAPI操作クラス""" 22 23 def _text_formatter(self, text: str, style: StyleOptions) -> str: 24 """ 25 テキスト整形 26 27 Args: 28 text (str): 対象テキスト 29 style (StyleOptions): 修飾オプション 30 31 Returns: 32 str: 整形済みテキスト 33 34 """ 35 ret: str = "" 36 for line in text.splitlines(): 37 line = line.replace("<@>", "") 38 if not style.keep_indent: 39 line = textwrap.dedent(line) 40 if line or style.keep_blank: 41 ret += textwrap.indent(f"{line}\n", "\t" * style.indent) 42 return ret.rstrip() 43 44 def post(self, m: "MessageParserProtocol") -> None: 45 """ 46 メッセージ出力 47 48 Args: 49 m (MessageParserProtocol): メッセージデータ 50 51 """ 52 # 見出し 53 if m.post.headline: 54 header_data, header_option = m.post.headline 55 if isinstance(header_data, str): 56 print("=" * 80) 57 if header_option.title: 58 print(f"【{header_option.title}】") 59 if isinstance(header_data, str): 60 print(textwrap.dedent(header_data).rstrip()) 61 print("=" * 80) 62 63 # 本文 64 for data, options in m.post.message: 65 if options.key_title and options.title: 66 print(options.print_title) 67 68 match data: 69 case x if isinstance(x, str): 70 print(self._text_formatter(x, options)) 71 case x if isinstance(x, pd.DataFrame): 72 options.rename_type = StyleOptions.RenameType.NORMAL 73 match options.data_kind: # 単位付与/文字列変換 74 case StyleOptions.DataKind.POINTS_TOTAL: 75 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 76 x["avg_point"] = x["avg_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 77 case StyleOptions.DataKind.POINTS_DIFF: 78 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 79 x["diff_from_above"] = x["diff_from_above"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 80 x["diff_from_top"] = x["diff_from_top"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 81 case StyleOptions.DataKind.RECORD_DATA: 82 x["rank"] = x["rank"].map(lambda v: f"{v:.0f}位") 83 x["rpoint"] = x["rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 84 x["point"] = x["point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 85 case StyleOptions.DataKind.RECORD_DATA_ALL: 86 for prefix in ("p1", "p2", "p3", "p4"): 87 x[f"{prefix}_rank"] = x[f"{prefix}_rank"].map(lambda v: f"{v:.0f}位") 88 x[f"{prefix}_rpoint"] = x[f"{prefix}_rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 89 x[f"{prefix}_point"] = x[f"{prefix}_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 90 case _: 91 pass 92 disp = formatter.df_rename(x, options).to_markdown( 93 index=options.show_index, 94 tablefmt="simple_outline", 95 floatfmt=formatter.floatfmt_adjust(x, index=options.show_index), 96 colalign=formatter.column_alignment(x, index=options.show_index), 97 ) 98 print(disp) 99 case x if isinstance(x, Path): 100 print(f"{options.title}: {x.absolute()}") 101 case _: 102 pass 103 104 print("")
インターフェースAPI操作クラス
44 def post(self, m: "MessageParserProtocol") -> None: 45 """ 46 メッセージ出力 47 48 Args: 49 m (MessageParserProtocol): メッセージデータ 50 51 """ 52 # 見出し 53 if m.post.headline: 54 header_data, header_option = m.post.headline 55 if isinstance(header_data, str): 56 print("=" * 80) 57 if header_option.title: 58 print(f"【{header_option.title}】") 59 if isinstance(header_data, str): 60 print(textwrap.dedent(header_data).rstrip()) 61 print("=" * 80) 62 63 # 本文 64 for data, options in m.post.message: 65 if options.key_title and options.title: 66 print(options.print_title) 67 68 match data: 69 case x if isinstance(x, str): 70 print(self._text_formatter(x, options)) 71 case x if isinstance(x, pd.DataFrame): 72 options.rename_type = StyleOptions.RenameType.NORMAL 73 match options.data_kind: # 単位付与/文字列変換 74 case StyleOptions.DataKind.POINTS_TOTAL: 75 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 76 x["avg_point"] = x["avg_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 77 case StyleOptions.DataKind.POINTS_DIFF: 78 x["total_point"] = x["total_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 79 x["diff_from_above"] = x["diff_from_above"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 80 x["diff_from_top"] = x["diff_from_top"].map(lambda v: f"{v:.1f}pt" if pd.notna(v) else "------") 81 case StyleOptions.DataKind.RECORD_DATA: 82 x["rank"] = x["rank"].map(lambda v: f"{v:.0f}位") 83 x["rpoint"] = x["rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 84 x["point"] = x["point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 85 case StyleOptions.DataKind.RECORD_DATA_ALL: 86 for prefix in ("p1", "p2", "p3", "p4"): 87 x[f"{prefix}_rank"] = x[f"{prefix}_rank"].map(lambda v: f"{v:.0f}位") 88 x[f"{prefix}_rpoint"] = x[f"{prefix}_rpoint"].map(lambda v: f"{v:.0f}点".replace("-", "▲")) 89 x[f"{prefix}_point"] = x[f"{prefix}_point"].map(lambda v: f"{v:+.1f}pt".replace("-", "▲")) 90 case _: 91 pass 92 disp = formatter.df_rename(x, options).to_markdown( 93 index=options.show_index, 94 tablefmt="simple_outline", 95 floatfmt=formatter.floatfmt_adjust(x, index=options.show_index), 96 colalign=formatter.column_alignment(x, index=options.show_index), 97 ) 98 print(disp) 99 case x if isinstance(x, Path): 100 print(f"{options.title}: {x.absolute()}") 101 case _: 102 pass 103 104 print("")
メッセージ出力
Arguments:
- m (MessageParserProtocol): メッセージデータ