libs.bootstrap.app_config

libs/bootstrap/app_config.py

  1"""
  2libs/bootstrap/app_config.py
  3"""
  4
  5import logging
  6import sys
  7from configparser import ConfigParser
  8from dataclasses import dataclass, field
  9from pathlib import Path
 10from typing import Any, Optional, Union
 11
 12from libs.bootstrap.section import AliasSection, BaseSection, SettingSection, SubCommands
 13from libs.commands.graph.entry import GraphConfig
 14from libs.commands.help.entry import HelpConfig
 15from libs.commands.ranking.entry import RankingConfig
 16from libs.commands.registry.member import MemberSection
 17from libs.commands.registry.team import TeamSection
 18from libs.commands.report.entry import ReportConfig
 19from libs.commands.results.entry import ResultsConfig
 20from libs.domain.rule import RuleSet
 21from libs.functions.lookup import read_memberslist
 22from libs.types import CommandType, GradeTableDict, ServiceType
 23
 24
 25class BadgeDisplay(BaseSection):
 26    """バッジ表示"""
 27
 28    @dataclass
 29    class BadgeGradeSpec:
 30        """段位"""
 31
 32        table_name: str = field(default=str())
 33        table: GradeTableDict = field(default_factory=GradeTableDict)
 34
 35    grade: "BadgeGradeSpec" = BadgeGradeSpec()
 36    """段位情報"""
 37
 38    def __init__(self, outer: "AppConfig") -> None:
 39        self.section = "grade"
 40        self.main_parser = outer.main_parser
 41
 42        if self.main_parser.has_section(self.section):
 43            self.section_proxy = self.main_parser[self.section]
 44            self.grade.table_name = self.get("table_name", fallback="")
 45
 46
 47class AppConfig:
 48    """アプリケーション設定"""
 49
 50    @dataclass
 51    class FixedWords:
 52        """非表示項目用固定ワード"""
 53
 54        flying: set[str] = field(default_factory=lambda: {"トビ", "トビ率"})
 55        """トビ関連ワード"""
 56        yakuman: set[str] = field(default_factory=lambda: {"役満", "役満和了", "役満和了率"})
 57        """役満関連ワード"""
 58        regulation: set[str] = field(default_factory=lambda: {"卓外", "卓外清算", "卓外ポイント"})
 59        """レギュレーション関連ワード"""
 60        other: set[str] = field(default_factory=lambda: {"その他", "メモ"})
 61        """その他ワード"""
 62
 63    def __init__(self, config_file: Path) -> None:
 64        self.config_file: Path = config_file
 65        """メイン設定ファイルパス"""
 66
 67        try:
 68            self.main_parser: ConfigParser = ConfigParser()
 69            self.main_parser.read(self.config_file, encoding="utf-8")
 70        except Exception as err:
 71            raise RuntimeError(err) from err
 72
 73        # セクションチェック
 74        option_sections = [
 75            "setting",
 76            "results",
 77            "graph",
 78            "ranking",
 79            "report",
 80            "help",
 81            "alias",
 82            "member",
 83            "team",
 84        ]
 85        for x in option_sections:
 86            if x not in self.main_parser.sections():
 87                self.main_parser.add_section(x)
 88
 89        # 基本設定
 90        self.script_dir: Path = Path(sys.argv[0]).absolute().parent
 91        """スクリプトが保存されているディレクトリパス"""
 92        self.config_dir: Path = self.config_file.absolute().parent
 93        """設定ファイルが保存されているディレクトリパス"""
 94        self.selected_service: ServiceType = ServiceType.SLACK
 95        """連携先サービス"""
 96
 97        # 設定値
 98        self.setting: SettingSection = SettingSection()
 99        """settingセクション設定値"""
