0
0

pyinstallerコマンドに指定したスクリプトファイルの`__file__`には、パッケージ名が含まれない

Last updated at Posted at 2024-08-21

環境

  • Ubuntu 22.04
  • Python 3.12.4
  • Poetry 1.8.3
  • pyinstaller 6.10.0

やりたいこと

以下のプロジェクトで、Pythonファイルからresources/foo.txtを参照したいです。

$ tree
.
├── pyproject.toml
├── sample
│   ├── __init__.py
│   ├── __main__.py
│   ├── resources
│   │   └── foo.txt
│   └── utils.py

以下のようなコードで、resources/foo.txtが存在するかどうかの結果を出力するようにしました。

__main__.py
from pathlib import Path

from sample.utils import foo_txt_exists as foo_txt_exists_in_utils

print(f"{__file__=} in '__main__.py")


def foo_txt_exists() -> bool:
    path = Path(__file__).parent / "resources/foo.txt"
    print(f"{path=}, {path.exists()=} in '__main__.py")


def main():
    foo_txt_exists()
    foo_txt_exists_in_utils()
    

if __name__ == "__main__":
    main()
utils.py
from pathlib import Path

print(f"{__file__=} in 'utils.py")


def foo_txt_exists() -> bool:
    path = Path(__file__).parent / "resources/foo.txt"
    print(f"{path=}, {path.exists()=} in 'utils.py")
pyproject.toml
[tool.poetry]
name = "sample"
version = "0.1.0"
description = ""
authors = ["yuji38kwmt"]

[tool.poetry.dependencies]
python = "^3.12"

[tool.poetry.group.publish.dependencies]
pyinstaller = { version = "^6.10", python = "=3.12" }

[tool.poetry.scripts]
sample = "sample.__main__:main"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

pyproject.tomlsample = "sample.__main__:main"という設定により、sampleというコマンドで__main__.pymain関数を実行できるようにしました。

sampleコマンドの実行結果を以下に記載します。__main__.pyutils.pyのそれぞれで、path.exists()=Trueと出力されたので、__main__.pyutils.pyresources/foo.txtを参照することができました。

$ poetry run sample
__file__='/home/yuji/tmp/20240821/sample/sample/utils.py' in 'utils.py
__file__='/home/yuji/tmp/20240821/sample/sample/__main__.py' in '__main__.py
path=PosixPath('/home/yuji/tmp/20240821/sample/sample/resources/foo.txt'), path.exists()=True in '__main__.py
path=PosixPath('/home/yuji/tmp/20240821/sample/sample/resources/foo.txt'), path.exists()=True in 'utils.py

問題提起

Pyinstallerを使って、このツールを実行ファイルに変換しました。

$ poetry run pyinstaller sample/__main__.py --name sample --add-data "sample/resources:sample/resources"
$ tree dist/sample/
dist/sample/
├── _internal
│   ├── base_library.zip
│   ├── lib-dynload
│   │   ├── ...
│   ├── ...
│   └── sample
│       └── resources
│           └── foo.txt
└── sample

実行ファイルを実行した結果を以下に記載します。__main__.pyではpath.exists()=Falseと出力されました。utils.pyではresources/foo.txtを参照できましたが、__main__.pyでは参照できませんでした。

$ dist/sample/sample
__file__='/home/yuji/tmp/20240821/sample/dist/sample/_internal/sample/utils.pyc' in 'utils.py
__file__='/home/yuji/tmp/20240821/sample/dist/sample/_internal/__main__.py' in '__main__.py
path=PosixPath('/home/yuji/tmp/20240821/sample/dist/sample/_internal/resources/foo.txt'), path.exists()=False in '__main__.py
path=PosixPath('/home/yuji/tmp/20240821/sample/dist/sample/_internal/sample/resources/foo.txt'), path.exists()=True in 'utils.py

原因

pyinstallerコマンドに指定したスクリプトファイルsample/__main__.py__file___internal/sample/__main__.pyではなく_internal/__main__.pyで、パッケージ名sampleが含まれていませんでした。これが原因のようです。

解決方法は分かりませんでした。
ひとまず、__main__.pyではresource配下のファイルを参照しないようにします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0