cls.config
cls/config.py
1""" 2cls/config.py 3""" 4 5import logging 6import shutil 7import sys 8from configparser import ConfigParser 9from dataclasses import dataclass, field 10from itertools import chain 11from math import ceil 12from pathlib import Path, PosixPath 13from types import NoneType, UnionType 14from typing import TYPE_CHECKING, Any, Literal, Optional, TypeAlias, Union 15 16from libs.types import GradeTableDict 17 18if TYPE_CHECKING: 19 from configparser import SectionProxy 20 21SubClassType: TypeAlias = Union[ 22 "MahjongSection", 23 "SettingSection", 24 "MemberSection", 25 "TeamSection", 26 "AliasSection", 27 "CommentSection", 28 "DropItems", 29 "BadgeDisplay", 30 "SubCommand", 31] 32 33 34class CommonMethodMixin: 35 """共通メソッド""" 36 37 _section: "SectionProxy" 38 39 def get(self, key: str, fallback: Any = None) -> Any: 40 """値の取得""" 41 return self._section.get(key, fallback) 42 43 def getint(self, key: str, fallback: int = 0) -> int: 44 """整数値の取得""" 45 return self._section.getint(key, fallback) 46 47 def getfloat(self, key: str, fallback: float = 0.0) -> float: 48 """数値の取得""" 49 return self._section.getfloat(key, fallback) 50 51 def getboolean(self, key: str, fallback: bool = False) -> bool: 52 """真偽値の取得""" 53 return self._section.getboolean(key, fallback) 54 55 def getlist(self, key: str) -> list: 56 """リストの取得""" 57 return [x.strip() for x in self._section.get(key, "").split(",")] 58 59 def keys(self) -> list: 60 """キーリストの返却""" 61 return list(self._section.keys()) 62 63 def values(self) -> list: 64 """値リストの返却""" 65 return list(self._section.values()) 66 67 def items(self): 68 """ItemsViewを返却""" 69 return self._section.items() 70 71 def to_dict(self) -> dict[str, str]: 72 """辞書型に変換""" 73 return dict(self._section.items()) 74 75 76class BaseSection(CommonMethodMixin): 77 """共通処理""" 78 79 def __init__(self, outer: SubClassType, section_name: str): 80 parser = outer._parser 81 if section_name not in parser: 82 return 83 self._section = parser[section_name] 84 85 self.initialization() 86 self.section = section_name # セクション名保持 87 88 def __repr__(self) -> str: 89 return str({k: v for k, v in vars(self).items() if not str(k).startswith("_")}) 90 91 def initialization(self): 92 """設定ファイルから値の取り込み""" 93 for k in self._section.keys(): 94 if k in self.__dict__: 95 match type(self.__dict__.get(k)): 96 case v_type if v_type is str: 97 setattr(self, k, self._section.get(k, fallback=self.get(k))) 98 case v_type if v_type is int: 99 setattr(self, k, self._section.getint(k, fallback=self.get(k))) 100 case v_type if v_type is float: 101 setattr(self, k, self._section.getfloat(k, fallback=self.get(k))) 102 case v_type if v_type is bool: 103 setattr(self, k, self._section.getboolean(k, fallback=self.get(k))) 104 case v_type if v_type is list: 105 v_list = [x.strip() for x in self._section.get(k, fallback=self.get(k)).split(",")] 106 current_list = getattr(self, k) 107 if isinstance(current_list, list) and current_list: # 設定済みリストは追加 108 current_list.extend(v_list) 109 else: 110 setattr(self, k, v_list) 111 case v_type if v_type is UnionType: # 文字列 or None 112 if set(v_type.__args__) == {str, type(None)}: 113 setattr(self, k, self._section.get(k, fallback=self.get(k))) 114 case v_type if v_type is PosixPath: 115 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 116 case v_type if v_type is NoneType: 117 if k in ["backup_dir"]: # ディレクトリを指定する設定はPathで格納 118 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 119 else: 120 setattr(self, k, self._section.get(k, fallback=self.get(k))) 121 case _: 122 setattr(self, k, self.__dict__.get(k)) 123 124 def to_dict(self) -> dict: 125 """必要なパラメータを辞書型で返す 126 127 Returns: 128 dict: 返却値 129 """ 130 131 ret_dict: dict = {} 132 for key in vars(self): 133 if key.startswith("_"): 134 continue 135 ret_dict[key] = getattr(self, key) 136 137 return ret_dict 138 139 140class MahjongSection(BaseSection): 141 """mahjongセクション初期値""" 142 143 def __init__(self, outer: "AppConfig", section_name): 144 self._parser = outer._parser 145 146 # 初期値セット 147 self.rule_version: str = "" 148 """ルール判別識別子""" 149 self.origin_point: int = 250 150 """配給原点""" 151 self.return_point: int = 300 152 """返し点""" 153 self.rank_point: list = [] 154 """順位点""" 155 self.ignore_flying: bool = False 156 """トビカウント 157 - True: なし 158 - False: あり 159 """ 160 self.draw_split: bool = False 161 """同点時の順位点 162 - True: 山分けにする 163 - False: 席順で決める 164 """ 165 self.regulations_type2: list = [] 166 """メモで役満として扱う単語リスト(カンマ区切り)""" 167 168 # 設定値取り込み 169 super().__init__(self, section_name) 170 171 # 順位点更新 172 if not self.rank_point: 173 self.rank_point = [30, 10, -10, -30] 174 175 self.rank_point = list(map(int, self.rank_point)) # 数値化 176 177 178class SettingSection(BaseSection): 179 """settingセクション初期値""" 180 181 def __init__(self, outer: "AppConfig", section_name: str): 182 self._parser = outer._parser 183 184 # 初期値セット 185 self.help: str = "麻雀成績ヘルプ" 186 """ヘルプ表示キーワード""" 187 self.keyword: str = "終局" 188 """成績記録キーワード""" 189 self.remarks_word: str = "麻雀成績メモ" 190 """メモ記録用キーワード""" 191 self.time_adjust: int = 12 192 """日付変更後、集計範囲に含める追加時間""" 193 self.guest_mark: str = "※" 194 """ゲスト無効時に未登録メンバーに付与する印""" 195 self.database_file: Union[Path, str] = Path("mahjong.db") 196 """成績管理データベースファイル名""" 197 self.backup_dir: Optional[Path] = None 198 """バックアップ先ディレクトリ""" 199 self.font_file: Path = Path("ipaexg.ttf") 200 """グラフ描写に使用するフォントファイル""" 201 self.graph_style: str = "ggplot" 202 """グラフスタイル""" 203 self.work_dir: Path = Path("work") 204 205 # 設定値取り込み 206 super().__init__(self, section_name) 207 208 # 作業用ディレクトリ作成 209 if self.work_dir.is_dir(): 210 shutil.rmtree(self.work_dir) 211 try: 212 self.work_dir.mkdir(exist_ok=True) 213 except FileExistsError as err: 214 sys.exit(str(err)) 215 216 # フォントファイルチェック 217 for chk_dir in (outer.config_dir, outer.script_dir): 218 chk_file = chk_dir / str(self.font_file) 219 if chk_file.exists(): 220 self.font_file = chk_file 221 break 222 else: 223 if not self.font_file.exists(): 224 logging.critical("The specified font file cannot be found.") 225 sys.exit(255) 226 227 # データベース関連 228 for chk_dir in (outer.config_dir, outer.script_dir): 229 chk_file = chk_dir / str(self.database_file) 230 if chk_file.exists(): 231 self.database_file = chk_file 232 break 233 234 if isinstance(self.backup_dir, PosixPath): 235 try: 236 self.backup_dir.mkdir(exist_ok=True) 237 except FileExistsError as err: 238 sys.exit(str(err)) 239 240 241class MemberSection(BaseSection): 242 "memberセクション初期値""" 243 244 def __init__(self, outer: "AppConfig", section_name: str): 245 self._parser = outer._parser 246 247 # 初期値セット 248 self.registration_limit: int = 255 249 """登録メンバー上限数""" 250 self.character_limit: int = 8 251 """名前に使用できる文字数""" 252 self.alias_limit: int = 16 253 """別名登録上限数""" 254 self.guest_name: str = "ゲスト" 255 """未登録メンバー名称""" 256 257 # 設定値取り込み 258 super().__init__(self, section_name) 259 260 # 呼び出しキーワード取り込み 261 self.commandword = [x.strip() for x in self._parser.get("member", "commandword", fallback="メンバー一覧").split(",")] 262 263 264class TeamSection(BaseSection): 265 """teamセクション初期値""" 266 267 def __init__(self, outer: "AppConfig", section_name: str): 268 self._parser = outer._parser 269 270 # 初期値セット 271 self.registration_limit: int = 255 272 """登録チーム上限数""" 273 self.character_limit: int = 16 274 """チーム名に使用できる文字数""" 275 self.member_limit: int = 16 276 """チームに所属できるメンバー上限""" 277 self.friendly_fire: bool = True 278 """チームメイトが同卓しているゲームを集計対象に含めるか""" 279 280 # 設定値取り込み 281 super().__init__(self, section_name) 282 283 # 呼び出しキーワード取り込み 284 self.commandword = [x.strip() for x in self._parser.get("team", "commandword", fallback="チーム一覧").split(",")] 285 286 287class AliasSection(BaseSection): 288 """aliasセクション初期値""" 289 290 def __init__(self, outer: "AppConfig", section_name: str): 291 self._parser = outer._parser 292 293 # 初期値セット 294 self.results: list = ["成績"] 295 self.graph: list = ["グラフ"] 296 self.ranking: list = ["ランキング"] 297 self.report: list = ["レポート"] 298 self.download: list = ["ダウンロード"] 299 self.member: list = ["userlist", "member_list"] 300 self.add: list = [] 301 self.delete: list = ["del"] # "del"はbuilt-inで使用 302 self.team_create: list = [] 303 self.team_del: list = [] 304 self.team_add: list = [] 305 self.team_remove: list = [] 306 self.team_list: list = [] 307 self.team_clear: list = [] 308 309 # 設定値取り込み 310 super().__init__(self, section_name) 311 312 # デフォルト値として自身と同じ名前のコマンドを登録する # 313 for k in self.to_dict(): 314 current_list = getattr(self, k) 315 if isinstance(current_list, list): 316 current_list.append(k) 317 # delのエイリアス取り込み(設定ファイルに`delete`と書かれていない) 318 list_data = [x.strip() for x in str(self._parser.get("alias", "del", fallback="")).split(",")] 319 self.delete.extend(list_data) 320 321 322class CommentSection(BaseSection): 323 """commentセクション初期値""" 324 325 def __init__(self, outer: "AppConfig", section_name: str): 326 self._parser = outer._parser 327 328 # 初期値セット 329 self.group_length: int = 0 330 """コメント検索時の集約文字数(固定指定)""" 331 self.search_word: str = "" 332 """コメント検索時の検索文字列(固定指定)""" 333 334 # 設定値取り込み 335 super().__init__(self, section_name) 336 337 338class DropItems(BaseSection): 339 """非表示項目リスト""" 340 341 def __init__(self, outer: "AppConfig"): 342 self._parser = outer._parser 343 344 # 初期値セット 345 self.results: list = [] 346 self.ranking: list = [] 347 self.report: list = [] 348 349 # 設定値取り込み 350 super().__init__(self, "") 351 352 self.results = [x.strip() for x in self._parser.get("results", "dropitems", fallback="").split(",")] 353 self.ranking = [x.strip() for x in self._parser.get("ranking", "dropitems", fallback="").split(",")] 354 self.report = [x.strip() for x in self._parser.get("report", "dropitems", fallback="").split(",")] 355 356 357class BadgeDisplay(BaseSection): 358 """バッジ表示""" 359 360 @dataclass 361 class BadgeGradeSpec: 362 """段位""" 363 364 table_name: str = field(default=str()) 365 table: GradeTableDict = field(default_factory=GradeTableDict) 366 367 grade: "BadgeGradeSpec" = BadgeGradeSpec() 368 369 def __init__(self, outer: "AppConfig"): 370 self._parser = outer._parser 371 super().__init__(self, "") 372 373 self.grade.table_name = self._parser.get("grade", "table_name", fallback="") 374 375 376class SubCommand(BaseSection): 377 """サブコマンド共通クラス""" 378 379 def __init__(self, outer: "AppConfig", section_name: str, default: str): 380 self._parser = outer._parser 381 self.section = section_name 382 383 # 初期値セット 384 self.section: str = "" 385 self.commandword: list = [] 386 """呼び出しキーワード""" 387 self.aggregation_range: str = "当日" 388 """検索範囲未指定時に使用される範囲""" 389 self.individual: bool = True 390 """個人/チーム集計切替フラグ 391 - True: 個人集計 392 - False: チーム集計 393 """ 394 self.all_player: bool = False 395 self.daily: bool = True 396 self.fourfold: bool = True 397 self.game_results: bool = False 398 self.guest_skip: bool = True 399 self.guest_skip2: bool = True 400 self.ranked: int = 3 401 self.score_comparisons: bool = False 402 """スコア比較""" 403 self.statistics: bool = False 404 """統計情報表示""" 405 self.stipulated: int = 0 406 """規定打数指定""" 407 self.stipulated_rate: float = 0.05 408 """規定打数計算レート""" 409 self.unregistered_replace: bool = True 410 """メンバー未登録プレイヤー名をゲストに置き換えるかフラグ 411 - True: 置き換える 412 - False: 置き換えない 413 """ 414 self.anonymous: bool = False 415 """匿名化フラグ""" 416 self.verbose: bool = False 417 """詳細情報出力フラグ""" 418 self.versus_matrix: bool = False 419 """対戦マトリックス表示""" 420 self.collection: str = "" 421 self.search_word: str = "" 422 self.group_length: int = 0 423 self.always_argument: list = [] 424 """オプションとして常に付与される文字列""" 425 self.format: str = "" 426 self.filename: str = "" 427 self.interval: int = 80 428 429 # 設定値取り込み 430 super().__init__(self, section_name) 431 432 # 呼び出しキーワード取り込み 433 self.commandword = [x.strip() for x in self._parser.get(section_name, "commandword", fallback=default).split(",")] 434 435 def stipulated_calculation(self, game_count: int) -> int: 436 """規定打数をゲーム数から計算 437 438 Args: 439 game_count (int): 指定ゲーム数 440 441 Returns: 442 int: 規定ゲーム数 443 """ 444 445 return int(ceil(game_count * self.stipulated_rate) + 1) 446 447 448class AppConfig: 449 """コンフィグ解析クラス""" 450 451 def __init__(self, config_file: str): 452 _config = Path(config_file) 453 try: 454 self._parser = ConfigParser() 455 self._parser.read(_config, encoding="utf-8") 456 except Exception as err: 457 raise RuntimeError(err) from err 458 459 # 必須セクションチェック 460 for x in ("mahjong", "setting"): 461 if x not in self._parser.sections(): 462 logging.critical("Required section not found. (%s)", x) 463 sys.exit(255) 464 465 # オプションセクションチェック 466 option_sections = [ 467 "results", 468 "graph", 469 "ranking", 470 "report", 471 "alias", 472 "member", 473 "team", 474 "comment", 475 "regulations", 476 ] 477 for x in option_sections: 478 if x not in self._parser.sections(): 479 self._parser.add_section(x) 480 481 # set base directory 482 self.script_dir = Path(sys.argv[0]).absolute().parent 483 """スクリプトが保存されているディレクトリパス""" 484 self.config_dir = _config.absolute().parent 485 """設定ファイルが保存されているディレクトリパス""" 486 487 # 設定値取り込み 488 self.setting = SettingSection(self, "setting") 489 """settingセクション設定値""" 490 self.mahjong = MahjongSection(self, "mahjong") 491 """mahjongセクション設定値""" 492 self.member = MemberSection(self, "member") 493 """memberセクション設定値""" 494 self.team = TeamSection(self, "team") 495 """teamセクション設定値""" 496 self.alias = AliasSection(self, "alias") 497 """aliasセクション設定値""" 498 self.comment = CommentSection(self, "comment") 499 """commentセクション設定値""" 500 self.dropitems = DropItems(self) # 非表示項目 501 """非表示項目""" 502 self.badge = BadgeDisplay(self) # バッジ表示 503 """バッジ設定""" 504 505 # サブコマンド 506 self.results = SubCommand(self, "results", "麻雀成績") 507 """resultsセクション設定値""" 508 self.graph = SubCommand(self, "graph", "麻雀グラフ") 509 """graphセクション設定値""" 510 self.ranking = SubCommand(self, "ranking", "麻雀ランキング") 511 """rankingセクション設定値""" 512 self.report = SubCommand(self, "report", "麻雀成績レポート") 513 """reportセクション設定値""" 514 515 # 共通設定値 516 self.undefined_word: int = 0 517 """レギュレーションワードテーブルに登録されていないワードの種別""" 518 self.aggregate_unit: Literal["A", "M", "Y", None] = None 519 """レポート生成用日付範囲デフォルト値(レポート生成用) 520 - *A*: 全期間 521 - *M*: 月別 522 - *Y*: 年別 523 - *None*: 未定義 524 """ 525 526 def word_list(self) -> list: 527 """設定されている値、キーワードをリスト化する 528 529 Returns: 530 list: リスト化されたキーワード 531 """ 532 533 words: list = [ 534 [self.setting.keyword], 535 [self.setting.remarks_word], 536 self.results.commandword, 537 self.graph.commandword, 538 self.ranking.commandword, 539 self.report.commandword, 540 ] 541 542 for k, v in self.alias.to_dict().items(): 543 if isinstance(v, list): 544 words.append([k]) 545 words.append(v) 546 547 words = list(set(chain.from_iterable(words))) # 重複排除/平滑化 548 words = [x for x in words if x != ""] # 空文字削除 549 550 return words
SubClassType: TypeAlias =
Union[ForwardRef('MahjongSection'), ForwardRef('SettingSection'), ForwardRef('MemberSection'), ForwardRef('TeamSection'), ForwardRef('AliasSection'), ForwardRef('CommentSection'), ForwardRef('DropItems'), ForwardRef('BadgeDisplay'), ForwardRef('SubCommand')]
class
CommonMethodMixin:
35class CommonMethodMixin: 36 """共通メソッド""" 37 38 _section: "SectionProxy" 39 40 def get(self, key: str, fallback: Any = None) -> Any: 41 """値の取得""" 42 return self._section.get(key, fallback) 43 44 def getint(self, key: str, fallback: int = 0) -> int: 45 """整数値の取得""" 46 return self._section.getint(key, fallback) 47 48 def getfloat(self, key: str, fallback: float = 0.0) -> float: 49 """数値の取得""" 50 return self._section.getfloat(key, fallback) 51 52 def getboolean(self, key: str, fallback: bool = False) -> bool: 53 """真偽値の取得""" 54 return self._section.getboolean(key, fallback) 55 56 def getlist(self, key: str) -> list: 57 """リストの取得""" 58 return [x.strip() for x in self._section.get(key, "").split(",")] 59 60 def keys(self) -> list: 61 """キーリストの返却""" 62 return list(self._section.keys()) 63 64 def values(self) -> list: 65 """値リストの返却""" 66 return list(self._section.values()) 67 68 def items(self): 69 """ItemsViewを返却""" 70 return self._section.items() 71 72 def to_dict(self) -> dict[str, str]: 73 """辞書型に変換""" 74 return dict(self._section.items())
共通メソッド
def
get(self, key: str, fallback: Any = None) -> Any:
40 def get(self, key: str, fallback: Any = None) -> Any: 41 """値の取得""" 42 return self._section.get(key, fallback)
値の取得
def
getint(self, key: str, fallback: int = 0) -> int:
44 def getint(self, key: str, fallback: int = 0) -> int: 45 """整数値の取得""" 46 return self._section.getint(key, fallback)
整数値の取得
def
getfloat(self, key: str, fallback: float = 0.0) -> float:
48 def getfloat(self, key: str, fallback: float = 0.0) -> float: 49 """数値の取得""" 50 return self._section.getfloat(key, fallback)
数値の取得
def
getboolean(self, key: str, fallback: bool = False) -> bool:
52 def getboolean(self, key: str, fallback: bool = False) -> bool: 53 """真偽値の取得""" 54 return self._section.getboolean(key, fallback)
真偽値の取得
def
getlist(self, key: str) -> list:
56 def getlist(self, key: str) -> list: 57 """リストの取得""" 58 return [x.strip() for x in self._section.get(key, "").split(",")]
リストの取得
77class BaseSection(CommonMethodMixin): 78 """共通処理""" 79 80 def __init__(self, outer: SubClassType, section_name: str): 81 parser = outer._parser 82 if section_name not in parser: 83 return 84 self._section = parser[section_name] 85 86 self.initialization() 87 self.section = section_name # セクション名保持 88 89 def __repr__(self) -> str: 90 return str({k: v for k, v in vars(self).items() if not str(k).startswith("_")}) 91 92 def initialization(self): 93 """設定ファイルから値の取り込み""" 94 for k in self._section.keys(): 95 if k in self.__dict__: 96 match type(self.__dict__.get(k)): 97 case v_type if v_type is str: 98 setattr(self, k, self._section.get(k, fallback=self.get(k))) 99 case v_type if v_type is int: 100 setattr(self, k, self._section.getint(k, fallback=self.get(k))) 101 case v_type if v_type is float: 102 setattr(self, k, self._section.getfloat(k, fallback=self.get(k))) 103 case v_type if v_type is bool: 104 setattr(self, k, self._section.getboolean(k, fallback=self.get(k))) 105 case v_type if v_type is list: 106 v_list = [x.strip() for x in self._section.get(k, fallback=self.get(k)).split(",")] 107 current_list = getattr(self, k) 108 if isinstance(current_list, list) and current_list: # 設定済みリストは追加 109 current_list.extend(v_list) 110 else: 111 setattr(self, k, v_list) 112 case v_type if v_type is UnionType: # 文字列 or None 113 if set(v_type.__args__) == {str, type(None)}: 114 setattr(self, k, self._section.get(k, fallback=self.get(k))) 115 case v_type if v_type is PosixPath: 116 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 117 case v_type if v_type is NoneType: 118 if k in ["backup_dir"]: # ディレクトリを指定する設定はPathで格納 119 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 120 else: 121 setattr(self, k, self._section.get(k, fallback=self.get(k))) 122 case _: 123 setattr(self, k, self.__dict__.get(k)) 124 125 def to_dict(self) -> dict: 126 """必要なパラメータを辞書型で返す 127 128 Returns: 129 dict: 返却値 130 """ 131 132 ret_dict: dict = {} 133 for key in vars(self): 134 if key.startswith("_"): 135 continue 136 ret_dict[key] = getattr(self, key) 137 138 return ret_dict
共通処理
BaseSection( outer: Union[MahjongSection, SettingSection, MemberSection, TeamSection, AliasSection, CommentSection, DropItems, BadgeDisplay, SubCommand], section_name: str)
def
initialization(self):
92 def initialization(self): 93 """設定ファイルから値の取り込み""" 94 for k in self._section.keys(): 95 if k in self.__dict__: 96 match type(self.__dict__.get(k)): 97 case v_type if v_type is str: 98 setattr(self, k, self._section.get(k, fallback=self.get(k))) 99 case v_type if v_type is int: 100 setattr(self, k, self._section.getint(k, fallback=self.get(k))) 101 case v_type if v_type is float: 102 setattr(self, k, self._section.getfloat(k, fallback=self.get(k))) 103 case v_type if v_type is bool: 104 setattr(self, k, self._section.getboolean(k, fallback=self.get(k))) 105 case v_type if v_type is list: 106 v_list = [x.strip() for x in self._section.get(k, fallback=self.get(k)).split(",")] 107 current_list = getattr(self, k) 108 if isinstance(current_list, list) and current_list: # 設定済みリストは追加 109 current_list.extend(v_list) 110 else: 111 setattr(self, k, v_list) 112 case v_type if v_type is UnionType: # 文字列 or None 113 if set(v_type.__args__) == {str, type(None)}: 114 setattr(self, k, self._section.get(k, fallback=self.get(k))) 115 case v_type if v_type is PosixPath: 116 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 117 case v_type if v_type is NoneType: 118 if k in ["backup_dir"]: # ディレクトリを指定する設定はPathで格納 119 setattr(self, k, Path(self._section.get(k, fallback=self.get(k)))) 120 else: 121 setattr(self, k, self._section.get(k, fallback=self.get(k))) 122 case _: 123 setattr(self, k, self.__dict__.get(k))
設定ファイルから値の取り込み
def
to_dict(self) -> dict:
125 def to_dict(self) -> dict: 126 """必要なパラメータを辞書型で返す 127 128 Returns: 129 dict: 返却値 130 """ 131 132 ret_dict: dict = {} 133 for key in vars(self): 134 if key.startswith("_"): 135 continue 136 ret_dict[key] = getattr(self, key) 137 138 return ret_dict
必要なパラメータを辞書型で返す
Returns:
dict: 返却値
Inherited Members
141class MahjongSection(BaseSection): 142 """mahjongセクション初期値""" 143 144 def __init__(self, outer: "AppConfig", section_name): 145 self._parser = outer._parser 146 147 # 初期値セット 148 self.rule_version: str = "" 149 """ルール判別識別子""" 150 self.origin_point: int = 250 151 """配給原点""" 152 self.return_point: int = 300 153 """返し点""" 154 self.rank_point: list = [] 155 """順位点""" 156 self.ignore_flying: bool = False 157 """トビカウント 158 - True: なし 159 - False: あり 160 """ 161 self.draw_split: bool = False 162 """同点時の順位点 163 - True: 山分けにする 164 - False: 席順で決める 165 """ 166 self.regulations_type2: list = [] 167 """メモで役満として扱う単語リスト(カンマ区切り)""" 168 169 # 設定値取り込み 170 super().__init__(self, section_name) 171 172 # 順位点更新 173 if not self.rank_point: 174 self.rank_point = [30, 10, -10, -30] 175 176 self.rank_point = list(map(int, self.rank_point)) # 数値化
mahjongセクション初期値
MahjongSection(outer: AppConfig, section_name)
144 def __init__(self, outer: "AppConfig", section_name): 145 self._parser = outer._parser 146 147 # 初期値セット 148 self.rule_version: str = "" 149 """ルール判別識別子""" 150 self.origin_point: int = 250 151 """配給原点""" 152 self.return_point: int = 300 153 """返し点""" 154 self.rank_point: list = [] 155 """順位点""" 156 self.ignore_flying: bool = False 157 """トビカウント 158 - True: なし 159 - False: あり 160 """ 161 self.draw_split: bool = False 162 """同点時の順位点 163 - True: 山分けにする 164 - False: 席順で決める 165 """ 166 self.regulations_type2: list = [] 167 """メモで役満として扱う単語リスト(カンマ区切り)""" 168 169 # 設定値取り込み 170 super().__init__(self, section_name) 171 172 # 順位点更新 173 if not self.rank_point: 174 self.rank_point = [30, 10, -10, -30] 175 176 self.rank_point = list(map(int, self.rank_point)) # 数値化
Inherited Members
179class SettingSection(BaseSection): 180 """settingセクション初期値""" 181 182 def __init__(self, outer: "AppConfig", section_name: str): 183 self._parser = outer._parser 184 185 # 初期値セット 186 self.help: str = "麻雀成績ヘルプ" 187 """ヘルプ表示キーワード""" 188 self.keyword: str = "終局" 189 """成績記録キーワード""" 190 self.remarks_word: str = "麻雀成績メモ" 191 """メモ記録用キーワード""" 192 self.time_adjust: int = 12 193 """日付変更後、集計範囲に含める追加時間""" 194 self.guest_mark: str = "※" 195 """ゲスト無効時に未登録メンバーに付与する印""" 196 self.database_file: Union[Path, str] = Path("mahjong.db") 197 """成績管理データベースファイル名""" 198 self.backup_dir: Optional[Path] = None 199 """バックアップ先ディレクトリ""" 200 self.font_file: Path = Path("ipaexg.ttf") 201 """グラフ描写に使用するフォントファイル""" 202 self.graph_style: str = "ggplot" 203 """グラフスタイル""" 204 self.work_dir: Path = Path("work") 205 206 # 設定値取り込み 207 super().__init__(self, section_name) 208 209 # 作業用ディレクトリ作成 210 if self.work_dir.is_dir(): 211 shutil.rmtree(self.work_dir) 212 try: 213 self.work_dir.mkdir(exist_ok=True) 214 except FileExistsError as err: 215 sys.exit(str(err)) 216 217 # フォントファイルチェック 218 for chk_dir in (outer.config_dir, outer.script_dir): 219 chk_file = chk_dir / str(self.font_file) 220 if chk_file.exists(): 221 self.font_file = chk_file 222 break 223 else: 224 if not self.font_file.exists(): 225 logging.critical("The specified font file cannot be found.") 226 sys.exit(255) 227 228 # データベース関連 229 for chk_dir in (outer.config_dir, outer.script_dir): 230 chk_file = chk_dir / str(self.database_file) 231 if chk_file.exists(): 232 self.database_file = chk_file 233 break 234 235 if isinstance(self.backup_dir, PosixPath): 236 try: 237 self.backup_dir.mkdir(exist_ok=True) 238 except FileExistsError as err: 239 sys.exit(str(err))
settingセクション初期値
SettingSection(outer: AppConfig, section_name: str)
182 def __init__(self, outer: "AppConfig", section_name: str): 183 self._parser = outer._parser 184 185 # 初期値セット 186 self.help: str = "麻雀成績ヘルプ" 187 """ヘルプ表示キーワード""" 188 self.keyword: str = "終局" 189 """成績記録キーワード""" 190 self.remarks_word: str = "麻雀成績メモ" 191 """メモ記録用キーワード""" 192 self.time_adjust: int = 12 193 """日付変更後、集計範囲に含める追加時間""" 194 self.guest_mark: str = "※" 195 """ゲスト無効時に未登録メンバーに付与する印""" 196 self.database_file: Union[Path, str] = Path("mahjong.db") 197 """成績管理データベースファイル名""" 198 self.backup_dir: Optional[Path] = None 199 """バックアップ先ディレクトリ""" 200 self.font_file: Path = Path("ipaexg.ttf") 201 """グラフ描写に使用するフォントファイル""" 202 self.graph_style: str = "ggplot" 203 """グラフスタイル""" 204 self.work_dir: Path = Path("work") 205 206 # 設定値取り込み 207 super().__init__(self, section_name) 208 209 # 作業用ディレクトリ作成 210 if self.work_dir.is_dir(): 211 shutil.rmtree(self.work_dir) 212 try: 213 self.work_dir.mkdir(exist_ok=True) 214 except FileExistsError as err: 215 sys.exit(str(err)) 216 217 # フォントファイルチェック 218 for chk_dir in (outer.config_dir, outer.script_dir): 219 chk_file = chk_dir / str(self.font_file) 220 if chk_file.exists(): 221 self.font_file = chk_file 222 break 223 else: 224 if not self.font_file.exists(): 225 logging.critical("The specified font file cannot be found.") 226 sys.exit(255) 227 228 # データベース関連 229 for chk_dir in (outer.config_dir, outer.script_dir): 230 chk_file = chk_dir / str(self.database_file) 231 if chk_file.exists(): 232 self.database_file = chk_file 233 break 234 235 if isinstance(self.backup_dir, PosixPath): 236 try: 237 self.backup_dir.mkdir(exist_ok=True) 238 except FileExistsError as err: 239 sys.exit(str(err))
Inherited Members
242class MemberSection(BaseSection): 243 "memberセクション初期値""" 244 245 def __init__(self, outer: "AppConfig", section_name: str): 246 self._parser = outer._parser 247 248 # 初期値セット 249 self.registration_limit: int = 255 250 """登録メンバー上限数""" 251 self.character_limit: int = 8 252 """名前に使用できる文字数""" 253 self.alias_limit: int = 16 254 """別名登録上限数""" 255 self.guest_name: str = "ゲスト" 256 """未登録メンバー名称""" 257 258 # 設定値取り込み 259 super().__init__(self, section_name) 260 261 # 呼び出しキーワード取り込み 262 self.commandword = [x.strip() for x in self._parser.get("member", "commandword", fallback="メンバー一覧").split(",")]
memberセクション初期値
MemberSection(outer: AppConfig, section_name: str)
245 def __init__(self, outer: "AppConfig", section_name: str): 246 self._parser = outer._parser 247 248 # 初期値セット 249 self.registration_limit: int = 255 250 """登録メンバー上限数""" 251 self.character_limit: int = 8 252 """名前に使用できる文字数""" 253 self.alias_limit: int = 16 254 """別名登録上限数""" 255 self.guest_name: str = "ゲスト" 256 """未登録メンバー名称""" 257 258 # 設定値取り込み 259 super().__init__(self, section_name) 260 261 # 呼び出しキーワード取り込み 262 self.commandword = [x.strip() for x in self._parser.get("member", "commandword", fallback="メンバー一覧").split(",")]
Inherited Members
265class TeamSection(BaseSection): 266 """teamセクション初期値""" 267 268 def __init__(self, outer: "AppConfig", section_name: str): 269 self._parser = outer._parser 270 271 # 初期値セット 272 self.registration_limit: int = 255 273 """登録チーム上限数""" 274 self.character_limit: int = 16 275 """チーム名に使用できる文字数""" 276 self.member_limit: int = 16 277 """チームに所属できるメンバー上限""" 278 self.friendly_fire: bool = True 279 """チームメイトが同卓しているゲームを集計対象に含めるか""" 280 281 # 設定値取り込み 282 super().__init__(self, section_name) 283 284 # 呼び出しキーワード取り込み 285 self.commandword = [x.strip() for x in self._parser.get("team", "commandword", fallback="チーム一覧").split(",")]
teamセクション初期値
TeamSection(outer: AppConfig, section_name: str)
268 def __init__(self, outer: "AppConfig", section_name: str): 269 self._parser = outer._parser 270 271 # 初期値セット 272 self.registration_limit: int = 255 273 """登録チーム上限数""" 274 self.character_limit: int = 16 275 """チーム名に使用できる文字数""" 276 self.member_limit: int = 16 277 """チームに所属できるメンバー上限""" 278 self.friendly_fire: bool = True 279 """チームメイトが同卓しているゲームを集計対象に含めるか""" 280 281 # 設定値取り込み 282 super().__init__(self, section_name) 283 284 # 呼び出しキーワード取り込み 285 self.commandword = [x.strip() for x in self._parser.get("team", "commandword", fallback="チーム一覧").split(",")]
Inherited Members
288class AliasSection(BaseSection): 289 """aliasセクション初期値""" 290 291 def __init__(self, outer: "AppConfig", section_name: str): 292 self._parser = outer._parser 293 294 # 初期値セット 295 self.results: list = ["成績"] 296 self.graph: list = ["グラフ"] 297 self.ranking: list = ["ランキング"] 298 self.report: list = ["レポート"] 299 self.download: list = ["ダウンロード"] 300 self.member: list = ["userlist", "member_list"] 301 self.add: list = [] 302 self.delete: list = ["del"] # "del"はbuilt-inで使用 303 self.team_create: list = [] 304 self.team_del: list = [] 305 self.team_add: list = [] 306 self.team_remove: list = [] 307 self.team_list: list = [] 308 self.team_clear: list = [] 309 310 # 設定値取り込み 311 super().__init__(self, section_name) 312 313 # デフォルト値として自身と同じ名前のコマンドを登録する # 314 for k in self.to_dict(): 315 current_list = getattr(self, k) 316 if isinstance(current_list, list): 317 current_list.append(k) 318 # delのエイリアス取り込み(設定ファイルに`delete`と書かれていない) 319 list_data = [x.strip() for x in str(self._parser.get("alias", "del", fallback="")).split(",")] 320 self.delete.extend(list_data)
aliasセクション初期値
AliasSection(outer: AppConfig, section_name: str)
291 def __init__(self, outer: "AppConfig", section_name: str): 292 self._parser = outer._parser 293 294 # 初期値セット 295 self.results: list = ["成績"] 296 self.graph: list = ["グラフ"] 297 self.ranking: list = ["ランキング"] 298 self.report: list = ["レポート"] 299 self.download: list = ["ダウンロード"] 300 self.member: list = ["userlist", "member_list"] 301 self.add: list = [] 302 self.delete: list = ["del"] # "del"はbuilt-inで使用 303 self.team_create: list = [] 304 self.team_del: list = [] 305 self.team_add: list = [] 306 self.team_remove: list = [] 307 self.team_list: list = [] 308 self.team_clear: list = [] 309 310 # 設定値取り込み 311 super().__init__(self, section_name) 312 313 # デフォルト値として自身と同じ名前のコマンドを登録する # 314 for k in self.to_dict(): 315 current_list = getattr(self, k) 316 if isinstance(current_list, list): 317 current_list.append(k) 318 # delのエイリアス取り込み(設定ファイルに`delete`と書かれていない) 319 list_data = [x.strip() for x in str(self._parser.get("alias", "del", fallback="")).split(",")] 320 self.delete.extend(list_data)
Inherited Members
323class CommentSection(BaseSection): 324 """commentセクション初期値""" 325 326 def __init__(self, outer: "AppConfig", section_name: str): 327 self._parser = outer._parser 328 329 # 初期値セット 330 self.group_length: int = 0 331 """コメント検索時の集約文字数(固定指定)""" 332 self.search_word: str = "" 333 """コメント検索時の検索文字列(固定指定)""" 334 335 # 設定値取り込み 336 super().__init__(self, section_name)
commentセクション初期値
CommentSection(outer: AppConfig, section_name: str)
Inherited Members
339class DropItems(BaseSection): 340 """非表示項目リスト""" 341 342 def __init__(self, outer: "AppConfig"): 343 self._parser = outer._parser 344 345 # 初期値セット 346 self.results: list = [] 347 self.ranking: list = [] 348 self.report: list = [] 349 350 # 設定値取り込み 351 super().__init__(self, "") 352 353 self.results = [x.strip() for x in self._parser.get("results", "dropitems", fallback="").split(",")] 354 self.ranking = [x.strip() for x in self._parser.get("ranking", "dropitems", fallback="").split(",")] 355 self.report = [x.strip() for x in self._parser.get("report", "dropitems", fallback="").split(",")]
非表示項目リスト
DropItems(outer: AppConfig)
342 def __init__(self, outer: "AppConfig"): 343 self._parser = outer._parser 344 345 # 初期値セット 346 self.results: list = [] 347 self.ranking: list = [] 348 self.report: list = [] 349 350 # 設定値取り込み 351 super().__init__(self, "") 352 353 self.results = [x.strip() for x in self._parser.get("results", "dropitems", fallback="").split(",")] 354 self.ranking = [x.strip() for x in self._parser.get("ranking", "dropitems", fallback="").split(",")] 355 self.report = [x.strip() for x in self._parser.get("report", "dropitems", fallback="").split(",")]
Inherited Members
358class BadgeDisplay(BaseSection): 359 """バッジ表示""" 360 361 @dataclass 362 class BadgeGradeSpec: 363 """段位""" 364 365 table_name: str = field(default=str()) 366 table: GradeTableDict = field(default_factory=GradeTableDict) 367 368 grade: "BadgeGradeSpec" = BadgeGradeSpec() 369 370 def __init__(self, outer: "AppConfig"): 371 self._parser = outer._parser 372 super().__init__(self, "") 373 374 self.grade.table_name = self._parser.get("grade", "table_name", fallback="")
バッジ表示
BadgeDisplay(outer: AppConfig)
Inherited Members
@dataclass
class
BadgeDisplay.BadgeGradeSpec:
361 @dataclass 362 class BadgeGradeSpec: 363 """段位""" 364 365 table_name: str = field(default=str()) 366 table: GradeTableDict = field(default_factory=GradeTableDict)
段位
BadgeDisplay.BadgeGradeSpec(table_name: str = '', table: libs.types.GradeTableDict = <factory>)
table: libs.types.GradeTableDict
377class SubCommand(BaseSection): 378 """サブコマンド共通クラス""" 379 380 def __init__(self, outer: "AppConfig", section_name: str, default: str): 381 self._parser = outer._parser 382 self.section = section_name 383 384 # 初期値セット 385 self.section: str = "" 386 self.commandword: list = [] 387 """呼び出しキーワード""" 388 self.aggregation_range: str = "当日" 389 """検索範囲未指定時に使用される範囲""" 390 self.individual: bool = True 391 """個人/チーム集計切替フラグ 392 - True: 個人集計 393 - False: チーム集計 394 """ 395 self.all_player: bool = False 396 self.daily: bool = True 397 self.fourfold: bool = True 398 self.game_results: bool = False 399 self.guest_skip: bool = True 400 self.guest_skip2: bool = True 401 self.ranked: int = 3 402 self.score_comparisons: bool = False 403 """スコア比較""" 404 self.statistics: bool = False 405 """統計情報表示""" 406 self.stipulated: int = 0 407 """規定打数指定""" 408 self.stipulated_rate: float = 0.05 409 """規定打数計算レート""" 410 self.unregistered_replace: bool = True 411 """メンバー未登録プレイヤー名をゲストに置き換えるかフラグ 412 - True: 置き換える 413 - False: 置き換えない 414 """ 415 self.anonymous: bool = False 416 """匿名化フラグ""" 417 self.verbose: bool = False 418 """詳細情報出力フラグ""" 419 self.versus_matrix: bool = False 420 """対戦マトリックス表示""" 421 self.collection: str = "" 422 self.search_word: str = "" 423 self.group_length: int = 0 424 self.always_argument: list = [] 425 """オプションとして常に付与される文字列""" 426 self.format: str = "" 427 self.filename: str = "" 428 self.interval: int = 80 429 430 # 設定値取り込み 431 super().__init__(self, section_name) 432 433 # 呼び出しキーワード取り込み 434 self.commandword = [x.strip() for x in self._parser.get(section_name, "commandword", fallback=default).split(",")] 435 436 def stipulated_calculation(self, game_count: int) -> int: 437 """規定打数をゲーム数から計算 438 439 Args: 440 game_count (int): 指定ゲーム数 441 442 Returns: 443 int: 規定ゲーム数 444 """ 445 446 return int(ceil(game_count * self.stipulated_rate) + 1)
サブコマンド共通クラス
SubCommand(outer: AppConfig, section_name: str, default: str)
380 def __init__(self, outer: "AppConfig", section_name: str, default: str): 381 self._parser = outer._parser 382 self.section = section_name 383 384 # 初期値セット 385 self.section: str = "" 386 self.commandword: list = [] 387 """呼び出しキーワード""" 388 self.aggregation_range: str = "当日" 389 """検索範囲未指定時に使用される範囲""" 390 self.individual: bool = True 391 """個人/チーム集計切替フラグ 392 - True: 個人集計 393 - False: チーム集計 394 """ 395 self.all_player: bool = False 396 self.daily: bool = True 397 self.fourfold: bool = True 398 self.game_results: bool = False 399 self.guest_skip: bool = True 400 self.guest_skip2: bool = True 401 self.ranked: int = 3 402 self.score_comparisons: bool = False 403 """スコア比較""" 404 self.statistics: bool = False 405 """統計情報表示""" 406 self.stipulated: int = 0 407 """規定打数指定""" 408 self.stipulated_rate: float = 0.05 409 """規定打数計算レート""" 410 self.unregistered_replace: bool = True 411 """メンバー未登録プレイヤー名をゲストに置き換えるかフラグ 412 - True: 置き換える 413 - False: 置き換えない 414 """ 415 self.anonymous: bool = False 416 """匿名化フラグ""" 417 self.verbose: bool = False 418 """詳細情報出力フラグ""" 419 self.versus_matrix: bool = False 420 """対戦マトリックス表示""" 421 self.collection: str = "" 422 self.search_word: str = "" 423 self.group_length: int = 0 424 self.always_argument: list = [] 425 """オプションとして常に付与される文字列""" 426 self.format: str = "" 427 self.filename: str = "" 428 self.interval: int = 80 429 430 # 設定値取り込み 431 super().__init__(self, section_name) 432 433 # 呼び出しキーワード取り込み 434 self.commandword = [x.strip() for x in self._parser.get(section_name, "commandword", fallback=default).split(",")]
def
stipulated_calculation(self, game_count: int) -> int:
436 def stipulated_calculation(self, game_count: int) -> int: 437 """規定打数をゲーム数から計算 438 439 Args: 440 game_count (int): 指定ゲーム数 441 442 Returns: 443 int: 規定ゲーム数 444 """ 445 446 return int(ceil(game_count * self.stipulated_rate) + 1)
規定打数をゲーム数から計算
Arguments:
- game_count (int): 指定ゲーム数
Returns:
int: 規定ゲーム数
Inherited Members
class
AppConfig:
449class AppConfig: 450 """コンフィグ解析クラス""" 451 452 def __init__(self, config_file: str): 453 _config = Path(config_file) 454 try: 455 self._parser = ConfigParser() 456 self._parser.read(_config, encoding="utf-8") 457 except Exception as err: 458 raise RuntimeError(err) from err 459 460 # 必須セクションチェック 461 for x in ("mahjong", "setting"): 462 if x not in self._parser.sections(): 463 logging.critical("Required section not found. (%s)", x) 464 sys.exit(255) 465 466 # オプションセクションチェック 467 option_sections = [ 468 "results", 469 "graph", 470 "ranking", 471 "report", 472 "alias", 473 "member", 474 "team", 475 "comment", 476 "regulations", 477 ] 478 for x in option_sections: 479 if x not in self._parser.sections(): 480 self._parser.add_section(x) 481 482 # set base directory 483 self.script_dir = Path(sys.argv[0]).absolute().parent 484 """スクリプトが保存されているディレクトリパス""" 485 self.config_dir = _config.absolute().parent 486 """設定ファイルが保存されているディレクトリパス""" 487 488 # 設定値取り込み 489 self.setting = SettingSection(self, "setting") 490 """settingセクション設定値""" 491 self.mahjong = MahjongSection(self, "mahjong") 492 """mahjongセクション設定値""" 493 self.member = MemberSection(self, "member") 494 """memberセクション設定値""" 495 self.team = TeamSection(self, "team") 496 """teamセクション設定値""" 497 self.alias = AliasSection(self, "alias") 498 """aliasセクション設定値""" 499 self.comment = CommentSection(self, "comment") 500 """commentセクション設定値""" 501 self.dropitems = DropItems(self) # 非表示項目 502 """非表示項目""" 503 self.badge = BadgeDisplay(self) # バッジ表示 504 """バッジ設定""" 505 506 # サブコマンド 507 self.results = SubCommand(self, "results", "麻雀成績") 508 """resultsセクション設定値""" 509 self.graph = SubCommand(self, "graph", "麻雀グラフ") 510 """graphセクション設定値""" 511 self.ranking = SubCommand(self, "ranking", "麻雀ランキング") 512 """rankingセクション設定値""" 513 self.report = SubCommand(self, "report", "麻雀成績レポート") 514 """reportセクション設定値""" 515 516 # 共通設定値 517 self.undefined_word: int = 0 518 """レギュレーションワードテーブルに登録されていないワードの種別""" 519 self.aggregate_unit: Literal["A", "M", "Y", None] = None 520 """レポート生成用日付範囲デフォルト値(レポート生成用) 521 - *A*: 全期間 522 - *M*: 月別 523 - *Y*: 年別 524 - *None*: 未定義 525 """ 526 527 def word_list(self) -> list: 528 """設定されている値、キーワードをリスト化する 529 530 Returns: 531 list: リスト化されたキーワード 532 """ 533 534 words: list = [ 535 [self.setting.keyword], 536 [self.setting.remarks_word], 537 self.results.commandword, 538 self.graph.commandword, 539 self.ranking.commandword, 540 self.report.commandword, 541 ] 542 543 for k, v in self.alias.to_dict().items(): 544 if isinstance(v, list): 545 words.append([k]) 546 words.append(v) 547 548 words = list(set(chain.from_iterable(words))) # 重複排除/平滑化 549 words = [x for x in words if x != ""] # 空文字削除 550 551 return words
コンフィグ解析クラス
AppConfig(config_file: str)
452 def __init__(self, config_file: str): 453 _config = Path(config_file) 454 try: 455 self._parser = ConfigParser() 456 self._parser.read(_config, encoding="utf-8") 457 except Exception as err: 458 raise RuntimeError(err) from err 459 460 # 必須セクションチェック 461 for x in ("mahjong", "setting"): 462 if x not in self._parser.sections(): 463 logging.critical("Required section not found. (%s)", x) 464 sys.exit(255) 465 466 # オプションセクションチェック 467 option_sections = [ 468 "results", 469 "graph", 470 "ranking", 471 "report", 472 "alias", 473 "member", 474 "team", 475 "comment", 476 "regulations", 477 ] 478 for x in option_sections: 479 if x not in self._parser.sections(): 480 self._parser.add_section(x) 481 482 # set base directory 483 self.script_dir = Path(sys.argv[0]).absolute().parent 484 """スクリプトが保存されているディレクトリパス""" 485 self.config_dir = _config.absolute().parent 486 """設定ファイルが保存されているディレクトリパス""" 487 488 # 設定値取り込み 489 self.setting = SettingSection(self, "setting") 490 """settingセクション設定値""" 491 self.mahjong = MahjongSection(self, "mahjong") 492 """mahjongセクション設定値""" 493 self.member = MemberSection(self, "member") 494 """memberセクション設定値""" 495 self.team = TeamSection(self, "team") 496 """teamセクション設定値""" 497 self.alias = AliasSection(self, "alias") 498 """aliasセクション設定値""" 499 self.comment = CommentSection(self, "comment") 500 """commentセクション設定値""" 501 self.dropitems = DropItems(self) # 非表示項目 502 """非表示項目""" 503 self.badge = BadgeDisplay(self) # バッジ表示 504 """バッジ設定""" 505 506 # サブコマンド 507 self.results = SubCommand(self, "results", "麻雀成績") 508 """resultsセクション設定値""" 509 self.graph = SubCommand(self, "graph", "麻雀グラフ") 510 """graphセクション設定値""" 511 self.ranking = SubCommand(self, "ranking", "麻雀ランキング") 512 """rankingセクション設定値""" 513 self.report = SubCommand(self, "report", "麻雀成績レポート") 514 """reportセクション設定値""" 515 516 # 共通設定値 517 self.undefined_word: int = 0 518 """レギュレーションワードテーブルに登録されていないワードの種別""" 519 self.aggregate_unit: Literal["A", "M", "Y", None] = None 520 """レポート生成用日付範囲デフォルト値(レポート生成用) 521 - *A*: 全期間 522 - *M*: 月別 523 - *Y*: 年別 524 - *None*: 未定義 525 """
aggregate_unit: Literal['A', 'M', 'Y', None]
レポート生成用日付範囲デフォルト値(レポート生成用)
- A: 全期間
- M: 月別
- Y: 年別
- None: 未定義
def
word_list(self) -> list:
527 def word_list(self) -> list: 528 """設定されている値、キーワードをリスト化する 529 530 Returns: 531 list: リスト化されたキーワード 532 """ 533 534 words: list = [ 535 [self.setting.keyword], 536 [self.setting.remarks_word], 537 self.results.commandword, 538 self.graph.commandword, 539 self.ranking.commandword, 540 self.report.commandword, 541 ] 542 543 for k, v in self.alias.to_dict().items(): 544 if isinstance(v, list): 545 words.append([k]) 546 words.append(v) 547 548 words = list(set(chain.from_iterable(words))) # 重複排除/平滑化 549 words = [x for x in words if x != ""] # 空文字削除 550 551 return words
設定されている値、キーワードをリスト化する
Returns:
list: リスト化されたキーワード