100        self.alias: AliasSection = AliasSection()
101        """aliasセクション設定値"""
102        self.member: MemberSection = MemberSection(self)
103        """memberセクション設定値"""
104        self.team: TeamSection = TeamSection(self)
105        """teamセクション設定値"""
106        self.badge: BadgeDisplay = BadgeDisplay(self)
107        """バッジ設定"""
108
109        # サブコマンド
110        self.results: "SubCommands" = ResultsConfig()
111        """resultsセクション設定値"""
112        self.graph: "SubCommands" = GraphConfig()
113        """graphセクション設定値"""
114        self.ranking: "SubCommands" = RankingConfig()
115        """rankingセクション設定値"""
116        self.report: "SubCommands" = ReportConfig()
117        """reportセクション設定値"""
118        self.help: "SubCommands" = HelpConfig()
119        """helpセクション設定値"""
120
121        self.initialization()
122
123        self.dropitems = self.FixedWords()
124        """非表示項目リスト"""
125        self.rule: RuleSet = RuleSet()
126        """ルール情報"""
127
128    def initialization(self) -> None:
129        """設定ファイル読み込み"""
130        self.setting.config_load(self.main_parser["setting"])
131        self.alias.config_load(self.main_parser["alias"])
132        self.member.config_load(self.main_parser["member"])
133        self.team.config_load(self.main_parser["team"])
134
135        self.results.config_load(self.main_parser["results"])
136        self.graph.config_load(self.main_parser["graph"])
137        self.ranking.config_load(self.main_parser["ranking"])
138        self.report.config_load(self.main_parser["report"])
139        self.help.config_load(self.main_parser["help"])
140
141        # フォントファイルチェック
142        for chk_dir in (self.config_dir, self.script_dir):
143            chk_file = chk_dir / str(self.setting.font_file)
144            if chk_file.exists():
145                self.setting.font_file = chk_file
146                break
147        else:
148            if not self.setting.font_file.exists():
149                logging.critical("The specified font file cannot be found.")
150                sys.exit(255)
151
152        # 作業ディレクトリパス
153        if not self.setting.work_dir.is_absolute():
154            self.setting.work_dir = self.script_dir / self.setting.work_dir
155
156        # データベース関連
157        if isinstance(self.setting.database_file, Path) and not self.setting.database_file.exists():
158            self.setting.database_file = self.config_dir / str(self.setting.database_file)
159
160    def word_list(self, add_words: list[str] | None = None) -> list[str]:
161        """
162        設定されている値、キーワードをリスト化する
163
164        Args:
165            add_words (list[str] | None, optional): リストに追加するワード. Defaults to None.
166
167        Returns:
168            list[str]: リスト化されたキーワード
169
170        """
171        words: list[str] = []
172
173        if add_words:
174            words.extend(add_words)
175
176        words.extend(list(self.rule.keyword_mapping.keys()))
177        words.extend([self.setting.remarks_word])
178
179        for command_name in CommandType:
180            if hasattr(self, str(command_name)):
181                if (command := getattr(self, str(command_name))) and isinstance(command, SubCommands):
182                    words.append(command.default_commandword)
183                    words.extend(command.commandword)
184                    words.extend(command.command_suffix)
185
186        for k, v in self.alias.to_dict().items():
187            if isinstance(v, list):
188                words.append(k)
189                words.extend(v)
190
191        words = [x for x in set(words) if x != ""]  # 重複排除/空文字削除
192
193        return words
194
195    def overwrite(self, additional_config: Path, section_name: str) -> None:
196        """
197        指定セクションを上書き
198
199        Args:
200            additional_config (Path): 追加設定ファイルパス
201            section_name (str): セクション名
202
203        """
204        if not additional_config.exists():
205            return
206
207        try:
208            additional_config_parser = ConfigParser()
209            additional_config_parser.read([self.config_file, additional_config], encoding="utf-8")
210        except Exception as err:
211            logging.error(err)
212            return
213
214        protected_values: Union[str, list[str]]
215        match section_name:
216            case "setting":
217                protected_values = self.setting.remarks_word  # 上書き保護
218                self.setting.config_load(additional_config_parser[section_name])
219                self.setting.remarks_word = protected_values
220            case "results":
221                protected_values = self.results.commandword  # 上書き保護
222                self.results.config_load(additional_config_parser[section_name])
223                self.results.commandword = protected_values
224            case "graph":
225                protected_values = self.graph.commandword  # 上書き保護
226                self.graph.config_load(additional_config_parser[section_name])
227                self.graph.commandword = protected_values
228            case "ranking":
229                protected_values = self.ranking.commandword  # 上書き保護
230                self.ranking.config_load(additional_config_parser[section_name])
231                self.ranking.commandword = protected_values
232            case "report":
233                protected_values = self.report.commandword  # 上書き保護
234                self.report.config_load(additional_config_parser[section_name])
235                self.report.commandword = protected_values
236            case _:
237                return
238
239    def read_channel_config(self, section_name: str, ret_dict: dict[str, Any]) -> Optional[Path]:
240        """
241        チャンネル個別設定読み込み
242
243        Args:
244            section_name (str): チャンネル個別設定セクション名
245            ret_dict (dict[str, Any]): パラメータ
246
247        Returns:
248            Optional[Path]: 個別設定読み込み結果
249            - *Path*: 読み込んだ設定ファイルパス
250            - *None*: 読み込める設定ファイルがない
251
252        """
253        config_path: Optional[Path] = None
254
255        if self.main_parser.has_section(section_name):
256            if default_rule := self.main_parser[section_name].get("default_rule"):
257                ret_dict.update({"default_rule": default_rule})
258            if channel_config := self.main_parser[section_name].get("channel_config"):
259                config_path = Path(channel_config)
260                if config_path.exists():
261                    logging.debug("Override: %s", config_path.absolute())
262                    self.initialization()
263                    self.overwrite(config_path, "setting")
264                    self.overwrite(config_path, "results")
265                    self.overwrite(config_path, "graph")
266                    self.overwrite(config_path, "ranking")
267                    self.overwrite(config_path, "report")
268                else:
269                    config_path = None
270
271        read_memberslist()
272
273        return config_path
274
275    def resolve_channel_id(self, section_name: Optional[str] = None) -> str:
276        """
277        メイン設定から優先度の高いチャンネルIDを取得する
278
279        Args:
280            section_name (Optional[str]): チャンネル個別設定セクション名
281
282        Returns:
283            str: チャンネルID
284
285        """
286        for section in (section_name, self.selected_service, "setting"):
287            if section and self.main_parser.has_section(section):
288                if channel_id := self.main_parser[section].get("channel_id"):
289                    return channel_id
290
291        if section_name:
292            return section_name
293        return ""
class BadgeDisplay(libs.bootstrap.section.BaseSection):
26class BadgeDisplay(BaseSection):
27    """バッジ表示"""
28
29    @dataclass
30    class BadgeGradeSpec:
31        """段位"""
32
33        table_name: str = field(default=str())
34        table: GradeTableDict = field(default_factory=GradeTableDict)
35
36    grade: "BadgeGradeSpec" = BadgeGradeSpec()
37    """段位情報"""
38
39    def __init__(self, outer: "AppConfig") -> None:
40        self.section = "grade"
41        self.main_parser = outer.main_parser
42
43        if self.main_parser.has_section(self.section):
44            self.section_proxy = self.main_parser[self.section]
45            self.grade.table_name = self.get("table_name", fallback="")

