make_mini_tklib プログラム仕様
make_mini_tklib.py
Technical Document for make_mini_tklib.py
概要: Pythonスクリプトのエントリポイントからインポートされるモジュールを静的解析し、 指定されたパッケージ配下の必要なPythonファイルを収集してコピーします。
詳細説明: このスクリプトは、特定のPythonエントリスクリプトが依存するモジュールを静的に解析し、 pkg_name で指定されたパッケージ(通常は tklib)に属するファイルのみを抽出します。 抽出されたファイルは、pkg_root からの相対パスを保ったまま out ディレクトリにコピーされ、 最小限のパッケージサブセットを構築します(mini-packaging 用途)。 また、依存関係のレポート(未使用ファイルのリスト、Graphviz dot形式での依存グラフ)を生成する機能も提供します。
追加機能: - --report-unused: pkg_root 配下のPythonファイルのうち、選択されなかったものを unused_files.txt に出力します。 - --dot-out FILE: 依存関係を Graphviz dot 形式で出力します(A -> B は A が B を import していることを示します)。 - --ignore-if-imports: if ブロック内のインポート文を無視し、より小さなサブセットを生成します。
デフォルト値 (要求): - pkg_name のデフォルト: "tklib" - pkg_root のデフォルト:
環境変数 tkProg_Root が設定されている場合、join(env['tkProg_Root'], 'tklib', 'python', 'tklib') が存在すればそれを使用します。
上記が存在しない場合、'd:/git/tkProg/tklib/python/tklib' が存在すればそれを使用します。
それでも見つからない場合、entry ファイルから親ディレクトリをたどり、pkg_name フォルダを探索します。
制限事項: - importlib などを用いた動的なインポートは検出できません。 - from X import name 形式で name が属性の場合、完全に追跡できないことがあります(この場合、X/__init__.py を保険として含めます)。
使用例:
デフォルトでtklibを検索 python make_mini_tklib.py --entry Ne-T_fit.py --out tklib_sub --verbose
tklib の場所を明示する場合 python make_mini_tklib.py --entry Ne-T_fit.py --pkg-root D:path o klib --out tklib_sub --verbose
パッケージ名を指定し、その場所を明示する場合 python make_mini_tklib.py --entry optimize_mup.py --pkg-name mypkg --pkg-root D:path omypkg --out mypkg_sub --verbose
まずは何がコピーされるかだけ確認 (ドライラン) python make_mini_tklib.py --entry optimize_mup.py --pkg-name tklib --pkg-root D:git kProg klibpython klib --out tklib_sub --dry-run --verbose
if ブロックでインポートするモジュールをコピーしない python make_mini_tklib.py --entry some_script.py --out output --ignore-if-imports
未使用ライブラリを報告 python make_mini_tklib.py --entry some_script.py --out output --report-unused
依存関係を可視化 python make_mini_tklib.py --entry some_script.py --out output --dot-out deps.dot
- class develop.make_mini_tklib.ImportRef(module: str | None, names: Tuple[str, ...] | None, level: int)[ソース]
ベースクラス:
object概要: Pythonのインポート文を表すデータクラスです。
詳細説明: import X または from X import Y 形式のインポート情報を格納します。
- パラメータ:
module -- インポートされるモジュールまたはパッケージの名前 (例: "os", "pkg.sub")。 from . import name のような相対インポートの場合、module は . や .. を含まず、 インポートのベースとなるモジュール名(例: submodule)になります。 import X の場合は X、from X import Y の場合は X。
names -- from X import Y, Z の Y, Z に相当する名前のタプル。import X の場合はNone。
level -- 相対インポートのレベル。0は絶対インポート、1は .、2は .. など。
- develop.make_mini_tklib.build_mini_pkg(entry: Path, pkg_root: Path, pkg_name: str, out_root: Path, dry_run: bool = False, verbose: bool = False, ignore_if_imports: bool = False) Tuple[Set[Path], Dict[Path, Set[Path]]][ソース]
概要: 最小限のパッケージサブセットを構築するためのコアロジックを実行します。
詳細説明: エントリスクリプトから開始し、Pythonファイルのインポート依存関係を再帰的に静的解析します。 解析中に見つかった pkg_root 配下のすべての依存ファイルを selected セットに追加し、 ファイル間の依存関係を edges 辞書に記録します。 最終的に、selected に含まれるファイルを out_root へコピーします。
- パラメータ:
entry -- 解析を開始するエントリスクリプトのPathオブジェクト
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
pkg_name -- ターゲットパッケージ名
out_root -- 選択されたファイルをコピーする出力ディレクトリのPathオブジェクト
dry_run -- Trueの場合、実際のファイルコピーは行いません。
verbose -- Trueの場合、スキャン中のファイルパスをログに出力します。
ignore_if_imports -- Trueの場合、ifブロック内のインポート文を無視します。
- 戻り値:
selected_files (Set[Path]): 必要なファイルのPathオブジェクトのセット
edges (Dict[Path, Set[Path]]): 選択されたファイル間の依存関係 (依存元 -> 依存先)
- develop.make_mini_tklib.copy_selected_files(pkg_root: Path, out_root: Path, selected: Set[Path], dry_run: bool = False) None[ソース]
概要: 選択されたファイルを指定された出力ディレクトリにコピーします。
詳細説明: selected セット内の各ファイルを pkg_root からの相対パスを保ったまま out_root にコピーします。 必要に応じて出力先のディレクトリ構造を作成します。 dry_run がTrueの場合、実際のファイルコピーは行わず、コピー予定のパスを出力します。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
out_root -- コピー先のルートディレクトリのPathオブジェクト
selected -- コピー対象のファイルのPathオブジェクトのセット
dry_run -- Trueの場合、ファイルコピーを実行せずログ出力のみ行います。
- 戻り値:
None
- develop.make_mini_tklib.default_pkg_root_from_env_or_fallback() Path | None[ソース]
概要: 環境変数またはデフォルトのパスからパッケージルートを決定します。
詳細説明: まず環境変数 tkProg_Root を確認し、そこから tklib/python/tklib へのパスが存在すれば返します。 次に、ハードコードされたデフォルトパス d:/git/tkProg/tklib/python/tklib が存在すれば返します。 いずれも見つからない場合はNoneを返します。
- 戻り値:
パッケージルートのPathオブジェクト、または見つからなかった場合はNone
- develop.make_mini_tklib.ensure_parent_init_files(pkg_root: Path, file_path: Path, selected: Set[Path]) None[ソース]
概要: コピー対象ファイルの親パッケージの __init__.py ファイルを選択セットに追加します。
詳細説明: file_path が pkg_root の配下にある場合、その親ディレクトリのパスを遡り、 各パッケージディレクトリに存在する __init__.py ファイルを selected セットに追加します。 これにより、パッケージ構造が正しく維持されます。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
file_path -- コピー対象として選択されたファイルのPathオブジェクト
selected -- 選択されたファイルのPathオブジェクトを格納するセット
- develop.make_mini_tklib.extract_imports(pyfile: Path, ignore_if_imports: bool = False) List[ImportRef][ソース]
概要: Pythonファイルからインポート文を抽出します。
詳細説明: 指定されたPythonファイルの内容をAST(抽象構文木)として解析し、 import および from ... import 文を ImportRef オブジェクトのリストとして抽出します。 ignore_if_imports=True の場合、if ブロック内にあるインポート文は無視されます。
- パラメータ:
pyfile -- 解析対象のPythonファイルのPathオブジェクト
ignore_if_imports -- Trueの場合、ifブロック内のインポートを無視します。
- 戻り値:
抽出されたImportRefオブジェクトのリスト
- develop.make_mini_tklib.find_pkg_root_upward(entry: Path, pkg_name: str) Path | None[ソース]
概要: エントリスクリプトの親ディレクトリから指定されたパッケージのルートを探索します。
詳細説明: entry パスから親ディレクトリを最大50階層まで遡り、 その中に pkg_name という名前のディレクトリが存在するかどうかをチェックします。 見つかった場合、そのディレクトリをパッケージのルートとして返します。
- パラメータ:
entry -- エントリスクリプトのPathオブジェクト
pkg_name -- 探索するパッケージ名
- 戻り値:
パッケージルートのPathオブジェクト、または見つからなかった場合はNone
- develop.make_mini_tklib.is_within(child: Path, parent: Path) bool[ソース]
概要: あるパスが別のパスのサブパスであるかどうかを判定します。
詳細説明: child パスが parent パスの配下にあるかどうかをチェックします。 両方のパスは正規化されて比較されます。
- パラメータ:
child -- 子パスとしてチェックするPathオブジェクト
parent -- 親パスとしてチェックするPathオブジェクト
- 戻り値:
childがparentの配下にあればTrue、そうでなければFalse
- develop.make_mini_tklib.iter_py_files_under(root: Path) List[Path][ソース]
概要: 指定されたルートディレクトリ以下のすべてのPythonファイルを列挙します。
詳細説明: root パス以下のすべての .py ファイルを再帰的に検索し、リストとして返します。
- パラメータ:
root -- 検索を開始するルートディレクトリのPathオブジェクト
- 戻り値:
検出されたPythonファイルのPathオブジェクトのリスト
- develop.make_mini_tklib.main() int[ソース]
概要: スクリプトのメインエントリポイントです。
詳細説明: コマンドライン引数を解析し、build_mini_pkg 関数を呼び出して最小パッケージを構築します。 構築後、選択されたファイルの数、および生成されたレポート(未使用ファイル、dotグラフ)のパスを出力します。 引数の検証も行い、エラーがあれば適切な終了コードで終了します。
- 戻り値:
成功時は0、エラー時は2の終了コード
- develop.make_mini_tklib.module_to_candidate_paths_under_root(pkg_root: Path, pkg_name: str, module: str) List[Path][ソース]
概要: モジュール名からパッケージルート以下の候補パスを生成します。
詳細説明: pkg_root と pkg_name を元に、module という名前のモジュールまたはパッケージに対応する 可能性のあるファイルパス(.py ファイルまたは __init__.py ファイル)を生成します。 モジュール名が pkg_name で始まる場合、その部分を削除して相対パスを構築します。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
pkg_name -- パッケージ名
module -- 解決するモジュール名 (例: "pkg.foo.bar" または "foo.bar")
- 戻り値:
候補となるファイルパスのリスト
- develop.make_mini_tklib.norm(p: Path) Path[ソース]
概要: パスを正規化し、絶対パスに解決します。
詳細説明: 与えられたパスのユーザーディレクトリを展開し、絶対パスに解決します。 これにより、パスの一貫性を保ちます。
- パラメータ:
p -- Pathオブジェクト
- 戻り値:
正規化された絶対パスのPathオブジェクト
- develop.make_mini_tklib.rel_under_root(pkg_root: Path, file_path: Path) Path[ソース]
概要: ファイルパスをパッケージルートからの相対パスとして取得します。
詳細説明: file_path が pkg_root の配下にある場合、その相対パスを返します。 両方のパスは正規化されて処理されます。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
file_path -- 相対パスを取得するファイルのPathオブジェクト
- 戻り値:
pkg_root からの相対パスのPathオブジェクト
- develop.make_mini_tklib.resolve_from_import_targets(pkg_root: Path, pkg_name: str, base_module: str, names: Tuple[str, ...]) List[Path][ソース]
概要: from X import Y, Z 形式のインポートで参照されるファイルを解決します。
詳細説明: from base_module import name1, name2 の形式でインポートされる場合に、 base_module 自体と、base_module.name1、base_module.name2 などのサブルートに 対応するファイルパスを解決します。存在しないパスはリストに含まれません。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
pkg_name -- パッケージ名
base_module -- from 文のベースとなるモジュール名 (例: "pkg.foo")
names -- インポートされる名前のタプル (例: ("bar", "baz"))
- 戻り値:
解決されたファイルパスのリスト
- develop.make_mini_tklib.resolve_import_ref_to_files(ref: ImportRef, pkg_root: Path, pkg_name: str, current_file: Path) List[Path][ソース]
概要: ImportRef オブジェクトが参照する実際のファイルパスを解決します。
詳細説明: ImportRef の種類(絶対/相対、通常のインポート/fromインポート)に基づいて、 pkg_root 配下にある可能性のあるファイルパスを特定します。 相対インポートの場合、current_file を基準にパスを解決します。
- パラメータ:
ref -- 解決するImportRefオブジェクト
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
pkg_name -- パッケージ名
current_file -- 現在解析中のPythonファイルのPathオブジェクト(相対インポートの基準点)
- 戻り値:
解決されたファイルパスのリスト
- develop.make_mini_tklib.write_dot_graph(pkg_root: Path, entry: Path, edges: Dict[Path, Set[Path]], out_path: Path) Path[ソース]
概要: モジュール間の依存関係を示すGraphviz dotファイルを書き出します。
詳細説明: edges で表現されるモジュール間の依存関係グラフをGraphviz dot形式でファイルに保存します。 ノードは可能な限り pkg_root からの相対パスでラベル付けされ、 エントリスクリプトは特別にハイライトされます。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
entry -- エントリスクリプトのPathオブジェクト(グラフ内で強調表示されます)
edges -- 依存関係の辞書 (キー: 依存元ファイルのPathオブジェクト、値: 依存先ファイルのPathオブジェクトのセット)
out_path -- 出力するdotファイルのPathオブジェクト
- 戻り値:
出力されたdotファイルのPathオブジェクト
- develop.make_mini_tklib.write_unused_report(pkg_root: Path, selected: Set[Path], out_dir: Path, filename: str = 'unused_files.txt') Path[ソース]
概要: pkg_root 配下で選択されなかったPythonファイルのリストをファイルに書き出します。
詳細説明: pkg_root 配下のすべてのPythonファイルから selected セットに含まれるファイルを除外し、 残りの未使用ファイルを out_dir 内の指定されたファイルにリストアップします。 ファイルパスは pkg_root からの相対パスとして記述されます。
- パラメータ:
pkg_root -- パッケージのルートディレクトリのPathオブジェクト
selected -- 選択されたPythonファイルのPathオブジェクトのセット
out_dir -- レポートファイルを出力するディレクトリのPathオブジェクト
filename -- 出力するレポートファイルの名前 (デフォルト: "unused_files.txt")
- 戻り値:
出力されたレポートファイルのPathオブジェクト