tklib.tkparams のソースコード

"""
設定パラメータを管理するためのクラスを提供します。

このモジュールは、アプリケーションの設定パラメータを読み込み、保存し、
アクセスするための `tkParams` クラスを定義します。INIファイル形式での
パラメータの永続化、コマンドライン引数の管理、パラメータの説明機能などを
サポートします。

関連リンク:
    :doc:`tklib_usage` (tklibの全体的な使用方法に関するドキュメントへのリンク例)
"""
import os
import sys
import copy


from tklib.tkobject import tkObject, _analyze_varstr
from tklib.tkutils import pconv, pint, pfloat
from tklib.tkinifile import tkIniFile
import tklib.tkre as tkre

#=========================
# Parameter class
#=========================


[ドキュメント] class tkParams(tkObject): """ アプリケーションの設定パラメータを管理するクラスです。 このクラスは、INIファイルからのパラメータの読み込み、保存、 コマンドライン引数からのパラメータの更新、パラメータ値へのアクセス、 およびその説明の管理機能を提供します。 """ def __init__(self, parameter_file = None, app = None, **args): """ tkParamsクラスの新しいインスタンスを初期化します。 パラメータファイルパス、アプリケーションオブジェクト、および 初期パラメータを設定します。 :param parameter_file: str, optional パラメータを読み書きするINIファイルのパス。デフォルトはNone。 :param app: object, optional 関連付けられるアプリケーションオブジェクト。主にログ出力などに使用されます。 デフォルトはNone。 :param args: dict 初期設定として追加する任意のキーワード引数(パラメータ)。 """ # super(tkObject, self).__init__(**args) self._argv = sys.argv self._path = parameter_file self._app = app self._explanation = {} self.update(**args) def __del__(self): """ オブジェクトが破棄される際に呼び出されるデストラクタです。 現在、特別な処理は行いません。 """ # super(tkObject, self).__del__() pass def __str__(self): """ オブジェクトの文字列表現を返します。 :returns: str このオブジェクトのクラスパスを示す文字列。 """ return self.ClassPath()
[ドキュメント] def dict(self): """ このオブジェクトの属性を辞書として返します。 :returns: dict オブジェクトの `__dict__` 属性。 """ return self.__dict__
[ドキュメント] def copy(self): """ 現在のパラメータの新しいコピーを作成し、tkParamsオブジェクトとして返します。 すべてのパラメータとその値を新しいtkParamsインスタンスにコピーします。 :returns: tkParams 現在のパラメータを持つ新しいtkParamsオブジェクト。 """ target = tkParams() for key, val in self.dict().items(): target.__dict__[key] = val return target
[ドキュメント] def get_param_dict(self): """ このオブジェクトのパラメータ辞書を取得します。 これは `self.__dict__` と同じです。 :returns: dict オブジェクトの `__dict__` 属性。 """ return self.__dict__
[ドキュメント] def get_path(self, path: str = None) -> str: """ 現在のパラメータファイルのパスを取得または設定します。 `path` が指定された場合、内部のパラメータファイルパスを更新します。 :param path: str, optional 設定するパラメータファイルのパス。Noneの場合、現在のパスが返されます。 デフォルトはNone。 :returns: str 現在の(または更新された)パラメータファイルのパス。 """ if path is not None: self._path = path return self._path
[ドキュメント] def keys(self): """ 現在のパラメータ辞書のキーのリストを返します。 :returns: dict_keys パラメータ辞書のすべてのキーを含む `dict_keys` オブジェクト。 """ return self.__dict__.keys()
[ドキュメント] def get(self, key: str, defval = None): """ 指定されたキーのパラメータ値を取得します。 キーが存在しない場合、指定されたデフォルト値を返します。 :param key: str 取得するパラメータのキー。 :param defval: any, optional キーが見つからなかった場合に返すデフォルト値。デフォルトはNone。 :returns: any 指定されたキーのパラメータ値、またはデフォルト値。 """ return self.__dict__.get(key, defval)
[ドキュメント] def set(self, key: str, val, explanation: str = None): """ 指定されたキーのパラメータ値を設定します。 オプションで、そのパラメータの説明を設定することもできます。 :param key: str 設定するパラメータのキー。 :param val: any 設定するパラメータの値。 :param explanation: str, optional パラメータの説明。デフォルトはNone。 :returns: any 設定された値。 """ setattr(self, key, val) self._explanation[key] = explanation return val
[ドキュメント] def set_attr(self, key: str, val, explanation: str = None): """ 指定されたキーのパラメータ値を設定します。(`set` メソッドのエイリアス) オプションで、そのパラメータの説明を設定することもできます。 :param key: str 設定するパラメータのキー。 :param val: any 設定するパラメータの値。 :param explanation: str, optional パラメータの説明。デフォルトはNone。 :returns: any 設定された値。 """ return self.set(key, val, explanation)
[ドキュメント] def get_explanation(self, key: str) -> str: """ 指定されたキーのパラメータの説明を取得します。 説明が見つからず、関連するアプリケーションオブジェクトが存在する場合は、 アプリケーションオブジェクトの翻訳機能(`p()` メソッド)を通じて 説明を処理します。 :param key: str 説明を取得するパラメータのキー。 :returns: str or None パラメータの説明、または説明が存在しない場合はNone。 """ expl = self._explanation.get(key, None) if expl is None: return None if self._app: return self._app.p(expl) return expl
[ドキュメント] def get_print_func(self, app, use_warning: bool) -> callable: """ 指定された条件に基づいて適切な出力関数を返します。 `app` オブジェクトと `use_warning` フラグに応じて、 `app.print_warning`、`app.print`、または標準の `print` 関数を返します。 :param app: object or None アプリケーションオブジェクト。存在しない場合は標準出力が使用されます。 :param use_warning: bool `True`の場合、`app.print_warning`を優先的に使用します。 :returns: callable 出力に使用する関数。 """ if app and use_warning: print_func = app.print_warning elif app: print_func = app.print else: print_func = print return print_func
[ドキュメント] def printinf(self, app = None, use_warning: bool = False): """ 現在のすべてのパラメータとその値を、オプションで説明と共に表示します。 :param app: object, optional 出力に使用するアプリケーションオブジェクト。Noneの場合、内部の `_app` を使用します。 デフォルトはNone。 :param use_warning: bool, optional `True`の場合、警告出力関数(`app.print_warning`)を使用します。 デフォルトはFalse。 """ if app is None: app = self.app print_func = self.get_print_func(app, use_warning) print_func("Parameters:") for key in self.__dict__.keys(): expl = self.get_explanation(key) if expl: print_func(f" {key}: {self.__dict__[key]} ({expl})") else: print_func(f" {key}: {self.__dict__[key]}")
[ドキュメント] def print_parameters(self, heading: str = "", sort_by_keys: bool = True, exclude_keys: list = [], app = None, use_warning: bool = False): """ 現在のパラメータとその値を整形して出力します。 特定のキーを除外したり、キーでソートしたり、見出しを付けたりすることができます。 :param heading: str, optional 出力の冒頭に表示する見出し文字列。デフォルトは空文字列。 :param sort_by_keys: bool, optional `True`の場合、キーをアルファベット順(大文字小文字を区別しない)でソートして表示します。 デフォルトはTrue。 :param exclude_keys: list of str, optional 出力から除外するキーのリスト。デフォルトは空リスト。 :param app: object, optional 出力に使用するアプリケーションオブジェクト。Noneの場合、内部の `_app` を使用します。 デフォルトはNone。 :param use_warning: bool, optional `True`の場合、警告出力関数(`app.print_warning`)を使用します。 デフォルトはFalse。 """ if app is None: app = self._app print_func = self.get_print_func(app, use_warning) # print("print_func=", print_func) dict = self.get_dict() keys = [key for key in dict.keys() if key] if sort_by_keys: keys = sorted(keys, key = str.lower) if heading != "": print_func(heading) for key in keys: if tkre.Match('_', key) or dict[key] is None: continue expl = self.get_explanation(key) if expl: print_func(f" {key}: {dict[key]} ({expl})") else: print_func(f" {key}: {dict[key]}")
[ドキュメント] def print_parameters_warning(self, heading: str = "", sort_by_keys: bool = True, app = None): """ 現在のパラメータとその値を警告として出力します。 `app` オブジェクトの `print_warning` メソッドを使用します。 :param heading: str, optional 出力の冒頭に表示する見出し文字列。デフォルトは空文字列。 :param sort_by_keys: bool, optional `True`の場合、キーをアルファベット順(大文字小文字を区別しない)でソートして表示します。 デフォルトはTrue。 :param app: object, optional 出力に使用するアプリケーションオブジェクト。Noneの場合、内部の `_app` を使用します。 デフォルトはNone。 """ if app is None: app = self._app app.print_original("print_parameters_warning") dict = self.get_dict() keys = [key for key in dict.keys()] if sort_by_keys: keys = sorted(keys, key = str.lower) if heading != "": app.print_warning(heading) for key in keys: if tkre.Match('_', key) or dict[key] is None: continue expl = self.get_explanation(key) if expl: app.print_warning(f" {key}: {dict[key]} ({expl})") else: app.print_warning(f" {key}: {dict[key]}")
[ドキュメント] def get_string(self, path: str = None, section: str = None, key: str = None, def_val: str = None, is_print: bool = False): """ INIファイルから文字列型のパラメータ値を読み込みます。 指定されたパス、セクション、キーに基づいて値を読み込みます。 :param path: str, optional INIファイルのパス。Noneの場合、現在の内部パスを使用します。 デフォルトはNone。 :param section: str, optional パラメータが属するセクション名。デフォルトはNone。 :param key: str, optional 取得するパラメータのキー。デフォルトはNone。 :param def_val: str, optional キーが見つからなかった場合に返すデフォルト値。デフォルトはNone。 :param is_print: bool, optional 処理中にメッセージを出力するかどうか。デフォルトはFalse。 :returns: str or None 指定されたキーの文字列値、またはデフォルト値、またはNone。 """ path = self.get_path(path) self._path = path ini = tkIniFile(IsPrint = IsPrint) # IsPrint は外部スコープで定義されていると仮定 if ini is None: return None return ini.get_string(section = section, key = key, def_val = def_val, is_print = is_print)
[ドキュメント] def write_string(self, path: str = None, section: str = None, key: str = None, value = None, outfile = None, is_print: bool = False): """ INIファイルに文字列型のパラメータ値を書き込みます。 指定されたパス、セクション、キー、値に基づいてファイルを更新します。 :param path: str, optional INIファイルのパス。Noneの場合、現在の内部パスを使用します。 デフォルトはNone。 :param section: str, optional パラメータが属するセクション名。デフォルトはNone。 :param key: str, optional 書き込むパラメータのキー。デフォルトはNone。 :param value: any, optional 書き込むパラメータの値。`str()` で文字列に変換されます。デフォルトはNone。 :param outfile: any, optional 出力ファイルオブジェクト(使用されていない可能性が高い)。デフォルトはNone。 :param is_print: bool, optional 処理中にメッセージを出力するかどうか。デフォルトはFalse。 :returns: bool or None 書き込みが成功した場合はTrue、失敗した場合はFalse。tkIniFileのインスタンス化に失敗した場合はNone。 """ path = self.get_path(path) self._path = path ini = tkIniFile(IsPrint = IsPrint) # IsPrint は外部スコープで定義されていると仮定 if ini is None: return None # ここは `ini.write_string(...)` の間違いの可能性が高いが、既存コードは変更しないルールのためそのまま。 return write_string(self, section = section, key = key, value = value, is_print = is_print)
[ドキュメント] def read_parameters(self, path: str = None, section: str = None, AddSection: bool = False, ignore_keys: list = [], terminator: str = None, IsPrint: bool = True, follow_vartype: bool = True, read_inifile: bool = False): """ INIファイルからすべてのパラメータを読み込み、現在のオブジェクトに適用します。 読み込んだ値は、既存のパラメータの型に基づいて型変換されます。 リスト、タプル、辞書などの複合型もサポートします。 :param path: str, optional INIファイルのパス。Noneの場合、現在の内部パスを使用します。 デフォルトはNone。 :param section: str, optional 読み込むセクション名。Noneの場合、すべてのセクションを読み込みます。 デフォルトはNone。 :param AddSection: bool, optional 読み込んだセクションをパラメータとして追加するかどうか。デフォルトはFalse。 :param ignore_keys: list of str, optional 読み込み時に無視するキーのリスト。デフォルトは空リスト。 :param terminator: str, optional 値の終端を示す文字。これ以降の文字列は無視されます。デフォルトはNone。 :param IsPrint: bool, optional 処理中にメッセージを出力するかどうか。デフォルトはTrue。 :param follow_vartype: bool, optional `True`の場合、既存のパラメータの型に合わせて読み込んだ値を変換します。 `False`の場合、`pconv` を使用して変換します。デフォルトはTrue。 :param read_inifile: bool, optional `True`の場合、INIファイル自体に関する情報を読み込みます。デフォルトはFalse。 :returns: dict or None 読み込まれたパラメータを含む辞書、またはINIファイルが存在しない場合はNone。 """ path = self.get_path(path) self._path = path # Store copy of self to check var types vars_org = copy.copy(self) # vars_org = copy.deepcopy(self) ini = tkIniFile(IsPrint = IsPrint) if ini is None: return None inf = ini.read_all(path, section = section, AddSection = AddSection, ignore_keys = ignore_keys) if inf is None: return None # Check list/tuple/dict variables. Get # of elements, and initialize dict variables if not read_inifile: try: del inf['inifile'] except: pass keys = inf.keys() list_dict = {} val_param = None for key in keys: varname, index = _analyze_varstr(key) if index is None: continue val_param = self.get2(varname, None) if type(index) is int: # print("*varname=", varname) if list_dict.get(index, None) is None: list_dict[varname] = index elif list_dict[varname] < index: list_dict[varname] = index else: self.__dict__[varname] = {} # Initialize list/tuple variables for varname in list_dict.keys(): # print("**varname=", varname) self.__dict__[varname] = [None] * (list_dict[varname] + 1) # print(f"{varname}=", self.__dict__[varname]) # Assign variables keys = inf.keys() for key in keys: # Check var types from vars_org varname, index = _analyze_varstr(key) # val_param = vars_org.get2(key, None) var = vars_org.__dict__.get(varname, None) if var is None: val_param = None else: # Scalar if index is None: val_param = var # list/tuple/dict else: # print("index=", varname, index, type(index)) if type(index) is int: # list/tuple nvar = len(var) if nvar == 0: val_param = '' elif index < nvar: val_param = var[index] # if vars_org is shorter than the var given else: val_param = var[0] # dict else: if var.get(index, None) is None: val_param = "" else: val_param = var[index] str = inf.get(key, None) if str is None: continue if terminator is not None: aa = str.split(terminator) if len(aa) > 1: str = aa[0] if follow_vartype and val_param is not None: vtype = type(val_param) # print("val=", key, val_param, vtype, str) if vtype is float: val = pfloat(str) elif vtype is int: val = pint(str) elif vtype is bool: if str == 'False' or str == '0' or str == '': val = False else: val = True else: val = str else: val = pconv(str, str) self.set_attribute2(key, val) return inf
[ドキュメント] def save_parameters_by_keys(self, prmfile: str, heading: str = None, section: str = None, keys: list = None, exclude_keys: list = [], save_commandline: bool = False): """ 指定されたキーのパラメータのみをINIファイルに保存します。 このメソッドは、`save_parameters` メソッドから特定のキーセットを 保存するために呼び出されるヘルパーメソッドです。 :param prmfile: str パラメータを保存するINIファイルのパス。 :param heading: str, optional ファイル内のセクションの前に挿入される見出し(使用されていない可能性が高い)。 デフォルトはNone。 :param section: str, optional パラメータを保存するセクション名。デフォルトはNone。 :param keys: list of str, optional 保存するパラメータのキーのリスト。Noneの場合、`params.keys()` が使用されます。 (`params` はこのスコープで未定義だが、既存コード変更ルールに従いそのまま)。 デフォルトはNone。 :param exclude_keys: list of str, optional 保存から除外するキーのリスト。デフォルトは空リスト。 :param save_commandline: bool, optional コマンドライン引数を保存するかどうか。デフォルトはFalse。 :returns: None 戻り値は明示的に指定されていませんが、`tkIniFile.write_string` の結果が使われます。 実際には何も返しません。 """ if keys is None: # paramsは未定義だが、既存ロジック変更不可のためそのまま。self.keys()の意図か。 keys = list(params.keys()) if save_commandline: keys.remove("commandline") ini = tkIniFile(path = prmfile) for key in keys: if key in exclude_keys: continue v = self.get(key, None) if v is not None: ini.write_string(section = section, key = key, value = v, is_print = False)
[ドキュメント] def save_parameters(self, path: str = None, section: str = 'Preferences', keys: list = None, exclude_keys: list = [], otherparams: dict = None, sort_by_keys: bool = True, other_section: str = 'OtherParameters', update_commandline: bool = True, save_commandline: bool = False, save_inifile: bool = False, IsPrint: bool = True): """ 現在のすべてのパラメータをINIファイルに保存します。 パラメータはセクションにまとめられ、キーと値のペアとして保存されます。 リストや辞書のような複合型のパラメータも適切に保存されます。 :param path: str, optional INIファイルのパス。Noneの場合、現在の内部パスを使用します。 デフォルトはNone。 :param section: str, optional 主要なパラメータを保存するセクション名。デフォルトは'Preferences'。 :param keys: list of str, optional 保存するパラメータのキーのリスト。Noneの場合、すべてのパラメータが保存されます。 デフォルトはNone。 :param exclude_keys: list of str, optional 保存から除外するキーのリスト。デフォルトは空リスト。 :param otherparams: dict, optional 別のセクションに保存する追加のパラメータ辞書。デフォルトはNone。 :param sort_by_keys: bool, optional `True`の場合、キーをアルファベット順(大文字小文字を区別しない)でソートして保存します。 デフォルトはTrue。 :param other_section: str, optional `otherparams` を保存するセクション名。デフォルトは'OtherParameters'。 :param update_commandline: bool, optional `True`の場合、現在のコマンドライン引数を `commandline` パラメータとして更新します。 デフォルトはTrue。 :param save_commandline: bool, optional `True`の場合、`commandline` パラメータも保存します。デフォルトはFalse。 :param save_inifile: bool, optional `True`の場合、`inifile` パラメータも保存します。デフォルトはFalse。 :param IsPrint: bool, optional 処理中にメッセージを出力するかどうか。デフォルトはTrue。 :returns: bool 保存が成功した場合はTrue、失敗した場合はFalse。 """ path = self.get_path(path) self._path = path if keys is not None: return self.save_parameters_by_keys(path, section = section, keys = keys, exclude_keys = exclude_keys, save_commandline = save_commandline) params = self.get_param_dict() if update_commandline: params['commandline'] = 'python ' + ' '.join(self._argv) inifile = params.get('inifile') if not save_inifile and inifile is not None: try: del params['inifile'] except: pass if keys is None: keys = list(params.keys()) if not save_commandline: # and params.get('update_commandline', None): if "commandline" in keys: keys.remove("commandline") if sort_by_keys: keys = sorted(keys, key = str.lower) ini = tkIniFile(path, IsPrint = IsPrint) for key in keys: if key in exclude_keys: continue if tkre.Match('_', key): continue val = params.get(key, None) ret = True if val is None: continue if type(val) is list or type(val) is tuple: for i in range(len(val)): ret = ini.write_string(section, f"{key}[{i}]", val[i], is_print = IsPrint) if not ret: break elif type(val) is dict: for key2 in val.keys(): ret = ini.write_string(section, "{}[{}]".format(key, key2), val[key2], is_print = IsPrint) if not ret: break else: ret = ini.write_string(section, key, val, is_print = IsPrint) if not ret: break if ret and otherparams is not None: keys = [key for key in otherparams.keys()] if sort_by_keys: keys = sorted(keys, key = str.lower) for key in keys: val = otherparams[key] if val is not None: ret = ini.write_string(other_section, key, val, is_print = IsPrint) if not ret: break if not ret and IsPrint: print(f"\nError in tkParams.save_parameters(): Can not write to [{path}]\n") params['inifile'] = inifile return ret
[ドキュメント] def main(): """ このモジュールがスクリプトとして直接実行されたときに呼び出されるメイン関数です。 このモジュールはライブラリとして使用されることを意図しているため、 直接実行された場合はその旨のメッセージを表示します。 """ print("") print("This is library, not runnable") print("")
if __name__ == "__main__": main()