バッジ表示

BadgeDisplay(outer: AppConfig)
39    def __init__(self, outer: "AppConfig") -> None:
40        self.section = "grade"
41        self.main_parser = outer.main_parser
42
43        if self.main_parser.has_section(self.section):
44            self.section_proxy = self.main_parser[self.section]
45            self.grade.table_name = self.get("table_name", fallback="")
grade: BadgeDisplay.BadgeGradeSpec = BadgeDisplay.BadgeGradeSpec(table_name='', table={})

段位情報

section

セクション名

main_parser

設定パーサー

@dataclass
class BadgeDisplay.BadgeGradeSpec:
29    @dataclass
30    class BadgeGradeSpec:
31        """段位"""
32
33        table_name: str = field(default=str())
34        table: GradeTableDict = field(default_factory=GradeTableDict)

段位

BadgeDisplay.BadgeGradeSpec(table_name: str = '', table: libs.types.GradeTableDict = <factory>)
table_name: str = ''
class AppConfig:
 48class AppConfig:
 49    """アプリケーション設定"""
 50
 51    @dataclass
 52    class FixedWords:
 53        """非表示項目用固定ワード"""
 54
 55        flying: set[str] = field(default_factory=lambda: {"トビ", "トビ率"})
 56        """トビ関連ワード"""
 57        yakuman: set[str] = field(default_factory=lambda: {"役満", "役満和了", "役満和了率"})
 58        """役満関連ワード"""
 59        regulation: set[str] = field(default_factory=lambda: {"卓外", "卓外清算", "卓外ポイント"})
 60        """レギュレーション関連ワード"""
 61        other: set[str] = field(default_factory=lambda: {"その他", "メモ"})
 62        """その他ワード"""
 63
 64    def __init__(self, config_file: Path) -> None:
 65        self.config_file: Path = config_file
 66        """メイン設定ファイルパス"""
 67
 68        try:
 69            self.main_parser: ConfigParser = ConfigParser()
 70            self.main_parser.read(self.config_file, encoding="utf-8")
 71        except Exception as err:
 72            raise RuntimeError(err) from err
 73
 74        # セクションチェック
 75        option_sections = [
 76            "setting",
 77            "results",
 78            "graph",
 79            "ranking",
 80            "report",
 81            "help",
 82            "alias",
 83            "member",
 84            "team",
 85        ]
 86        for x in option_sections:
 87            if x not in self.main_parser.sections():
 88                self.main_parser.add_section(x)
 89
 90        # 基本設定
 91        self.script_dir: Path = Path(sys.argv[0]).absolute().parent
 92        """スクリプトが保存されているディレクトリパス"""
 93        self.config_dir: Path = self.config_file.absolute().parent
 94        """設定ファイルが保存されているディレクトリパス"""
 95        self.selected_service: ServiceType = ServiceType.SLACK
 96        """連携先サービス"""
 97
 98        # 設定値
 99        self.setting: SettingSection = SettingSection()
