nuitkaのファイルパス取得の問題と解決方法
今回もただの備忘録なので走り書きします。
nuitkaは自身のファイルパス取得方法がややこしい
問題点
原因
- 実行可能アプリケーションかどうかの判定方法がPyinstallerと違う
解決方法
from pathlib import Path # pyinstaller if getattr(sys, 'frozen', False): # nuitkaでコンパイルするとここが真にならない。 BASE_DIR = Path(sys.executable).resolve().parent else: BASE_DIR = Path(__file__).resolve() # nuitka is_nuitka = '__compiled__' in globals() # ←これが重要 if is_nuitka: BASE_DIR = Path(sys.executable).resolve().parent else: BASE_DIR = Path(__file__).resolve()
モジールにしてみる
class AppPath: _base_path_cache: Path = None # パスのキャッシュ用 @classmethod def get_base_dir(cls, parents_up: int = 0) -> Path: """ アプリケーションのベースディレクトリを計算し返す。 必要に応じて'parents_up'で指定された数だけ親ディレクトリを遡る。 デフォルト(parents_up = 0)の結果はキャッシュされる Args: Parents_up(int): 基準となるパスから親ディレクトリを遡る階層数 0 を指定すると基準となるパス自体を返す 1 を指定すると基準となるパスの直近の親を返す ex) Path('/a/b/c.py').parents[0] は '/a/b' を返す returns: Path: 計算されたベースパス """ # デフォルトの場合でキャッシュがあればそれを使用 if parents_up == 0 and cls._base_path_cache is not None: retrun cls._base_path_cache is_nuitka = '__compiled__' in globals() current_path: Path if getattr(sys, 'frozen', False) or is_nuitka: current_path = Path(sys.executable).resolve().parent else: current_path = Path(__file__).resolve().parents[parents_up] # デフォルトの場合のみキャッシュ if parents_up == 0: cls._base_path_cache = current_path return current_path
外部からの利用方法
# --- ファイル名 --- # main.py # --- フォルダ構成 --- # ./MyApp/main.py <- このpythonスクリプト # ./MyApp/Modules/AppPath.py # --- インポート --- # ファイル名の大文字小文字、クラス・関数名の大文字小文字に注意。 from Modules.AppPath import AppPath # もしPyinstallerもしくはnuitkaでビルドした場合はparents_up = 0 # Pythonスクリプトとして実行している場合はparents_up = 1 BASE_DIR = AppPath.get_base_dir(parents_up = 0) print(f"アプリケーションのベースディレクトリ: {BASE_DIR}")