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 のデフォルト:

  1. 環境変数 tkProg_Root が設定されている場合、join(env['tkProg_Root'], 'tklib', 'python', 'tklib') が存在すればそれを使用します。

  2. 上記が存在しない場合、'd:/git/tkProg/tklib/python/tklib' が存在すればそれを使用します。

  3. それでも見つからない場合、entry ファイルから親ディレクトリをたどり、pkg_name フォルダを探索します。

制限事項: - importlib などを用いた動的なインポートは検出できません。 - from X import name 形式で name が属性の場合、完全に追跡できないことがあります(この場合、X/__init__.py を保険として含めます)。

使用例:

  1. デフォルトでtklibを検索 python make_mini_tklib.py --entry Ne-T_fit.py --out tklib_sub --verbose

  2. tklib の場所を明示する場合 python make_mini_tklib.py --entry Ne-T_fit.py --pkg-root D:path o klib --out tklib_sub --verbose

  3. パッケージ名を指定し、その場所を明示する場合 python make_mini_tklib.py --entry optimize_mup.py --pkg-name mypkg --pkg-root D:path omypkg --out mypkg_sub --verbose

  4. まずは何がコピーされるかだけ確認 (ドライラン) 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

  5. if ブロックでインポートするモジュールをコピーしない python make_mini_tklib.py --entry some_script.py --out output --ignore-if-imports

  6. 未使用ライブラリを報告 python make_mini_tklib.py --entry some_script.py --out output --report-unused

  7. 依存関係を可視化 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 の場合は Xfrom X import Y の場合は X

  • names -- from X import Y, ZY, Z に相当する名前のタプル。import X の場合はNone。

  • level -- 相対インポートのレベル。0は絶対インポート、1は .、2は .. など。

level: int
module: str | None
names: Tuple[str, ...] | None
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_pathpkg_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_rootpkg_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_pathpkg_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.name1base_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オブジェクト