100        """settingセクション設定値"""
101        self.alias: AliasSection = AliasSection()
102        """aliasセクション設定値"""
103        self.member: MemberSection = MemberSection(self)
104        """memberセクション設定値"""
105        self.team: TeamSection = TeamSection(self)
106        """teamセクション設定値"""
107        self.badge: BadgeDisplay = BadgeDisplay(self)
108        """バッジ設定"""
109
110        # サブコマンド
111        self.results: "SubCommands" = ResultsConfig()
112        """resultsセクション設定値"""
113        self.graph: "SubCommands" = GraphConfig()
114        """graphセクション設定値"""
115        self.ranking: "SubCommands" = RankingConfig()
116        """rankingセクション設定値"""
117        self.report: "SubCommands" = ReportConfig()
118        """reportセクション設定値"""
119        self.help: "SubCommands" = HelpConfig()
120        """helpセクション設定値"""
121
122        self.initialization()
123
124        self.dropitems = self.FixedWords()
125        """非表示項目リスト"""
126        self.rule: RuleSet = RuleSet()
127        """ルール情報"""
128
129    def initialization(self) -> None:
130        """設定ファイル読み込み"""
131        self.setting.config_load(self.main_parser["setting"])
132        self.alias.config_load(self.main_parser["alias"])
133        self.member.config_load(self.main_parser["member"])
134        self.team.config_load(self.main_parser["team"])
135
136        self.results.config_load(self.main_parser["results"])
137        self.graph.config_load(self.main_parser["graph"])
138        self.ranking.config_load(self.main_parser["ranking"])
139        self.report.config_load(self.main_parser["report"])
140        self.help.config_load(self.main_parser["help"])
141
142        # フォントファイルチェック
143        for chk_dir in (self.config_dir, self.script_dir):
144            chk_file = chk_dir / str(self.setting.font_file)
145            if chk_file.exists():
146                self.setting.font_file = chk_file
147                break
148        else:
149            if not self.setting.font_file.exists():
150                logging.critical("The specified font file cannot be found.")
151                sys.exit(255)
152
153        # 作業ディレクトリパス
154        if not self.setting.work_dir.is_absolute():
155            self.setting.work_dir = self.script_dir / self.setting.work_dir
156
157        # データベース関連
158        if isinstance(self.setting.database_file, Path) and not self.setting.database_file.exists():
159            self.setting.database_file = self.config_dir / str(self.setting.database_file)
160
161    def word_list(self, add_words: list[str] | None = None) -> list[str]:
162        """
163        設定されている値、キーワードをリスト化する
164
165        Args:
166            add_words (list[str] | None, optional): リストに追加するワード. Defaults to None.
167
168        Returns:
169            list[str]: リスト化されたキーワード
170
171        """
172        words: list[str] = []
173
174        if add_words:
175            words.extend(add_words)
176
177        words.extend(list(self.rule.keyword_mapping.keys()))
178        words.extend([self.setting.remarks_word])
179
180        for command_name in CommandType:
181            if hasattr(self, str(command_name)):
182                if (command := getattr(self, str(command_name))) and isinstance(command, SubCommands):
183                    words.append(command.default_commandword)
184                    words.extend(command.commandword)
185                    words.extend(command.command_suffix)
186
187        for k, v in self.alias.to_dict().items():
188            if isinstance(v, list):
189                words.append(k)
190                words.extend(v)
191
192        words = [x for x in set(words) if x != ""]  # 重複排除/空文字削除
193
194        return words
195
196    def overwrite(self, additional_config: Path, section_name: str) -> None:
197        """
198        指定セクションを上書き
199
200        Args:
201            additional_config (Path): 追加設定ファイルパス
202            section_name (str): セクション名
203
204        """
205        if not additional_config.exists():
206            return
207
208        try:
209            additional_config_parser = ConfigParser()
210            additional_config_parser.read([self.config_file, additional_config], encoding="utf-8")
211        except Exception as err:
212            logging.error(err)
213            return
214
215        protected_values: Union[str, list[str]]
216        match section_name:
217            case "setting":
218                protected_values = self.setting.remarks_word  # 上書き保護
219                self.setting.config_load(additional_config_parser[section_name])
220                self.setting.remarks_word = protected_values
221            case "results":
222                protected_values = self.results.commandword  # 上書き保護
223                self.results.config_load(additional_config_parser[section_name])
224                self.results.commandword = protected_values
225            case "graph":
226                protected_values = self.graph.commandword  # 上書き保護
227                self.graph.config_load(additional_config_parser[section_name])
228                self.graph.commandword = protected_values
229            case "ranking":
230                protected_values = self.ranking.commandword  # 上書き保護
231                self.ranking.config_load(additional_config_parser[section_name])
232                self.ranking.commandword = protected_values
233            case "report":
234                protected_values = self.report.commandword  # 上書き保護
235                self.report.config_load(additional_config_parser[section_name])
236                self.report.commandword = protected_values
237            case _:
238                return
239
240    def read_channel_config(self, section_name: str, ret_dict: dict[str, Any]) -> Optional[Path]:
241        """
242        チャンネル個別設定読み込み
243
244        Args:
245            section_name (str): チャンネル個別設定セクション名
246            ret_dict (dict[str, Any]): パラメータ
247
248        Returns:
249            Optional[Path]: 個別設定読み込み結果
250            - *Path*: 読み込んだ設定ファイルパス
251            - *None*: 読み込める設定ファイルがない
252
253        """
254        config_path: Optional[Path] = None
255
256        if self.main_parser.has_section(section_name):
257            if default_rule := self.main_parser[section_name].get("default_rule"):
258                ret_dict.update({"default_rule": default_rule})
259            if channel_config := self.main_parser[section_name].get("channel_config"):
260                config_path = Path(channel_config)
261                if config_path.exists():
262                    logging.debug("Override: %s", config_path.absolute())
263                    self.initialization()
264                    self.overwrite(config_path, "setting")
265                    self.overwrite(config_path, "results")
266                    self.overwrite(config_path, "graph")
267                    self.overwrite(config_path, "ranking")
268                    self.overwrite(config_path, "report")
269                else:
270                    config_path = None
271
272        read_memberslist()
273
274        return config_path
275
276    def resolve_channel_id(self, section_name: Optional[str] = None) -> str:
277        """
278        メイン設定から優先度の高いチャンネルIDを取得する
279
280        Args:
281            section_name (Optional[str]): チャンネル個別設定セクション名
282
283        Returns:
284            str: チャンネルID
285
286        """
287        for section in (section_name, self.selected_service, "setting"):
288            if section and self.main_parser.has_section(section):
289                if channel_id := self.main_parser[section].get("channel_id"):
290                    return channel_id
291
292        if section_name:
293            return section_name
294        return ""

アプリケーション設定

AppConfig(config_file: pathlib.Path)
 64    def __init__(self, config_file: Path) -> None:
 65        self.config_file: Path = config_file
 66        """メイン設定ファイルパス"""
 67
 68        try:
 69            self.main_parser: ConfigParser = ConfigParser()
 70            self.main_parser.read(self.config_file, encoding="utf-8")
 71        except Exception as err:
 72            raise RuntimeError(err) from err
 73
 74        # セクションチェック
 75        option_sections = [
 76            "setting",
 77            "results",
 78            "graph",
 79            "ranking",
 80            "report",
 81            "help",
 82            "alias",
 83            "member",
 84            "team",
 85        ]
 86        for x in option_sections:
 87            if x not in self.main_parser.sections():
 88                self.main_parser.add_section(x)
 89
 90        # 基本設定
 91        self.script_dir: Path = Path(sys.argv[0]).absolute().parent
 92        """スクリプトが保存されているディレクトリパス"""
 93        self.config_dir: Path = self.config_file.absolute().parent
 94        """設定ファイルが保存されているディレクトリパス"""
 95        self.selected_service: ServiceType = ServiceType.SLACK
 96        """連携先サービス"""
 97
 98        # 設定値
 99        self.setting: SettingSection = SettingSection()
100        """settingセクション設定値"""
101        self.alias: AliasSection = AliasSection()
102        """aliasセクション設定値"""
103        self.member: MemberSection = MemberSection(self)
104        """memberセクション設定値"""
105        self.team: TeamSection = TeamSection(self)
106        """teamセクション設定値"""
107        self.badge: BadgeDisplay = BadgeDisplay(self)
108        """バッジ設定"""
109
110        # サブコマンド
111        self.results: "SubCommands" = ResultsConfig()
112        """resultsセクション設定値"""
113        self.graph: "SubCommands" = GraphConfig()
114        """graphセクション設定値"""
115        self.ranking: "SubCommands" = RankingConfig()
116        """rankingセクション設定値"""
117        self.report: "SubCommands" = ReportConfig()
118        """reportセクション設定値"""
119        self.help: "SubCommands" = HelpConfig()
120        """helpセクション設定値"""
121
122        self.initialization()
123
124        self.dropitems = self.FixedWords()
125        """非表示項目リスト"""
126        self.rule: RuleSet = RuleSet()
127        """ルール情報"""
config_file: pathlib.Path

メイン設定ファイルパス

script_dir: pathlib.Path

スクリプトが保存されているディレクトリパス

config_dir: pathlib.Path

設定ファイルが保存されているディレクトリパス

selected_service: libs.types.ServiceType

連携先サービス

settingセクション設定値

aliasセクション設定値

memberセクション設定値

teamセクション設定値

badge: BadgeDisplay

バッジ設定

resultsセクション設定値

graphセクション設定値

rankingセクション設定値

reportセクション設定値

helpセクション設定値

dropitems

非表示項目リスト

ルール情報

def initialization(self) -> None:
129    def initialization(self) -> None:
130        """設定ファイル読み込み"""
131        self.setting.config_load(self.main_parser["setting"])
132        self.alias.config_load(self.main_parser["alias"])
133        self.member.config_load(self.main_parser["member"])
134        self.team.config_load(self.main_parser["team"])
135
136        self.results.config_load(self.main_parser["results"])
137        self.graph.config_load(self.main_parser["graph"])
138        self.ranking.config_load(self.main_parser["ranking"])
139        self.report.config_load(self.main_parser["report"])
140        self.help.config_load(self.main_parser["help"])
141
142        # フォントファイルチェック
143        for chk_dir in (self.config_dir, self.script_dir):
144            chk_file = chk_dir / str(self.setting.font_file)
145            if chk_file.exists():
146                self.setting.font_file = chk_file
147                break
148        else:
149            if not self.setting.font_file.exists():
150                logging.critical("The specified font file cannot be found.")
151                sys.exit(255)
152
153        # 作業ディレクトリパス
154        if not self.setting.work_dir.is_absolute():
155            self.setting.work_dir = self.script_dir / self.setting.work_dir
156
157        # データベース関連
158        if isinstance(self.setting.database_file, Path) and not self.setting.database_file.exists():
159            self.setting.database_file = self.config_dir / str(self.setting.database_file)

設定ファイル読み込み

def word_list(self, add_words: list[str] | None = None) -> list[str]:
161    def word_list(self, add_words: list[str] | None = None) -> list[str]:
162        """
163        設定されている値、キーワードをリスト化する
164
165        Args:
166            add_words (list[str] | None, optional): リストに追加するワード. Defaults to None.
167
168        Returns:
169            list[str]: リスト化されたキーワード
170
171        """
172        words: list[str] = []
173
174        if add_words:
175            words.extend(add_words)
176
177        words.extend(list(self.rule.keyword_mapping.keys()))
178        words.extend([self.setting.remarks_word])
179
180        for command_name in CommandType:
181            if hasattr(self, str(command_name)):
182                if (command := getattr(self, str(command_name))) and isinstance(command, SubCommands):
183                    words.append(command.default_commandword)
184                    words.extend(command.commandword)
185                    words.extend(command.command_suffix)
186
187        for k, v in self.alias.to_dict().items():
188            if isinstance(v, list):
189                words.append(k)
190                words.extend(v)
191
192        words = [x for x in set(words) if x != ""]  # 重複排除/空文字削除
193
194        return words

設定されている値、キーワードをリスト化する

Arguments:
  • add_words (list[str] | None, optional): リストに追加するワード. Defaults to None.
Returns:

list[str]: リスト化されたキーワード

def overwrite(self, additional_config: pathlib.Path, section_name: str) -> None:
196    def overwrite(self, additional_config: Path, section_name: str) -> None:
197        """
198        指定セクションを上書き
199
200        Args:
201            additional_config (Path): 追加設定ファイルパス
202            section_name (str): セクション名
203
204        """
205        if not additional_config.exists():
206            return
207
208        try:
209            additional_config_parser = ConfigParser()
210            additional_config_parser.read([self.config_file, additional_config], encoding="utf-8")
211        except Exception as err:
212            logging.error(err)
213            return
214
215        protected_values: Union[str, list[str]]
216        match section_name:
217            case "setting":
218                protected_values = self.setting.remarks_word  # 上書き保護
219                self.setting.config_load(additional_config_parser[section_name])
220                self.setting.remarks_word = protected_values
221            case "results":
222                protected_values = self.results.commandword  # 上書き保護
223                self.results.config_load(additional_config_parser[section_name])
224                self.results.commandword = protected_values
225            case "graph":
226                protected_values = self.graph.commandword  # 上書き保護
227                self.graph.config_load(additional_config_parser[section_name])
228                self.graph.commandword = protected_values
229            case "ranking":
230                protected_values = self.ranking.commandword  # 上書き保護
231                self.ranking.config_load(additional_config_parser[section_name])
232                self.ranking.commandword = protected_values
233            case "report":
234                protected_values = self.report.commandword  # 上書き保護
235                self.report.config_load(additional_config_parser[section_name])
236                self.report.commandword = protected_values
237            case _:
238                return

指定セクションを上書き

Arguments:
  • additional_config (Path): 追加設定ファイルパス
  • section_name (str): セクション名
def read_channel_config( self, section_name: str, ret_dict: dict[str, typing.Any]) -> pathlib.Path | None:
240    def read_channel_config(self, section_name: str, ret_dict: dict[str, Any]) -> Optional[Path]:
241        """
242        チャンネル個別設定読み込み
243
244        Args:
245            section_name (str): チャンネル個別設定セクション名
246            ret_dict (dict[str, Any]): パラメータ
247
248        Returns:
249            Optional[Path]: 個別設定読み込み結果
250            - *Path*: 読み込んだ設定ファイルパス
251            - *None*: 読み込める設定ファイルがない
252
253        """
254        config_path: Optional[Path] = None
255
256        if self.main_parser.has_section(section_name):
257            if default_rule := self.main_parser[section_name].get("default_rule"):
258                ret_dict.update({"default_rule": default_rule})
259            if channel_config := self.main_parser[section_name].get("channel_config"):
260                config_path = Path(channel_config)
261                if config_path.exists():
262                    logging.debug("Override: %s", config_path.absolute())
263                    self.initialization()
264                    self.overwrite(config_path, "setting")
265                    self.overwrite(config_path, "results")
266                    self.overwrite(config_path, "graph")
267                    self.overwrite(config_path, "ranking")
268                    self.overwrite(config_path, "report")
269                else:
270                    config_path = None
271
272        read_memberslist()
273
274        return config_path

チャンネル個別設定読み込み

Arguments:
  • section_name (str): チャンネル個別設定セクション名
  • ret_dict (dict[str, Any]): パラメータ
Returns:

Optional[Path]: 個別設定読み込み結果

  • Path: 読み込んだ設定ファイルパス
  • None: 読み込める設定ファイルがない
def resolve_channel_id(self, section_name: str | None = None) -> str:
276    def resolve_channel_id(self, section_name: Optional[str] = None) -> str:
277        """
278        メイン設定から優先度の高いチャンネルIDを取得する
279
280        Args:
281            section_name (Optional[str]): チャンネル個別設定セクション名
282
283        Returns:
284            str: チャンネルID
285
286        """
287        for section in (section_name, self.selected_service, "setting"):
288            if section and self.main_parser.has_section(section):
289                if channel_id := self.main_parser[section].get("channel_id"):
290                    return channel_id
291
292        if section_name:
293            return section_name
294        return ""

メイン設定から優先度の高いチャンネルIDを取得する

Arguments:
  • section_name (Optional[str]): チャンネル個別設定セクション名
Returns:

str: チャンネルID

@dataclass
class AppConfig.FixedWords:
51    @dataclass
52    class FixedWords:
53        """非表示項目用固定ワード"""
54
55        flying: set[str] = field(default_factory=lambda: {"トビ", "トビ率"})
56        """トビ関連ワード"""
57        yakuman: set[str] = field(default_factory=lambda: {"役満", "役満和了", "役満和了率"})
58        """役満関連ワード"""
59        regulation: set[str] = field(default_factory=lambda: {"卓外", "卓外清算", "卓外ポイント"})
60        """レギュレーション関連ワード"""
61        other: set[str] = field(default_factory=lambda: {"その他", "メモ"})
62        """その他ワード"""

非表示項目用固定ワード

AppConfig.FixedWords( flying: set[str] = <factory>, yakuman: set[str] = <factory>, regulation: set[str] = <factory>, other: set[str] = <factory>)
flying: set[str]

トビ関連ワード

yakuman: set[str]

役満関連ワード

regulation: set[str]

レギュレーション関連ワード

other: set[str]

その他ワード